这两种原型继承实现之间的区别是什么?

时间:2015-04-26 18:46:00

标签: javascript inheritance prototype prototypal-inheritance

原型继承的这两个实现之间有什么区别,并且考虑到我们正在使用2个不同的“原型”(仅在函数和内部原型上的原型属性),以及这些实现如何区别于原型链查找?另外,第一个实现(使用prototype属性)是否依赖于我们对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();

3 个答案:

答案 0 :(得分:3)

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

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

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

关于原型授权的

Eric Eliott talks about it very wellKyle Simpson wrote a whole book

现在,这里是查找的发生方式:

  • 使用构造函数,查找在Constructor.prototype上完成(不是构造函数的实际内部原型,而是prototype属性。如果您发现它令人困惑,请祝贺,你是人类)。其他属性在构造函数中设置。 foo本身不用于查找,foo.prototype(再次,与指向Function的foo.__proto__不同)是用于查找的。
  • 使用Object.create查找对象本身(foo)。对象上没有prototype非原型属性。

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

此问题中的new更多信息:Is JavaScript's "new" keyword considered harmful?

答案 1 :(得分:1)

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

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

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

Object.prototype

答案 2 :(得分:-1)

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

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

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

作为旁注,通常的最佳做法是构造函数应以大写字母开头。