我对 JavaScript 原型概念的概念相当陌生。
考虑以下代码:
var x = function func(){
}
x.prototype.log = function() {
console.log("1");
}
var b = new x();
据我了解,b.log()
应该返回 1 因为x
是它的原型。但是为什么属性b.prototype
未定义?
不b.prototype
应该返回对x
函数的引用吗?
我对 JavaScript 原型概念的概念相当陌生。
考虑以下代码:
var x = function func(){
}
x.prototype.log = function() {
console.log("1");
}
var b = new x();
据我了解,b.log()
应该返回 1 因为x
是它的原型。但是为什么属性b.prototype
未定义?
不b.prototype
应该返回对x
函数的引用吗?
只有构造函数有原型。既然x
是构造函数,x
就有原型。
b
不是构造函数。因此,它没有原型。
如果您想获得对构造函数的引用b
(在本例中为x
),您可以使用
b.constructor
.prototype
当函数作为构造函数被调用时,函数的属性只是为了在新对象上设置继承。
创建新对象时,它会将其内部[[Prototype]]
属性设置为函数.prototype
属性指向的对象。
对象本身没有.prototype
属性。它与对象的关系完全是内部的。
这就是它起作用的原因b.log()
。当 JS 引擎看到b
对象本身没有log
属性时,它会尝试在 objects 内部[[Prototype]]
对象上查找它,并成功找到它。
需要明确的是,该[[Prototype]]
属性不可直接访问。它是一个内部属性,只能通过 JS 引擎提供的其他构造间接可变。
JavaScript 中的所有普通对象都有一个内部原型槽(注意:这里的原型不是指原型属性)。ECMAScript 标准 ( http://www.ecma-international.org/ecma-262/6.0/index.html ) 指定此插槽称为 [[Prototype]]。您可以通过 __proto__ 属性访问此插槽。
__proto__ 可能无法跨浏览器可靠地使用。__proto__ 成为 ECMAScript 6 中的官方属性
然而,原型属性是构造函数上的一个属性,它设置构造对象上的 __proto__ 属性。
您可以访问某些类型的原型属性,例如核心 JavaScript 类型(日期、数组等)。还有一个 JavaScript 函数(可以看作是一个构造函数)有一个公共的原型属性。但是,函数的实例没有原型属性。
在你的情况下var b = new x();
,b 是函数 x 的一个实例。因此 b.prototype 是未定义的。但是,b 确实有一个内部 [[Prototype]] 插槽。如果您b.__proto__
在 Google Chrome 中输出,例如版本 63.0.3239.132,或在 Firefox 中输出,例如版本 43.0.4
console.log(b.__proto__);
您将看到它的 [[Prototype]] 插槽,如下所示:
{log: ƒ, constructor: ƒ}
而已。
仅供参考,整个代码片段如下:
var x = function() {
};
x.prototype.log = function() {
console.log("1");
}
var b = new x();
b.log(); // 1
console.log(b.prototype); // undefined
console.log(b.__proto__); // {log: ƒ, constructor: ƒ}
console.log(x.prototype); // {log: ƒ, constructor: ƒ}
在浏览您的代码之前,我想确保了解您的代码行为所需的原型概念。
[[prototype]]
是 JavaScript 对象的隐藏属性。这个隐藏属性只不过是一个链接Object.prototype
(如果由对象字面量创建)。没有标准方法可以访问此[[prototype]]
属性。[[prototype]]
属性。在这里,如果是函数,这个隐藏的属性是一个链接Function.prototype
。也没有标准的方法来访问这个[[prototype]]
属性。[[prototype]]
,每当创建一个函数对象时,都会在其中创建一个prototype
属性,该属性与隐藏属性是分开的[[prototype]]
。现在来到你的代码:
var x = 函数 func(){}
执行此行时,将x
创建一个带有两个链接的函数对象:
x.prototype.log = function() { console.log("1"); }
正如我们现在知道的那样,它x
是一个函数对象,因此x.prototype
可以访问,因此您可以在此处包含 log 方法。
var b = 新 x();
b
是一个对象,但不是函数对象。它有那个隐藏的链接[[prototype]]
,但它是不可访问的。因此,当您尝试访问时,b.prototype
它会给出undefined
结果。如果您想检查原型,b
则可以看到(x.prototype).isPrototypeOf(b);
它将返回true
。所以你可以说隐藏链接被引用x.prototype
。
以下是有关原型的一些事实:
O
是用O = new func(){}
然后 O[[prototype]] 创建的Function.prototype
。O
是用O = {}
然后 O[[prototype]] 创建的Object.prototype
。O
是用O = Object.create(obj)
然后 O[[prototype]] 创建的obj
。因为prototype
是函数(实际上是构造函数)的属性,因为它定义了此类对象(从该原型所属的构造函数创建的对象)的属性/方法。看看这个链接