那篇博文包含很多有趣的细节,但大多数时候对大多数人来说是不必要的混乱。
首先说一下函数;暂时忘记原型。创建函数时:
function Whatever() {
// ...
}
你已经创建了一个对象。也就是说,所有函数都是对象,它们是通过Function
内置构造函数构造的。此示例中的符号“Whatever”将具有对该对象的引用作为其值。
给定对函数的引用,可以调用它:
Whatever(); // call the function
可以获取该值(对函数对象的引用)并将其分配给另一个变量,或者将其作为参数传递给另一个函数,或者像 JavaScript 中的任何其他值一样使用它。
var another = Whatever;
another(); // also calls the "Whatever" function
通过Function
构造函数显式构造函数是很少做的事情,但它为您提供了一个在其他方面不起眼的函数。(在 OP 中,构造函数不做任何事情,因为没有代码传递给Function
构造函数。)
现在,当函数作为new
表达式的一部分被调用时,事情变得有趣了。
var test = new Whatever();
通过使用new
,一个新对象被实例化并与“Whatever”函数相关联。“Whatever”函数是该新对象的构造函数。
每个函数对象,无论它是否曾经用作构造函数,都有一个关联的“原型”对象。当函数用作构造函数时,它所构造的对象(即在new
调用函数的表达式中生成的对象)隐式与该原型对象相关联。
当评估对象属性引用表达式时,原型对象变得有趣。对象属性引用如下所示:
obj.name
obj[ nameExpression ]
在这样的表达式中,属性名称(表达式中使用的标识符.
或内部表达式的值[ ]
)直接与对象上的属性集进行检查。如果名称与对象的属性之一不同,则运行时会查询与用于制作对象的构造函数关联的原型对象。
对于大多数人编写的大多数代码,这种关系及其一些直接影响是唯一需要担心的事情。除非您将某种库或框架放在一起,否则您不必玩弄对象的(非标准,此时)“ proto ”属性。
最后,查看Object.create()
函数,特别是该文档中显示的“polyfill”可能会很有启发性。