如果没有实例化(new-'ing')它怎么可能:var a = Array.prototype.slice.call(arguments)?

时间:2012-02-07 02:44:10

标签: javascript arrays

在函数内部的上下文中,这里是代码(基于将函数的'参数'转换为数组的标准模式):

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

我正在尝试研究这个问题(我是JavaScript的初学者,来自C#)。

我理解slice是一个实例方法,因为它是Array的prototype函数。

我也明白这不是一个静态的“效用函数”,意味着使用它,你必须new这样:(例)var myArray = new Array(); myArray.slice(...);

call传递此处的对象,将上下文更改为arguments

的上下文

与此相关,我也不知道它们之间的区别 Array.prototype.slice.call([32,32,121,412])Array.prototype.slice([32,32,121,412])不在call的上下文中。

所以,这是我的问题:

我只是不知道这与实例与静态方法的关系如何...所以任何人都可以解释var args = Array.prototype.slice.call(arguments);的复杂性吗?

为什么可以在不调用new的情况下使用它?

为什么这可能?这不是一个静态方法,它必须是'新的',它只能在你使用call函数... 时起作用(至少在我的C#心态......) < / p>

4 个答案:

答案 0 :(得分:1)

Array.prototype.slice.call([32, 32, 121, 412])Array.prototype.slice([32, 32, 121, 412])之间的区别在于,在第一种情况下,实际Array [32, 32, 121, 412]成为&#34;此&#34;呼叫的对象。换句话说,它就像这段代码:[32, 32, 121, 412].slice()。只需在原型上调用slice就可以在原型对象的上下文中执行它,这可能不会做任何有用的事情。

答案 1 :(得分:1)

将函数添加到对象的原型时,它将成为可以在该对象的实例上使用的函数。该函数的上下文是实例。即。

Array.prototype.myFunction = function() {
     alert( this[0] ); // this should refer to the Array instance
};
var x = new Array(1);
x[0] = 5;
x.myFunction(); // alerts 5

但是,有时您可能有一个类似数组的结构,它不是Array的子​​类或实例(例如Arguments对象)。函数的调用方法的作用是将上下文更改为要调用的第一个参数。在这种情况下,调用方法是在Array的原型函数上调用的。在所有现实中,Array.prototype.myFunction只是上述代码块中定义的函数。 call是一种可以在任何函数上调用以更改其上下文的方法。因此,您将拥有一个参数对象,而不是Array实例作为上下文。

function foo() {
    Array.prototype.myFunction.call( arguments ); // arguments is [6]
    // alerts 6
}
foo( 6 );

More info on call.

答案 2 :(得分:1)

我想也许你会对像Java这样有类的语言中的“实例”和“静态”方法的行为感到困惑。 JavaScript的工作方式不同。

你也对另一个问题感到困惑,那就是所有JS函数调用在被调用函数中设置this方面的工作方式(即设置函数可能尝试操作的对象)以及效果.call()设置this

.slice()方法被定义为Array.prototype的属性,而不是单个数组实例上的Java风格“实例方法”。您可以调用Array.prototype.slice(),而无需使用new创建的数组实例。

当你说:

myArray.slice()

JS首先会看到.slice()实际上是myArray对象的方法,然后(假设它不是),它会看到它是否是Array原型的方法 - 它是,所以它运行该方法。

当您使用“dot”表示法调用任何JS函数,即myArray.slice()时,该函数中的特殊变量this将被设置为该对象。 this是对函数应该操作的对象的引用。但是如果使用.call()调用JS函数,则该函数this将被设置为您作为参数传递给.call()的对象。所以

myArray.slice()

表示要致电.slice()并让其在myArray上运作。

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

表示致电.slice()并让其在arguments

上运作

P.S。不要使用var myArray = new Array(); - 更好地说var myArray = [];

答案 3 :(得分:0)

与C#/ Java不同,函数实际上是JavaScript中的一等公民。

一般意义上说:

这意味着不需要“新”它......它的工作原理完全正确,因为它是它自己的对象。

“新”一个函数(在一般意义上)只是将该函数的“this”值更改为它将被赋值给的变量,然后返回它。

可以在JavaScript中使用一个函数,而无需“新建”它,因为它们是JavaScript中的“一等公民”。

从更深层次的意义上说,这就是“新”所做的事情:
- 它创建一个派生自MyConstructor.prototype的新对象
- 它将构造函数的'this'值赋给新对象
- 在里面执行代码(为新对象/实例添加属性)
- 返回新对象

关于我从实例中学到的内容的一些额外说明:
- 它们没有像构造函数那样的.prototype属性
- 虽然它们有一个[[prototype]]属性,派生自MyConstructor.prototype
- 覆盖实例中的属性会遮蔽MyConstructor.prototype [property] ..