我们真的必须更改为Object.create吗?

时间:2013-04-18 10:38:20

标签: javascript prototype prototypal-inheritance

我有一个问题

据我所知,new运算符以这种方式工作

function fakeNew(Ctor) {
  var instance = Object.create(Ctor.prototype);
  instance.constructor();
  // I skip the conditional for simplicity
  return instance;
}

这一切都是在我进行Object.create polifill时开始的,所以我可以在不使用new的情况下创建对象。

Object.create = function(proto) {
  function F() { }
  F.prototype = proto;
  return new F();
}

我开始创建很多对象并对其进行原型设计,但是很多时候需要初始化它的属性我向它们做了.init()方法

var base = {
  init: function() {
    EmitterMixin.call(this);
    return this;
  }
};

var obj = Object.create(base).init();

但是,当然,我不得不重新登记this始终从.init()返回{很多次我忘了或最糟糕,我忘了打电话给.init()。因此,为了简化对象初始化,我想创建一个全局帮助器来执行它:调用Object.create,调用初始化函数并返回它。

function create(proto) {
  var child = Object.create(proto);
  child.init();
  return child;
}

当我意识到我在做什么实际上是 new操作员做什么但是速度慢了的时候我才想碰到我的头。如果polifill适用,我甚至会使用new

所以我问自己,投掷new有什么好处?它是主浏览器上的notably quicker,由于javascript性质,我们通常需要调用一个initualizer函数,而不是new从它开始的事情。

最糟糕的是,我注意到我使用了两种不同类型的对象," abstract"和"实例",比我必须调用.init()的实例更大的区别,而对于抽象它不是必需的,因为它们只会被用作其他对象的原型。我在使用new

时已经看到了这种模式
function Foo() { }
Foo.prototype.method = function() { ... };

function Bar() { }
// "abstract" doesnt invoke initializer
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.other = function() { ... };

// "instance", the constructor is called as initializer
var obj = new Bar();

如果我们停止看new,真的有什么好处吗?我们是否确定它不是一个更高级别的工具,而不是简化我们必须要做的事情? 您对newObject.create有哪些优缺点?

1 个答案:

答案 0 :(得分:1)

我尝试了两种方法,但我个人认为使用new的传统方法没有任何问题。 Object.create的主要论点是它使原型继承更加清晰 - 您不必理解函数构造函数上prototype属性的复杂性以及它与对象的实际原型的关系。但它确实要求初始化是一个单独的步骤。

我首选的方法是将两种方法结合起来,例如:

function Animal(name) {
    this.name = name || null;
}
Animal.prototype.eat = function() {
    console.log('yum');
}

function Cat(name) {
    Animal.call(this, name);
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;

Cat.prototype.meow = function() {
    console.log('meow');
}

var garfield = new Cat('garfield');
garfield.eat();
garfield.meow();

Object.create此处的继承优于Cat.prototype = new Animal(),原因有两个:

  1. 如果您想要name参数(如果未通过则抛出异常),您可以这样做,继承(Cat.prototype = Object.create(Animal.prototype))仍然有效。
  2. 如果您忘记从Cat构造函数调用Animal构造函数,那么Animal构造函数创建的所有属性都将是未定义的,这样您就可以快速完成意识到错误。
  3. 虽然这种方法(使用构造函数和new)不那么“纯粹”原型,但它仍然是原型继承,只要你理解如何正确使用它就可以正常工作,并且需要更少的输入而不是Object.create方法。

    我在Javascript OO库simpleoo的文档中写了一些关于此的注释。 (注意:我可能很快就会为该库更改API;我正在链接它,主要是因为文档更详细地讨论了其中的一些概念。)