' array。prototype。slice。称之为“工作吗?

我知道它被用来使arguments成为真正的Array,但我不明白使用Array.prototype.slice.call(arguments);时会发生什么。

165920 次浏览

它使用数组拥有的slice方法,并将其this作为arguments对象调用它。这意味着它像调用arguments.slice()一样调用它,假设arguments有这样一个方法。

创建一个不带任何参数的切片将简单地获取所有元素——因此它只是简单地将元素从arguments复制到一个数组。

通常,调用

var b = a.slice();

将数组a复制到b中。然而,我们做不到

var a = arguments.slice();

因为arguments没有slice作为方法(它不是一个真正的数组)。

Array.prototype.slice是数组的slice函数。.call运行这个slice函数,将this值设置为arguments

让我们假设你有:function.apply(thisArg, argArray )

apply方法调用一个函数,传入将绑定到this的对象 和可选的参数数组

slice()方法选择数组的一部分,并返回新数组。

因此,当你调用Array.prototype.slice.apply(arguments, [0])时,数组切片方法在参数上被调用(绑定)。

这是因为,作为MDN笔记

参数对象不是数组。它类似于数组,但是 除了长度以外,没有任何数组属性。例如,它确实如此 没有pop方法。但是它可以转换为一个真实的数组:

这里我们在本机对象Array上调用slice,而不是在其实现上调用,这就是为什么要调用额外的.prototype

var args = Array.prototype.slice.call(arguments);

arguments对象实际上不是Array的实例,也没有任何Array方法。因此,arguments.slice(...)将不起作用,因为arguments对象没有slice方法。

数组确实有这个方法,而且因为arguments对象非常类似于数组,所以两者是兼容的。这意味着我们可以在arguments对象中使用数组方法。由于数组方法是在考虑数组的情况下构建的,因此它们将返回数组而不是其他参数对象。

那么为什么要使用Array.prototype呢?Array是我们从(new Array())中创建新数组的对象,这些新数组被传递方法和属性,如slice。这些方法存储在[Class].prototype对象中。因此,为了提高效率,我们不通过(new Array()).slice.call()[].slice.call()访问slice方法,而是直接从原型中获取它。这样我们就不必初始化一个新数组。

但我们一开始为什么要这么做?正如你所说,它将一个arguments对象转换为一个Array实例。然而,我们使用slice的原因更多的是一种“hack”。slice方法会取一个,你猜对了,数组的切片,并返回这个切片作为一个新数组。不向它传递任何参数(除了作为上下文的arguments对象)会导致slice方法获取传递的“数组”(在本例中是arguments对象)的完整块,并将其作为一个新数组返回。

实际上,当正常调用.slice()时,this是一个数组,然后它只是迭代该数组,并完成它的工作。

.slice()函数中的this如何是数组?因为当你这样做的时候:

object.method();

...object自动成为method()this的值。所以有:

[1,2,3].slice()

...[1,2,3]数组被设置为.slice()中的this的值。


但是如果你可以用其他东西代替this值呢?只要你所替换的对象具有数值.length属性,以及一堆数值索引属性,它就可以工作。这种类型的对象通常被称为类数组对象

.call().apply()方法允许你在函数中设置this的值。因此,如果我们将.slice()中的this的值设置为类数组对象.slice()将只是假设,它与数组一起工作,并将完成它的工作。

以这个普通对象为例。

var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};

这显然不是一个数组,但如果你可以将它设置为.slice()this值,那么它就可以工作,因为它看起来足够像一个数组,让.slice()正常工作。

var sliced = Array.prototype.slice.call( my_object, 3 );

例子: http://jsfiddle.net/wSvkv/

正如你在控制台看到的,结果是我们所期望的:

['three','four'];

这就是当你将一个arguments对象设置为.slice()this值时所发生的情况。因为arguments有一个.length属性和一堆数值索引,所以.slice()就像在一个真正的数组上工作一样。

别忘了,这种行为的底层基础是完全集成在js引擎中的类型转换。

Slice只接受object(多亏了已有的参数。Length属性),并在对其执行所有操作后返回数组对象。

如果你试图用INT-value来处理String-method,你可以测试相同的逻辑:

String.prototype.bold.call(11);  // returns "<b>11</b>"

这就解释了上面的表述。

// 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]

当正常调用.slice()时,这是一个数组,然后它只是迭代该数组,并完成它的工作。

 //ARGUMENTS
function func(){
console.log(arguments);//[1, 2, 3, 4]


//var arrArguments = arguments.slice();//Uncaught TypeError: undefined is not a function
var arrArguments = [].slice.call(arguments);//cp array with explicity THIS
arrArguments.push('new');
console.log(arrArguments)
}
func(1,2,3,4)//[1, 2, 3, 4, "new"]

首先,你应该阅读函数调用在JavaScript中是如何工作的。我想这就足以回答你的问题了。但下面是正在发生的事情的总结:

Array.prototype.sliceArray原型中提取slice 方法。但是直接调用它将不起作用,因为它是一个方法(不是函数),因此需要一个上下文(调用对象,this),否则它将抛出Uncaught TypeError: Array.prototype.slice called on null or undefined

call()方法允许你指定一个方法的上下文,基本上使这两个调用等价:

someObject.slice(1, 2);
slice.call(someObject, 1, 2);

除了前者要求slice方法存在于someObject的原型链中(就像它对Array所做的那样),而后者允许将上下文(someObject)手动传递给该方法。

后者也是:

var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);

也就是:

Array.prototype.slice.call(someObject, 1, 2);
也许有点晚了,但所有这些混乱的答案是,call()在JS中用于继承。 如果我们将其与Python或PHP进行比较,例如,调用分别用作super(). __abc0()或parent::_construct().

这是它的用法的一个例子,阐明了所有:

function Teacher(first, last, age, gender, interests, subject) {
Person.call(this, first, last, age, gender, interests);


this.subject = subject;
}

参考:https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance

array. prototype.slice.call(参数)是将参数转换为数组的老式方法。

在ECMAScript 2015中,你可以使用Array.from或展开操作符:

let args = Array.from(arguments);


let args = [...arguments];
Array.prototype.slice=function(start,end){
let res=[];
start=start||0;
end=end||this.length
for(let i=start;i<end;i++){
res.push(this[i])
}
return res;
}

当你这样做时:

Array.prototype.slice.call(arguments)

arguments变成了slice中的this的值,然后slice返回一个数组

/*
arguments: get all args data include Length .
slice : clone Array
call: Convert Object which include Length to Array
Array.prototype.slice.call(arguments):
1. Convert arguments to Array
2. Clone Array arguments
*/
//normal
function abc1(a,b,c){
console.log(a);
}
//argument
function: function abc2(){
console.log(Array.prototype.slice.call(arguments,0,1))
}


abc1('a','b','c');
//a
abc2('a','b','c');
//a