Javascript Array.prototype.slice.call() 是如何工作的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7056925/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how does Array.prototype.slice.call() work?
提问by ilyo
I know it is used to make arguments a real array, but I don't understand what happens when using Array.prototype.slice.call(arguments)
我知道它用于使参数成为真正的数组,但我不明白使用时会发生什么 Array.prototype.slice.call(arguments)
回答by user113716
What happens under the hood is that when .slice()is called normally, thisis an Array, and then it just iterates over that Array, and does its work.
在幕后发生的事情是,when.slice()被正常调用,this是一个数组,然后它只是迭代那个数组,并完成它的工作。
How is thisin the .slice()function an Array? Because when you do:
如何this在.slice()功能的阵列?因为当你这样做时:
object.method();
...the objectautomatically becomes the value of thisin the method(). So with:
...该object自动成为价值this的method()。所以用:
[1,2,3].slice()
...the [1,2,3]Array is set as the value of thisin .slice().
...[1,2,3]数组被设置为thisin的值.slice()。
But what if you could substitute something else as the thisvalue? As long as whatever you substitute has a numeric .lengthproperty, and a bunch of properties that are numeric indices, it should work. This type of object is often called an array-like object.
但是如果你可以用其他东西代替this价值呢?只要你替换的任何东西都有一个数字.length属性,以及一堆数字索引的属性,它应该可以工作。这种类型的对象通常称为类数组对象。
The .call()and .apply()methods let you manuallyset the value of thisin a function. So if we set the value of thisin .slice()to an array-like object, .slice()will just assumeit's working with an Array, and will do its thing.
该.call()和.apply()方法让你手动设置的值this的函数。因此,如果我们的值设置this在.slice()一个阵列状物体,.slice()只会认为它的工作与Array,并会做它的东西。
Take this plain object as an example.
以这个普通对象为例。
var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};
This is obviously not an Array, but if you can set it as the thisvalue of .slice(), then it will just work, because it looks enough like an Array for .slice()to work properly.
这显然不是一个数组,但如果你可以将它设置为 的this值.slice(),那么它就可以正常工作,因为它看起来足够像一个数组,.slice()可以正常工作。
var sliced = Array.prototype.slice.call( my_object, 3 );
Example:http://jsfiddle.net/wSvkv/
示例:http : //jsfiddle.net/wSvkv/
As you can see in the console, the result is what we expect:
正如您在控制台中看到的,结果是我们所期望的:
['three','four'];
So this is what happens when you set an argumentsobject as the thisvalue of .slice(). Because argumentshas a .lengthproperty and a bunch of numeric indices, .slice()just goes about its work as if it were working on a real Array.
所以这就是当您将arguments对象设置为 的this值时会发生的情况.slice()。因为arguments有一个.length属性和一堆数字索引,所以.slice()它的工作就像在一个真正的数组上工作一样。
回答by Ben Fleming
The argumentsobject is not actually an instance of an Array, and does not have any of the Array methods. So, arguments.slice(...)will not work because the arguments object does not have the slice method.
该arguments对象实际上不是 Array 的实例,并且没有任何 Array 方法。因此,arguments.slice(...)将不起作用,因为参数对象没有 slice 方法。
Arrays do have this method, and because the argumentsobject is very similar to an array, the two are compatible. This means that we can use array methods with the arguments object. And since array methods were built with arrays in mind, they will return arrays rather than other argument objects.
数组确实有这个方法,而且由于arguments对象和数组非常相似,所以两者是兼容的。这意味着我们可以将数组方法与参数对象一起使用。由于数组方法是在考虑数组的情况下构建的,因此它们将返回数组而不是其他参数对象。
So why use Array.prototype? The Arrayis the object which we create new arrays from (new Array()), and these new arrays are passed methods and properties, like slice. These methods are stored in the [Class].prototypeobject. So, for efficiency sake, instead of accessing the slice method by (new Array()).slice.call()or [].slice.call(), we just get it straight from the prototype. This is so we don't have to initialise a new array.
那么为什么要使用Array.prototype?的Array是,我们创建从(新阵列的对象new Array()),而这些新的阵列被传递的方法和属性,像切片。这些方法存储在[Class].prototype对象中。因此,为了效率起见,我们不是通过(new Array()).slice.call()or访问 slice 方法[].slice.call(),而是直接从原型中获取它。这样我们就不必初始化一个新数组。
But why do we have to do this in the first place? Well, as you said, it converts an arguments object into an Array instance. The reason why we use slice, however, is more of a "hack" than anything. The slice method will take a, you guessed it, slice of an array and return that slice as a new array. Passing no arguments to it (besides the arguments object as its context) causes the slice method to take a complete chunk of the passed "array" (in this case, the arguments object) and return it as a new array.
但是为什么我们首先要这样做呢?好吧,正如您所说,它将参数对象转换为 Array 实例。然而,我们使用切片的原因更像是一种“黑客”而不是任何东西。slice 方法将接受一个你猜对了的数组切片并将该切片作为一个新数组返回。不向它传递任何参数(除了参数对象作为其上下文)会导致 slice 方法获取传递的“数组”的完整块(在本例中为参数对象)并将其作为新数组返回。
回答by Delan Azabani
Normally, calling
通常,调用
var b = a.slice();
will copy the array ainto b. However, we can't do
将数组复制a到b. 然而,我们做不到
var a = arguments.slice();
because argumentsisn't a real array, and doesn't have sliceas a method. Array.prototype.sliceis the slicefunction for arrays, and callruns the function with thisset to arguments.
因为arguments不是真正的数组,也没有slice作为方法。Array.prototype.slice是slice数组的函数,并call在this设置为 的情况下运行该函数arguments。
回答by sam
// We can apply `slice` from `Array.prototype`:
Array.prototype.slice.call([]); //-> []
// Since `slice` is available on an array's prototype chain,
'slice' in []; //-> true
[].slice === Array.prototype.slice; //-> true
// … we can just invoke it directly:
[].slice(); //-> []
// `arguments` has no `slice` method
'slice' in arguments; //-> false
// … but we can apply it the same way:
Array.prototype.slice.call(arguments); //-> […]
// In fact, though `slice` belongs to `Array.prototype`,
// it can operate on any array-like object:
Array.prototype.slice.call({0: 1, length: 1}); //-> [1]
回答by Marco Roy
First, you should read how function invocation works in JavaScript. I suspect that alone is enough to answer your question. But here's a summary of what is happening:
首先,您应该阅读JavaScript 中函数调用的工作原理。我怀疑仅此一项就足以回答您的问题。但这里是正在发生的事情的摘要:
Array.prototype.sliceextracts the slicemethodfrom Array's prototype. But calling it directly won't work, as it's a method (not a function)and therefore requires a context (a calling object, this), otherwise it would throw Uncaught TypeError: Array.prototype.slice called on null or undefined.
Array.prototype.slice从的原型中提取方法。但是直接调用它是行不通的,因为它是一个方法(不是一个函数),因此需要一个上下文(一个调用对象,),否则它会抛出.sliceArraythisUncaught TypeError: Array.prototype.slice called on null or undefined
The call()method allows you to specify a method's context, basically making these two calls equivalent:
该call()方法允许您指定方法的上下文,基本上使这两个调用等效:
someObject.slice(1, 2);
slice.call(someObject, 1, 2);
Except the former requires the slicemethod to exist in someObject's prototype chain (as it does for Array), whereas the latter allows the context (someObject) to be manually passed to the method.
除了前者要求slice方法存在于someObject的原型链中(就像它一样Array),而后者允许将上下文 ( someObject) 手动传递给方法。
Also, the latter is short for:
此外,后者是以下简称:
var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);
Which is the same as:
这与以下内容相同:
Array.prototype.slice.call(someObject, 1, 2);
回答by Alexander Moiseyev
Array.prototype.slice.call(arguments) is the old-fashioned way to convert an arguments into an array.
Array.prototype.slice.call(arguments) 是将参数转换为数组的老式方法。
In ECMAScript 2015, you can use Array.from or the spread operator:
在 ECMAScript 2015 中,您可以使用 Array.from 或扩展运算符:
let args = Array.from(arguments);
let args = [...arguments];
回答by naveen
Its because, as MDN notes
这是因为,正如MDN 指出的那样
The arguments object is not an array. It is similar to an array, but does not have any array properties except length. For example, it does not have the pop method. However it can be converted to a real array:
arguments 对象不是数组。它类似于数组,但除了长度之外没有任何数组属性。例如,它没有 pop 方法。但是它可以转换为一个真正的数组:
Here we are calling sliceon the native object Arrayand not on its implementationand thats why the extra .prototype
这里我们调用slice本地对象Array而不是它的实现,这就是为什么额外的.prototype
var args = Array.prototype.slice.call(arguments);
回答by Andrey
Dont forget, that a low-level basics of this behaviour is the type-casting that integrated in JS-engine entirely.
不要忘记,这种行为的底层基础是完全集成在 JS 引擎中的类型转换。
Slice just takes object (thanks to existing arguments.length property) and returns array-object casted after doing all operations on that.
Slice 只接受对象(感谢现有的arguments.length 属性)并在对其执行所有操作后返回转换的数组对象。
The same logics you can test if you try to treat String-method with an INT-value:
如果您尝试使用 INT 值处理字符串方法,则可以测试相同的逻辑:
String.prototype.bold.call(11); // returns "<b>11</b>"
And that explains statement above.
这解释了上面的陈述。
回答by user278064
Let's assume you have: function.apply(thisArg, argArray )
让我们假设你有: function.apply(thisArg, argArray )
The apply method invokes a function, passing in the object that will be bound to this and an optional array of arguments.
apply 方法调用一个函数,传入将绑定到 this 的对象和一个可选的参数数组。
The slice() method selects a part of an array, and returns the new array.
slice() 方法选择数组的一部分,并返回新数组。
So when you call Array.prototype.slice.apply(arguments, [0])the array slice method is invoked (bind) on arguments.
因此,当您调用Array.prototype.slice.apply(arguments, [0])数组 slice 方法时,会在参数上调用(绑定)。
回答by ThiefMaster
It uses the slicemethod arrays have and calls it with its thisbeing the argumentsobject. This means it calls it as if you did arguments.slice()assuming argumentshad such a method.
它使用slice数组所拥有的方法,并以其this为arguments对象来调用它。这意味着它调用它就好像您确实arguments.slice()假设arguments有这样的方法一样。
Creating a slice without any arguments will simply take all elements - so it simply copies the elements from argumentsto an array.
创建一个没有任何参数的切片将简单地获取所有元素 - 因此它只是将元素复制arguments到数组中。

