为什么在对象本身上定义了Function属性(例如Function.name),而在Function.prototype上定义了方法?

时间:2015-09-27 00:45:09

标签: javascript function prototype

From the API属性定义为Function.name,以及Function.prototype.call()等方法。但是在代码中我仍然以相同的方式调用它们,例如:

function Foo() {console.log("inside Foo")}
console.log(Foo.name);  // Foo
Foo.call();             // inside Foo

即。我只是输入一个函数名(Foo),然后是我想要使用的方法/属性。那么为什么在API中我会在Function上看到Function.prototype和方法上定义的属性?

5 个答案:

答案 0 :(得分:1)

简短回答:

函数(通常)可以在实例之间共享,因此它们会进入prototype

属性是按实例进行的,所以请进入构造函数。

答案 1 :(得分:1)

prototype中放置方法允许您在所有实例之间共享它们,而不是为每个实例重复它们。

例如,Function.prototype.call的行为不依赖于调用哪个函数。它只需要引用函数(通过this参数接收)以便稍后调用它。

但是,像name这样的内在数据必须存储在函数对象本身中。它不能存储在prototype中,因为每个函数实例都有自己的name。好吧,它可以存储为内部[[Name]]属性,并通过prototype中定义的getter和setter访问,但数据仍然需要存储在函数中。

请注意,prototype中定义了非方法属性,例如constructor

答案 2 :(得分:1)

实际上有一些论据可以在普通/预期属性的原型中放置不可变值默认值(或者不按合同变异的对象)。

属性的重新分配将始终位于“当前此对象”对象中(即,发生赋值的对象)。因此,如果稍后分配属性 - 在构造函数中或甚至之后 - 它们将被“提升”为实际实例的属性而不是原型 1

但是,由于差异(如果有的话)是非常适度的,并且取决于情况,所以常规练习只是转储构造函数中的所有属性赋值。无论采用何种方法,都需要单独设置每个对象的属性。

在[prototype]中共享 mutable 属性会有问题,因为属性(当变异时)的行为类似于静态变量;应始终谨慎地改变共享对象。

1 关于“在何处”分配默认属性的唯一可观察差异是使用hasOwnProperty

有趣的相关内容:Should I put default values of attributes on the prototype to save space?(是的,我知道这不同意我的第一句话。)

答案 3 :(得分:1)

你在这里有一点误解。您可以在函数本身上定义属性和函数(方法)。您可以定义希望函数在原型上构造的对象的属性和函数。这不是一回事。

例如,基础.create()构造函数的Object方法定义为Object.create(),但对象实例的.hasOwnProperty()方法定义为Object.prototype.hasOwnProperty()

例如,如果您有一个从构造函数mango创建的对象Fruit(),那么:

mango.weight(); // method comes from Fruit.prototype.weight()
Fruit.isFruit(mango); // method comes from Fruit.isFruit()

特别是,this内的Fruit.isFruit()引用了函数Fruit(),而上例中this内的Fruit.prototype.weight()引用了对象{{} 1}}。

如果您习惯使用其他语言进行OO编程,则静态类和非静态类成员之间存在差异。

答案 4 :(得分:1)

可以使用对象的实例访问

HTTP request属性(例如方法prototype),而直接属性(例如Foo.prototype.call)可通过对象本身(而不是它的实例),如 static 属性。

在您的示例中,Foo.nameFoo.name之间存在很大差异,为了使用Foo.prototype.call您可以直接调用它,而为了使用Foo.name - 你需要创建一个实例,然后它才可用

Foo.prototype.call

您需要注意的另一件事是,function Foo(){} Foo.prototype.call = funciton(){console.log('I was called');} Foo.name = 'My name is'; console.log(Foo.name); //My name is var instance = new Foo(); instances.call(); //I was called name在JavaScript中的call对象类型中都有一个原生定义 - 因此当您致电Function时 - 您调用Foo.call()方法(就像调用Function.prototype.call一样,只有一个小的区别,在这种情况下不会影响)