【问题标题】:What's the difference between these 2 implementations of prototypal inheritance?这两种原型继承的实现有什么区别?
【发布时间】:2015-04-26 18:46:00
【问题描述】:

这两种原型继承实现之间有什么区别,考虑到我们正在使用 2 种不同的“原型”(仅在函数上的原型属性和内部原型),以及这些实现的不同之处原型链查找?另外,第一个实现(使用原型属性)是否依赖于我们对new 运算符的使用?

分配给函数的prototype 属性并使用new 运算符:

function foo() {}

foo.prototype.output = function(){
   console.log('inherits from Function.prototype property');
};

bar = new foo();
bar.output();

将函数存储在对象字面量中并使用Object.create() 方法:

var foo = {
  output: function(){
    console.log('inherits from the internal prototype');
  }
};

var bar = Object.create(foo);
bar.output();

【问题讨论】:

  • 一个区别是Object.create更新,IE8及以下不支持
  • 我在您的示例中没有看到原型继承
  • @hindmost 你能详细说明一下吗?
  • 我认为@hindmost 的意思是它不是继承(从上到下),而是委托。对象的功能依赖于其他对象,而不是它们的“祖先”,因为它们没有任何功能。
  • Kyll 获取了 Kyle SImpson 关于该主题的图表。我建议自己阅读整个链接章节。

标签: javascript inheritance prototype prototypal-inheritance


【解决方案1】:

主要区别在于它的使用方式以及相关的危险。

当你想创建一个新对象时,第一个强制你使用new。语法相当难看(SomeConstructor.prototype.method),它有一个主要缺陷:调用一个添加属性的构造函数(this.name = nameParam...)而不使用new 会将构造应用于全局对象。构造函数的行为很奇怪(创建委托给SomeConstructor.prototype 的新对象,然后将构造函数应用于新对象,然后如果构造函数返回某些内容,则将对象替换为某些内容)。另外,在您的示例中,foo 本身不可用,您必须创建一个新对象才能访问其功能。

第二个,Object.create,不会强迫你使用任何合乎情理的怪癖。你没有全球污染风险。对象foo 具有无需创建新对象即可使用的功能,bar 将简单地借用这些功能。这种模式还可以更容易地实现工厂(无需 news 替换所有地方)和对象池(如果需要)。

Eric Eliott talks about it very wellKyle Simpson wrote a whole book 关于原型委托!

现在,查找的过程如下:

  • 使用构造函数,查找是在Constructor.prototype(不是构造函数的实际内部原型,而是它的prototypeproperty。如果你觉得它令人困惑,恭喜你,你是人类)。附加属性在构造函数中设置。 foo 本身不用于查找,foo.prototype(同样,与指向 Function 的 foo.__proto__ 不同)是用于查找的。​​li>
  • 使用Object.create,查找是在对象本身(foo)上完成的。对象上没有 prototype 非原型属性。

very funny diagrams on this page of Kyle Simpson's book 进一步解释了这件事。

更多关于new这个问题:Is JavaScript's "new" keyword considered harmful?

【讨论】:

  • @Kyll 就“查找”而言有什么不同?这些实现使用 2 个不同的 prototype 对象,不是吗?
  • 我的意思是,委托在这两个实现中是如何发生的?它们在原型查找中的追踪方式有何不同?可以发个简单的图吗?
  • Kyle Simpson 做了一个很棒的图表,如果可以的话让我拿来。
【解决方案2】:

好的,首先,如果你不知道,Object.create 是基于 Douglas Crockford 提出的以下模式(阅读更多here):

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

现在,您必须注意,如果您将null 作为参数传递,上述代码不会产生相同的结果。
用于创建新对象的 ECMAScript 算法(阅读更多 here)指出,如果函数的原型设置为 null(或任何非对象),当您尝试使用 new f() 语法时,新创建的对象将从Object.prototype继承。
如果你使用Object.create(null),新创建的对象的[[Prototype]]内部成员将设置为null,这意味着原型链将停在那里(你的对象不会从Object.prototype获得hasOwnProperty和其他东西像普通物体一样)。

var o1 = create(null);
var o2 = Object.create(null);
Object.getPrototypeOf(o1) === Object.prototype // true
Object.getPrototypeOf(o2) === Object.prototype // false
Object.getPrototypeOf(o2) === null // true

【讨论】:

    【解决方案3】:

    第一个例子——foo,是一个函数。

    第二个例子 - foo 是一个对象。

    在第二个例子中,bar 变成了一个没有构造函数的新实例。 请参阅 - https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/create,添加构造函数。

    作为旁注,构造函数应以大写字母开头是常见的最佳实践。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-09
      • 1970-01-01
      • 1970-01-01
      • 2019-05-23
      • 2018-07-12
      • 1970-01-01
      • 2011-11-05
      • 1970-01-01
      相关资源
      最近更新 更多