【问题标题】:Why doesn't an initialized JavaScript object contain the prototype object?为什么初始化的 JavaScript 对象不包含原型对象?
【发布时间】:2015-02-28 17:24:23
【问题描述】:

我尝试使用以下代码向对象添加start 方法:

var Bounce = Bounce || {
    Info : {},
    Game : {}
};

Bounce.Game.prototype.start = function() {
    Bounce.log("Starting " + new Bounce.Info());
}

但这会导致以下错误(在Bounce.Game.prototype.start 行):

未捕获的类型错误:无法设置未定义的属性“开始”

查看 Chrome 控制台中的对象,我可以看到它不包含 prototype 对象(但有 toString、valueOf 和 constructor 等)。

这很容易通过在原型访问之前添加以下行来解决:

Bounce.Game = function() {};

我不知道为什么在对象已经初始化时需要这样做?

W3Schools 告诉我“每个 JavaScript 对象都有一个原型”,但事实并非如此。

【问题讨论】:

  • 从概念上讲,所有对象都有原型,但只有函数对象有prototype属性。她们不一样。如果您阅读 ECMAScript 规范,原型通常表示为 [[Prototype]],这是 JS 引擎中的实现细节而不是语言功能。但是,在某些引擎中,[[Prototype]] 可以通过 __proto__ 属性访问。
  • 没有。每个对象都有一个原型。但是,它没有 named prototype 的属性。两种不同的东西。是的,这令人困惑。但它们的相关性在于函数的prototype 属性成为使用该函数作为构造函数创建的新对象的实际原型。
  • 确实应该注意__proto__ 是非标准的——有更好的patterns。
  • @Leo 是对的,但是您将无法调用 Bounce.Game.start()。看看这个:jsbin.com/bapuvo/1/edit?html,js,console,output
  • 确实很有趣的问题,很高兴它重新打开了。

标签: javascript object prototype


【解决方案1】:

从概念上讲,所有对象都具有原型,但只有函数对象(包括 Object、Array 等构造函数,虽然它们不产生函数)具有名为 prototype 的属性 .它们不一样。

如果您阅读 ECMAScript 规范,原型通常表示为 [[Prototype]],这是 JS 引擎中的实现细节,而不是语言特性。但是,在某些引擎中 [[Prototype]] 是公开的,可以使用 __proto__ 属性(非标准)访问。


顺便说一句:

  1. 如果你想访问 [[Prototype]],Object.getPrototypeOf() 是你的朋友。

  2. 使用a instanceof b时,实际上是在比较a的[[Prototype]]链与b的prototype属性 .

  3. 为什么我们说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
    

【讨论】:

  • 这让我想到了一个解决方法......我会写一个答案
【解决方案2】:

因此,受@Leo cmets 的启发,我想到了使用带有原型的普通{} 对象的解决方案。

我们有这个对象:

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();

看看这个:http://jsbin.com/bapuvo/3/edit

【讨论】:

  • 有趣的方法。但是为什么不简单地Bounce.Game.start = function... 呢?
  • 为了继承和节省内存的原因,原型应该在不同的实例之间“共享”。这个解决方案是针对@Mikaveli 提出的问题,也许我永远不会使用这种方法。例如,我们不知道这段代码在哪里使用以及如何使用:如果它在完全符合 CommonJS 的环境中,我宁愿使用适当的模块设计解决方案(考虑 nodejs 或钛)。
  • @Leo 回答您的问题:是的,它是一样的。由于您不会将new 运算符与普通对象一起使用,因此使用原型变得毫无意义。
猜你喜欢
  • 2012-06-13
  • 1970-01-01
  • 2017-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多