拓展原型链的方法

一、扩展原型链的方法:New-initialization、Object.create、Object.setPrototypeOf、proto

New-initialization

一、示例

  1. function foo(){}
  2. foo.prototype = {
  3. foo_prop: "foo val"
  4. };
  5. function bar(){}
  6. // 关键代码 start======
  7. var proto = new foo;
  8. // 关键代码 end======
  9. proto.bar_prop = "bar val";
  10. bar.prototype = proto;
  11. var inst = new bar;
  12. console.log(inst.foo_prop); // foo val
  13. console.log(inst.bar_prop); // bar val

二、优势
1、支持目前以及所有可想象到的浏览器(IE5.5都可以使用)。
2、这种方法非常快,非常符合标准,并且充分利用JIT优化。
三、缺陷
1、为使用此方法,必须对相关函数初始化。
(1)在初始化过程中,构造函数可以存储每个对象必须生成的唯一信息。
(2)但是,这种唯一信息只生成一次,可能会带来潜在的问题。
2、此外,构造函数的初始化,可能会将不需要的方法放在对象上。
(1)然而,如果你只在自己的代码中使用,你也清楚(或有通过注释等写明)各段代码在做什么,这些在大体上都不是问题(事实上,通常是有益处的)。

Object.create

一、示例
【示例1】

  1. function foo(){}
  2. foo.prototype = {
  3. foo_prop: "foo val"
  4. };
  5. function bar(){}
  6. // 关键代码 start======
  7. var proto = Object.create(
  8. foo.prototype
  9. );
  10. // 关键代码 end======
  11. proto.bar_prop = "bar val";
  12. bar.prototype = proto;
  13. var inst = new bar;
  14. console.log(inst.foo_prop); // foo val
  15. console.log(inst.bar_prop); // bar val

【示例2】

  1. function foo(){}
  2. foo.prototype = {
  3. foo_prop: "foo val"
  4. };
  5. function bar(){}
  6. // 关键代码 start======
  7. var proto = Object.create(
  8. foo.prototype,
  9. {
  10. bar_prop: {
  11. value: "bar val"
  12. }
  13. }
  14. );
  15. // 关键代码 end======
  16. bar.prototype = proto;
  17. var inst = new bar;
  18. console.log(inst.foo_prop); // foo val
  19. console.log(inst.bar_prop); // bar val

二、优势
1、支持当前所有非微软版本或者 IE9 以上版本的浏览器。
2、允许一次性地直接设置 proto属性,以便浏览器能更好地优化对象。
3、同时允许通过 Object.create(null) 来创建一个没有原型的对象。
三、缺陷
1、不支持 IE8 以下的版本。
(1)随着微软不再对系统中运行的旧版本浏览器提供支持,这将不是在大多数应用中的主要问题。
2、 这个慢对象初始化在使用第二个参数的时候有可能成为一个性能黑洞,因为每个对象的描述符属性都有自己的描述对象。
(1)当以对象的格式处理成百上千的对象描述的时候,可能会造成严重的性能问题。

Object.setPrototypeOf

一、示例

  1. function foo(){}
  2. foo.prototype = {
  3. foo_prop: "foo val"
  4. };
  5. function bar(){}
  6. var proto = {
  7. bar_prop: "bar val"
  8. };
  9. // 关键代码 start======
  10. Object.setPrototypeOf(
  11. proto, foo.prototype
  12. );
  13. // 关键代码 end======
  14. bar.prototype = proto;
  15. var inst = new bar;
  16. console.log(inst.foo_prop);
  17. console.log(inst.bar_prop);
  1. function foo(){}
  2. foo.prototype = {
  3. foo_prop: "foo val"
  4. };
  5. function bar(){}
  6. var proto;
  7. // 关键代码 start======
  8. proto=Object.setPrototypeOf(
  9. { bar_prop: "bar val" },
  10. foo.prototype
  11. );
  12. // 关键代码 end======
  13. bar.prototype = proto;
  14. var inst = new bar;
  15. console.log(inst.foo_prop);
  16. console.log(inst.bar_prop)

二、优势
1、支持所有现代浏览器和微软IE9+浏览器。
2、允许动态操作对象的原型,甚至能强制给通过 Object.create(null) 创建出来的没有原型的对象添加一个原型。
三、缺陷
1、这个方式表现并不好,应该被弃用。
2、如果你在生产环境中使用这个方法,那么快速运行 Javascript 就是不可能的,因为许多浏览器优化了原型,尝试在调用实例之前猜测方法在内存中的位置,但是动态设置原型干扰了所有的优化,甚至可能使浏览器为了运行成功,使用完全未经优化的代码进行重编译。
3、不支持 IE8 及以下的浏览器版本。

proto(不推荐)

一、示例

function foo(){}
foo.prototype = {
  foo_prop: "foo val"
};
function bar(){}

// 关键代码 start======
var proto = {
  bar_prop: "bar val",
  __proto__: foo.prototype
};
// 关键代码 end======

bar.prototype = proto;
var inst = new bar;
console.log(inst.foo_prop);
console.log(inst.bar_prop);

// 关键代码 start======
var inst = {
  __proto__: {
    bar_prop: "bar val",
    __proto__: {
      foo_prop: "foo val",
      __proto__: Object.prototype
    }
  }
};
// 关键代码 end======

console.log(inst.foo_prop);
console.log(inst.bar_prop)

二、优势
1、支持所有现代非微软版本以及 IE11 以上版本的浏览器。
2、将 proto 设置为非对象的值会静默失败,并不会抛出错误。
三、缺陷
1、应该完全将其抛弃,因为这个行为完全不具备性能可言。
2、如果你在生产环境中使用这个方法,那么快速运行 Javascript 就是不可能的,因为许多浏览器优化了原型,尝试在调用实例之前猜测方法在内存中的位置,但是动态设置原型干扰了所有的优化,甚至可能使浏览器为了运行成功,使用完全未经优化的代码进行重编译。
3、不支持 IE10 及以下的浏览器版本。
四、详见:https://www.yuque.com/tqpuuk/yrrefz/bxgqbc