为什么初始化的 JavaScript 对象不包含原型对象?
Why doesn't an initialized JavaScript object contain the prototype object?
我尝试使用以下代码向对象添加 start
方法:
var Bounce = Bounce || {
Info : {},
Game : {}
};
Bounce.Game.prototype.start = function() {
Bounce.log("Starting " + new Bounce.Info());
}
但这会导致以下错误(在 Bounce.Game.prototype.start
行):
Uncaught TypeError: Cannot set property 'start' of undefined
查看 Chrome 控制台中的对象,我可以看到它不包含 prototype
对象(但有 toString
、valueOf
和 constructor
等.).
通过在原型访问之前添加以下行可以轻松解决此问题:
Bounce.Game = function() {};
我不知道为什么在对象已经初始化的情况下还需要这样做?
W3Schools 告诉我 "Every JavaScript object has a prototype",但事实并非如此。
从概念上讲,所有对象都有原型,但只有函数对象(包括 Object
、Array
这样的构造函数,尽管它们不产生函数)有 属性 名为 prototype
。他们不一样。
如果你阅读 ECMAScript 规范,原型通常表示为 [[Prototype]],这是 JS 引擎的实现细节,而不是语言功能。然而,在一些引擎中 [[Prototype]] 被公开并且可以通过 __proto__
属性 (非标准)访问。
顺便说一句:
如果你想访问[[Prototype]],Object.getPrototypeOf()
是你的朋友。
使用a instanceof b
时,实际上是在比较a
的[[Prototype]]链与b
的prototype
属性.
而为什么说null
是所有的原型呢?它也不是指 prototype
而是 [[Prototype]]:
Object.getPrototypeOf(Object.getPrototypeOf({})) // null
Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf([]))) // null
Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(new String("")))) // null
// or shorter like this
({}).__proto__.__proto__ // null
([]).__proto__.__proto__.__proto__ // null
("").__proto__.__proto__.__proto__ // null
因此,受到 @Leo 评论的启发,我想到了这个解决方案,使用一个普通的 {}
对象及其原型。
我们有这个对象:
var Bounce = Bounce || {
Info : {},
Game : {}
};
我们为给定的对象定义prototype
属性
Object.defineProperty(Bounce.Game, 'prototype', {
get: function() {
return Object.getPrototypeOf(Bounce.Game);
}
});
现在,我们可以照常使用原型了:
Bounce.Game.prototype.start = function(){
console.log('start');
};
Bounce.Game.start();
我尝试使用以下代码向对象添加 start
方法:
var Bounce = Bounce || {
Info : {},
Game : {}
};
Bounce.Game.prototype.start = function() {
Bounce.log("Starting " + new Bounce.Info());
}
但这会导致以下错误(在 Bounce.Game.prototype.start
行):
Uncaught TypeError: Cannot set property 'start' of undefined
查看 Chrome 控制台中的对象,我可以看到它不包含 prototype
对象(但有 toString
、valueOf
和 constructor
等.).
通过在原型访问之前添加以下行可以轻松解决此问题:
Bounce.Game = function() {};
我不知道为什么在对象已经初始化的情况下还需要这样做?
W3Schools 告诉我 "Every JavaScript object has a prototype",但事实并非如此。
从概念上讲,所有对象都有原型,但只有函数对象(包括 Object
、Array
这样的构造函数,尽管它们不产生函数)有 属性 名为 prototype
。他们不一样。
如果你阅读 ECMAScript 规范,原型通常表示为 [[Prototype]],这是 JS 引擎的实现细节,而不是语言功能。然而,在一些引擎中 [[Prototype]] 被公开并且可以通过 __proto__
属性 (非标准)访问。
顺便说一句:
如果你想访问[[Prototype]],
Object.getPrototypeOf()
是你的朋友。使用
a instanceof b
时,实际上是在比较a
的[[Prototype]]链与b
的prototype
属性.而为什么说
null
是所有的原型呢?它也不是指prototype
而是 [[Prototype]]:Object.getPrototypeOf(Object.getPrototypeOf({})) // null Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf([]))) // null Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(new String("")))) // null // or shorter like this ({}).__proto__.__proto__ // null ([]).__proto__.__proto__.__proto__ // null ("").__proto__.__proto__.__proto__ // null
因此,受到 @Leo 评论的启发,我想到了这个解决方案,使用一个普通的 {}
对象及其原型。
我们有这个对象:
var Bounce = Bounce || {
Info : {},
Game : {}
};
我们为给定的对象定义prototype
属性
Object.defineProperty(Bounce.Game, 'prototype', {
get: function() {
return Object.getPrototypeOf(Bounce.Game);
}
});
现在,我们可以照常使用原型了:
Bounce.Game.prototype.start = function(){
console.log('start');
};
Bounce.Game.start();