我对 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
属性时,它会尝试在对象内部[[Prototype]]
对象上查找它,并成功找到它。
需要明确的[[Prototype]]
是,该属性不能直接访问。它是一个内部属性,只能通过 JS 引擎提供的其他构造间接可变。
JavaScript 中的所有普通对象都有一个内部原型槽(注意:这里的原型不是指原型属性)。ECMAScript 标准 ( http://www.ecma-international.org/ecma-262/6.0/index.html ) 指定此插槽称为 [[Prototype]]。您可以通过 __proto__ 属性访问此插槽。
__proto__ 可能无法跨浏览器可靠地使用。__proto__ 成为 ECMAScript 6 的官方属性
然而,prototype 属性是构造函数上的一个属性,它设置将成为构造对象上的 __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 = new 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
是函数(实际上是构造函数)的属性,因为它定义了此类对象的属性/方法(从该原型所属的构造函数创建的对象)。看看这个链接