为什么在新对象上未定义JavaScript prototype属性?
我对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
属性就是在函数被调用作为构造函数时,在新对象上设置inheritance的地方。
当新对象被创build时,它的内部[[Prototype]]
属性被设置为函数的.prototype
属性指向的对象。
该对象本身不会得到一个.prototype
属性。 它与对象的关系是完全内部的。
这就是为什么它能够做b.log()
。 当JS引擎发现b
对象本身没有log
属性时,它会尝试在对象internal [[Prototype]]
对象上查找它,并在其中成功find它。
要清楚, [[Prototype]]
属性不能直接访问。 这是一个内部属性,只能通过JS引擎提供的其他结构间接变化。
在通过你的代码之前,我想确定一些理解代码行为所需的原型概念。
-
[[prototype]]
是一个JavaScript对象的隐藏属性。这个隐藏的属性不过是一个到Object.prototype
的链接(如果由对象文字创build)。没有标准的方法来访问这个[[prototype]]
属性。 - JavaScript中的函数是对象,所以它们也具有
[[prototype]]
属性。这里,在函数的情况下,这个隐藏的属性是一个到Function.prototype
的链接。也没有标准的方法来访问这个[[prototype]]
属性。 - 除了这个隐藏的链接
[[prototype]]
,每当一个函数对象被创build,一个prototype
属性被创build,它与隐藏的[[prototype]]
属性是分开的。
现在来到你的代码:
var x = function func(){}
当这行执行时,一个函数对象x
用两个链接创build:
- Function.prototype(不可访问),
- x.prototype(可访问)。
x.prototype.log = function(){console.log(“1”); }
因为我们现在知道x
是一个函数对象,所以x.prototype
是可访问的,所以在这里你可以包含log方法。
var b = new x();
b
是一个对象而不是函数对象,它有隐藏的链接[[prototype]]
但是不可访问。 所以当你尝试像b.prototype
一样b.prototype
它会给出undefined
的结果。如果你想检查b
的原型,你可以看到(x.prototype).isPrototypeOf(b);
它会返回true
。 所以你可以说隐藏的链接引用了x.prototype
。
以下是关于原型的一些事实:
- 如果使用
O = new func(){}
创build对象O
而不是O [[prototype]]是Function.prototype
。 - 如果使用
O = {}
创build对象O
而不是O [[prototype]]是Object.prototype
。 - 如果用
O = Object.create(obj)
创build的对象O
比O [[prototype]]是obj
。
JavaScript中的每个对象都有一个原型(注意:这里的原型并不是指原型属性)。 ECMAScript标准( http://www.ecma-international.org/ecma-262/6.0/index.html )指定该属性被称为[[Prototype]]。 您可以通过两种方式访问该属性:非标准__proto__属性和prototype属性。
__proto__在浏览器中可能不可靠。 __proto__成为ECMAScript 6中的官方属性
您还可以访问某些types的原型属性,例如,核心JavaScripttypes(date,数组等)。 另外一个JavaScript函数(可以被看作构造函数)有一个公共的prototype属性。 但是,函数的实例没有原型属性。
在你的情况下,b.prototype是未定义的,但如果你输出在Firefox如43.0.4版本
console.log(b.__proto__);
你会看到它的[[Prototype]]属性如下:
func { log=function()}
因为prototype
是函数(实际上是构造函数)的一个属性,因为它定义了这个类的对象的属性/方法(这些是从这个原型的构造函数创build的)。 看看这个链接