为什么';初始化的JavaScript对象是否包含原型对象?

为什么';初始化的JavaScript对象是否包含原型对象?,javascript,object,prototype,Javascript,Object,Prototype,我尝试使用以下代码向对象添加start方法: var Bounce = Bounce || { Info : {}, Game : {} }; Bounce.Game.prototype.start = function() { Bounce.log("Starting " + new Bounce.Info()); } 但这会导致以下错误(在Bounce.Game.prototype.start行上): 未捕获的TypeError:无法设置未定义的属性“start”

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

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

Bounce.Game.prototype.start = function() {
    Bounce.log("Starting " + new Bounce.Info());
}
但这会导致以下错误(在
Bounce.Game.prototype.start
行上):

未捕获的TypeError:无法设置未定义的属性“start”

查看Chrome控制台中的对象,我可以看到它不包含
prototype
对象(但包含
toString
valueOf
构造函数
等)

通过在原型访问之前添加以下行,可以轻松解决此问题:

Bounce.Game = function() {};
我不知道在对象已经初始化的情况下为什么需要这样做


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

从概念上讲,所有对象都有一个原型,但只有函数对象(包括构造函数,如
object
Array
,尽管它们不生成函数)有一个名为
prototype
属性。它们不一样

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


顺便说一下:

  • 如果您想访问[[Prototype]]
    Object.getPrototypeOf()
    是您的朋友

  • 当使用b的
    a实例时,它实际上是将
    a的[[Prototype]]链与
    b的
    Prototype
    属性进行比较

  • 为什么我们说
    null
    是一切的原型?它也不是指
    原型
    ,而是指[[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
    
  • 因此,受评论的启发,我考虑使用一个普通的
    {}
    对象及其原型

    我们的目标是:

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

    检查一下:

    从概念上讲,所有对象都有一个原型,但只有函数对象有
    prototype
    属性。它们不一样。如果您阅读ECMAScript规范,原型通常表示为[[prototype]],这是JS引擎中的实现细节,而不是语言特性。但是,在某些引擎中,[[Prototype]]可以通过
    \uuuu proto\uuu
    property.No访问。每个物体都有一个原型。但是,它没有名为
    prototype
    的属性。两件不同的事情。是的,这令人困惑。但是,函数的
    prototype
    属性成为使用该函数作为构造函数创建的新对象的实际原型,这一事实与它们相关。应该注意的是
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu>是非标准的-有更好的。@Leo是对的,但是您将无法调用Bounce.Game.start()。看看这个:的确是个有趣的问题,很高兴它被重新打开。这让我想到了一个解决办法。。。我会写一个有趣的答案。但是为什么不干脆
    Bounce.Game.start=function…
    ?出于继承和内存节省的原因,原型应该在不同的实例之间“共享”。这个解决方案是针对@Mikaveli提出的问题,也许我永远不会使用这种方法。例如,我们不知道这段代码在哪里使用以及如何使用:如果它在完全符合CommonJS的环境中,我宁愿使用适当的模块设计解决方案(想想nodejs或Tianium)。@Leo回答你的问题:是的,它是一样的。由于您不打算对普通对象使用
    new
    操作符,所以使用prototype变得毫无意义。