【问题标题】:Setting prototype on object created through Object.create在通过 Object.create 创建的对象上设置原型
【发布时间】:2012-07-27 01:45:38
【问题描述】:

给定以下代码,我在弄清楚如何设置原型链时遇到了一些麻烦。

var Model = {
    prototype: {
        init: function(){},
        log: function(){ console.log('instance method log was called') }
    },
    log: function(){ console.log('class method log was called') },
    create: function() {
        var object = Object.create(this);
        object.parent = this;
        object.prototype = object.fn = Object.create(this.prototype);
        return object;
    },
    init: function() {
        var instance = Object.create(this.prototype);
        instance.parent = this;
        instance.init.apply(instance, arguments);
        return instance;
    }
}

var User = Model.create();
User.log(); // 'class method log was called'

// create a new method after creation
Model.warn = function() { console.warn('warn was called') }

User.warn() // 'warn was called'

var user = User.init();
user.log(); // 'instance method log was called'

特别是这一行在 create 方法中让我感到困惑:

object.prototype = object.fn = Object.create(this.prototype);

我了解 create 方法如何创建一个原型指向 Model 的新对象,但倒数第二行似乎用新对象 (Model.prototype) 覆盖了该原型。但是,原来的原型似乎仍然完好无损,因为我可以在创建新对象后向模型添加方法,并且新对象仍然可以访问它。

有人能解释一下到底发生了什么吗?

编辑 - 我应该指出这段代码来自 O'reilly 的 Javascript Web Applications

【问题讨论】:

  • 有点不清楚是什么让你感到困惑,但也许你认为thisobject 指的是Model.create 中的同一件事。如果是这样,他们不是。 this 是对Model 的引用,但object 是对从Object.create(this) 创建的新对象的引用。因此,当您执行object.prototype = ...whatever 时,您并没有覆盖Model.prototype,而是通过放置具有相同属性的属性来遮蔽存在于object 原型链中的.prototype 属性直接在object上命名。
  • 我理解 'this' 是 Model 而 'object' 是一个新对象,让我感到困惑的是最初 Object.create(this) 将新对象原型设置为 'Model',但是然后几行之后 object.prototype 被重置为 Object.create(this.prototype)。这是我不明白的线。在我看来,object.prototype 现在设置为一个对象,其原型设置为 Model.prototype(init 和 log 函数),但返回的对象可以直接访问 Model 上的方法。
  • 我想我明白什么让你感到困惑了。在object 上设置的.prototype 属性与原型链本身无关。一旦你创建了一个对象,就不可能改变原型链。所以当一个值写入object.prototype 时,它完全不会干扰objectModel 之间的关系。唯一一次设置.prototype 属性对原型链有影响,就是当您更改构造函数的.prototype 属性时,只有构造函数生成的未来对象才会受到该更改的影响。
  • 谢谢。这正是让我感到困惑的地方。
  • 很高兴找到这个问题;我对书中相同的 sn-p 感到困惑。对于 JS 新手来说,使用 .prototype 属性绝对是一个陷阱。

标签: javascript prototype object-create


【解决方案1】:

好的。所以只是为了删除噪音代码,你问的是这个代码:

var Model = {
    prototype: {},
    create: function() {
        var object = Object.create(this);
        object.prototype = Object.create(this.prototype);
        return object;
    }
};

Model.create() 函数的第一行很简单,它创建了一个扩展(原型)模型的新对象。

但是你很困惑,因为下一行覆盖了对象的“原型”属性。不是对象的原型,对象原型仍然是Model,它存储在一个名为[[Prototype]]的隐藏属性中,代码修改的属性与对象的[[Prototype]]无关,它只有相同的姓名。让我们改个名字来理解它,它会是一样的:

var Model = {
    blablabla: {},
    create: function() {
        var object = Object.create(this);
        object.blablabla = Object.create(this.blablabla);
        return object;
    }
};

它扩展了 Model.blablabla,因此当您更改 object.blablabla 时,它不会影响 Model.blablabla。

var SubModel = Model.create();
SubModel.blablabla.newMethod = function() { };
console.log(Model.blablabla.newMethod); // undefined

很多时候,为字段选择正确的名称比看起来更重要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 2015-08-11
    • 1970-01-01
    相关资源
    最近更新 更多