javascript - 我们真的必须改成 Object.create 吗?

标签 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();
}

我开始创建很多对象并制作它们的原型(prototype),但是很多时候需要初始化它的属性我对它们做了一个 .init() 方法

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

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

但是当然,我不得不记住总是从 .init() 返回 this 并且很多时候我忘记了它或者最糟糕的是,我忘记调用 .init()。因此,为了简化对象初始化,我想创建一个全局助手来完成它:调用 Object.create,调用初始化函数并返回它。

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

当我意识到我所做的实际上是 new 运算符所做的 时,我想撞墙,但速度要慢得多。如果 polifill 适用,我什至会在后台使用 new

所以我问自己,throw new 有什么好处?这是notably quicker在主流浏览器上,由于 javascript 的特性,我们通常需要调用一个初始化函数,而不是 new 从一开始就做的事情。

最糟糕的是,我注意到我使用了两种不同类型的对象,“抽象”和“实例”,更大的区别是我必须调用 .init 的实例() 而对于抽象来说,这不是必需的,因为它们只会被用作其他对象的原型(prototype)。我已经在使用 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 有哪些优点/缺点?

最佳答案

我已经尝试了这两种方法,我个人认为使用 new 的传统方法没有任何问题。 Object.create 的主要论点是它使原型(prototype)继承更加清晰 - 您不必理解函数构造函数上的 prototype 属性的复杂性以及它是如何实现的与对象的实际原型(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.createCat.prototype = new Animal() 更适合继承,原因有二:

  1. 如果你想要求 name 参数(如果没有传递则抛出异常),你可以这样做并且继承(Cat.prototype = Object.create(Animal .prototype)) 仍然有效。
  2. 如果您忘记从 Animal 构造函数中调用 Cat 构造函数,所有本应由 Animal 构造函数创建的属性将改为未定义,让您快速意识到错误。

虽然这种方法(使用构造函数和 new)不是“纯粹”的原型(prototype),但它仍然是原型(prototype)继承,只要您了解如何正确使用它,它就可以正常工作,并且需要与 Object.create 方法相比,输入更少。

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

关于javascript - 我们真的必须改成 Object.create 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16080691/

相关文章:

Java 原型(prototype)克隆没有按预期工作?

javascript - 如何在 JavaScript 中重写私有(private)方法?

javascript - 如何使用 javascript(原型(prototype))继承正确派生具有私有(private)变量的对象

javascript - 当我查看 DOM 对象的 getter 属性时,控制台中发生了什么?

javascript - 再次将 Canvas 像素设置为透明

javascript - 如何使用 React 在提交时使用 props 重定向到新组件

javascript - 使用特定的 JavaScript 版本 (< 1.8.5)

javascript - 在通过 Object.create 创建的对象上设置原型(prototype)

javascript - 如何在javascript中检查instanceof而不使用proto链?

javascript - 没有 jQuery 的 .prependTo() 和 .insertAfter()