【问题标题】:Replicating constructors and new with Object.create()使用 Object.create() 复制构造函数和 new
【发布时间】:2013-08-28 07:19:09
【问题描述】:

根据我对 OOP javascript 的有限经验,处理具有不同属性但相同方法的多个对象的常用方法是使用如下构造函数:

function Animal ( type ) {
    this.type = type
};
Animal.prototype.sayHello = function () {
    return 'Hi, I am a ' + this.type
};
var goat = new Animal( 'Goat' );

我这里的理解是goat会继承/引用Animal的功能。

假设我可以使用以下对象字面量概念复制上述内容:

var Animal = {
    type : '',
    sayHello : function () {
        return 'Hi, I am a ' + this.type
    }
}
var goat = Object.create( Animal );
goat.type = 'Goat';

Animal 的继承在这里丢失了,还是Goat 仍然引用Animal 的方法?

我想知道使用Object.create() 而不是new 复制构造函数/类是否有任何问题。是否有性能偏移或任何理由继续使用new

任何建议都将不胜感激,如果需要澄清,我很乐意补充问题。

更新对象创建

var Animal = {
    sayHello : function () {
        return 'Hi, I am a ' + this.type
    }
}
var goat = Object.create( Animal, { 'type' : { value: 'goat' } } );

【问题讨论】:

  • 您真的想在所有呼叫站点输入goat.type(以及更多)?另外,如果你想改变它,重构会更难。这太可怕了。在有人说“创建工厂”之前,在这种情况下,您只是在做美化的构造函数+原型。
  • @Esailija 我添加了关于如何填充type 的更新。我很想知道你会如何处理这个问题。
  • 这比我刚才批评的还要糟糕 :D 它仍然在调用站点,在对象外部,甚至更冗长
  • @Esailija 你能解释一下为什么,不仅仅是为了我自己的理解,而是为了其他用户?我需要创建多个对象。它们之间的唯一区别是type。在下面的答案中,function CreateAnimal(type) 和你坐得更好吗?我将不胜感激任何进一步的cmets。谢谢
  • 那么 var a = new Animal(type)var a = CreateAnimal(type) 有什么区别?两者都一样方便,并将属性分配放在它们所属的地方。然而,代码在声明站点上仍然有点难看,您必须显式创建并返回一个对象 - 当使用普通构造函数时,创建和返回语句是隐式的 -> 这就是为什么你只在普通构造函数中键入 this.type = xxx 但需要返回工厂内部的语句和 object.create。

标签: javascript oop


【解决方案1】:

...处理具有不同属性但相同方法的多个对象的常用方法是使用构造函数...

是的,另一种常见的方式是(如您所见)Object.create

我这里的理解是goat会继承/引用Animal的功能。

不完全是。在new Animal 表达式中,goat 被分配Animal.prototype 引用的对象作为其底层原型。与Animal 没有直接 连接,仅与Animal.prototype 连接。 (在正常情况下,Animal.prototype 通过其constructor 属性引用回Animal,尽管如果有人将新对象分配给Animal.prototype,则该链接可能会断开。)

Animal 的继承在这里丢失了,还是Goat 仍然引用Animal 的方法?

在您的非构造函数示例中,goatAnimal 作为其底层原型,因此对于在 goat 本身上找不到的任何属性,JavaScript 引擎将查看 Animal 以查看是否 有。在您的示例中,这意味着goat 使用的是来自AnimalsayHello,但不是type,因为goat 有自己的type

大致相当于:

function Animal ( type ) {
    this.type = type
};
Animal.prototype.sayHello = function () {
    return 'Hi, I am a ' + this.type
};
var goat = new Animal( 'Goat' );

...使用Object.create 设置原型改为如下所示:

var animalPrototype = {
    sayHello: function () {
        return 'Hi, I am a ' + this.type
    }
};
function createAnimal(type) {
    var rv = Object.create(animalPrototype);
    rv.type = type;
    return rv;
};
var goat = createAnimal( 'Goat' );

你的评论:

会不会有任何问题,包括animalPrototypecreateAnimal 中,然后调用Object.create(this.animalPrototype)

如果你是这个意思:

function createAnimal(type) {
    var animalPrototype = {                       // Issue #1
        sayHello: function () {
            return 'Hi, I am a ' + this.type
        }
    };
    var rv = Object.create(this.animalPrototype); // Issue #2
    rv.type = type;
    return rv;
};
var goat = createAnimal( 'Goat' );

...那么是的,有两个问题:

  1. 您将为每次调用 createAnimal 创建一个 animalPrototype,这违背了目的,并且 2. this 在对 createAnimal 的调用中要么是全局的对象(松散模式)或undefined(严格模式),所以this.animalPrototype 可能不是您想要的表达式。

你可以这样做:

function createAnimal(type) {
    var rv = Object.create(createAnimal.proto);
    rv.type = type;
    return rv;
};
createAnimal.proto = {
    sayHello: function () {
        return 'Hi, I am a ' + this.type
    }
};
var goat = createAnimal( 'Goat' );

当然,这可能会让人们感到困惑,因为它看起来很像构造函数。

【讨论】:

  • +1 对正在发生的事情的非常好的和客观的总结。 OP - 总之 Yes ,使用 Object.create 可以让您在 JavaScript 中进行原型继承。它创建一个新对象,其 prototype 是您指定的对象。 (顺便说一句,我在“大多数情况下更喜欢 Object.create”)
  • @BenjaminGruenbaum:谢谢!我持相当平衡的观点。如果我要创建一些感觉“优雅”的东西,我会使用构造函数(通过我的Lineage script)。但是我一直使用Object.create,我只需要一个与另一个特定对象大致相同但略有不同的对象。我有一个项目我们经常这样做,虽然它可以使用构造函数来完成,但它会非常笨重。我发现它们都是非常有用的工具。我喜欢 JavaScript 的灵活性。
  • @T.J.Crowder 非常感谢您的回答,它解决了我的一些问题。我更新了我的问题删除首选项,因此您可能需要更新答案的开头。再次感谢您!
  • @T.J.Crowder 再次感谢您。会有任何问题,包括animalPrototypecreateAnimal 中,然后调用Object.create(this.animalPrototype)?只是为了组织?也许是个愚蠢的想法。
  • @mikedidthis:请参阅答案末尾的进一步更新。
猜你喜欢
  • 2013-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-14
  • 2016-09-12
  • 1970-01-01
相关资源
最近更新 更多