Object Prototype Extending

所有拓展原型链方法的总结

来源: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Summary_of_methods_for_extending_the_prototype_chain

New 构造函数法

function foo(){}
foo.prototype = {
  foo_prop: "foo val"
};
function bar(){}
var proto = new foo;
proto.bar_prop = "bar val";
bar.prototype = proto;
var inst = new bar;
console.log(inst.foo_prop);
console.log(inst.bar_prop);

优点

  • 兼容性优秀(IE5.5+)
  • 速度非常快,基本是最快的实现。
  • 可以被众多引擎无损优化。

缺点

  • 要使用这种方法,这个函数必须被初始化。在初始化过程中(也就是上述代码中proto的建立过程中),构造函数应该在每次被使用时创造独立的值。然而,这种值只会被构造一次,很有可能引起不必要的麻烦。
  • 在构造函数的初始化中,很多不需要的方法也可能被放到对象中。但是,只要足够小心去维护,这些都是JavaScript合理的行为,只要你充分理解原型链的概念和它们的原理,这些问题也可能变成特性从而可以加以利用。

Object.create

function foo(){}
foo.prototype = {
  foo_prop: "foo val"
};
function bar(){}
var proto = Object.create(
  foo.prototype
);
proto.bar_prop = "bar val";
bar.prototype = proto;
var inst = new bar;
console.log(inst.foo_prop);
console.log(inst.bar_prop);

优点

  • 被所有的现代浏览器所支持(IE9+)
  • 允许通过Object.create直接设定__proto__的值,而且这种设定会被引擎充分优化,因为它只被设置了一次。
  • 允许创建一个没有原型的对象,通过Object.create(null)

缺点

  • 不支持IE8-。
  • 如果使用Object.create的第二个参数,这种构造有可能很慢,因为每个独立的对象(这里应该指的是字面量)都会创造对应的描述符对象(也就是哈希表)。如果被创造了过多的这种描述符,就会因为频繁GC而导致性能问题。

Object.setPrototypeOf

function foo(){}
foo.prototype = {
  foo_prop: "foo val"
};
function bar(){}
var proto = {
  bar_prop: "bar val"
};
Object.setPrototypeOf(
  proto, foo.prototype
);
bar.prototype = proto;
var inst = new bar;
console.log(inst.foo_prop);
console.log(inst.bar_prop);

优点

  • 兼容性良好(IE9+)
  • 允许动态改变一个对象的原型链,甚至让一个被Object.create(null)创建的无原型对象拥有原型。

缺点

  • 应该被弃用,而且性能很差。大多数的引擎都是通过推测对象的原型链从而进行针对性的优化。动态设置原型链会让这些优化完全失效,甚至使得引擎重新编译部分代码从而保证结果一致。
  • 不被IE8-支持。

直接设置__proto__

function foo(){}
foo.prototype = {
  foo_prop: "foo val"
};
function bar(){}
var proto = {
  bar_prop: "bar val",
  __proto__: foo.prototype
};
bar.prototype = proto;
var inst = new bar;
console.log(inst.foo_prop);
console.log(inst.bar_prop);

优点

  • 被IE11+和现代浏览器所支持。
  • 如果__proto__不是一个对象,这种方法不会引发异常。

缺点

  • Object.setPrototypeOf一样,性能比较糟糕而且应该弃用。动态改变原型链在什么时候都是开销较大的操作。
  • 不支持IE10-。