一文搞懂js中的继承

原型链继承(Prototypal inheritance) 1. [[Prototype]] (对象的属性)

  • [[Prototype]] 是 对象的 隐藏 属性
  • 它的值要么为 null,要么就是对另一个对象的引用
  • __proto__ 是 [[Prototype]] 的 getter/setter
    Object.getPrototypeOf/Object.setPrototypeOf 来取代 __proto__ 去 get/set 原型
  • 这个属性在对象继承对象时用到
    一文搞懂js中的继承
    文章图片
2. prototype (函数的属性)
  • 每个 函数 都有prototype属性
  • 它的值要么是一个对象,要么就是 null
  • 默认的 "prototype" 是一个只有属性 constructor 的对象,属性 constructor 指向函数自身
  • 如果 F.prototype 是一个对象,那么 new 操作符会使用它为新对象设置 [[Prototype]]
  • 【一文搞懂js中的继承】"prototype" 属性仅在设置了一个构造函数(constructor function),并通过 new 调用时,才具有这种特殊的影响。

    一文搞懂js中的继承
    文章图片
function Parent(){ this.flag = true; this.arr = []; } function Child(){} console.log(Child.prototype.constructor); // Child // 会修改Child.prototype的constructor指向 Child.prototype = new Parent(); // 原型链继承 console.log(Child.prototype.constructor); // Parent const child1 = new Child(); const child2 = new Child(); // 非引用类型不影响 console.log(child1.flag); // true console.log(child2.flag); // true child2.flag = false; console.log(child1.flag); // true console.log(child2.flag); // false// 缺点1:引用数据类型共享,修改了child2的arr值,所有实例的值都改变 console.log(child1.arr); // [] console.log(child2.arr); // [] child2.arr.push(1); console.log(child1.arr); // [1] console.log(child2.arr); // [1] // 缺点2:无法向Parent传参

借用构造函数继承(经典继承)
function Parent(){ this.flag = true; this.arr = []; } Parent.prototype.getFlag = function(){} function Child(){ Parent.call(this); // 借用构造函数继承 } // 无法继承Parent prototype的方法 // 因为prototype只在new时有用 // child1只是Child的实例,而非Parent的实例 const child1 = new Child(); console.log(child1 instanceof Parent); // false

组合继承(原型链+经典)
// 缺点,调用2次父类构造函数 function Parent(){ this.flag = true; this.arr = []; } Parent.prototype.getFlag = function(){} function Child(){ // 通过经典继承继承实例属性的继承 Parent.call(this); // 借用构造函数继承 } // 通过原型链继承prototype方法的继承 Child.prototype = new Parent(); // 原型链继承

原型式继承
  1. 接受一个对象A
  2. 返回一个新对象B
  3. 并且B.proto --> A
// 相当于Object.create() function createObjcet(obj) { function F () {}; F.prototype = obj; return new F(); }

寄生式继承
function createObjcet(obj) { function F () {}; F.prototype = obj; return new F(); } function wraop(o){ var obj = createObjcet(o); // 在原型式继承的基础上新增一些函数或属性 obj.sayName = function(){ console.log(this.name); } return obj; }

寄生组合式继承(经典+原型式继承)
  • 和组合继承的区别,用原型式继承代替原型链继承
function createObjcet(obj) { function F () {}; F.prototype = obj; return new F(); } function Parent(){ this.flag = true; this.arr = []; } Parent.prototype.getFlag = function(){} function Child(){ // 通过经典继承继承实例属性的继承 Parent.call(this); // 借用构造函数继承 } // 通过原型式继承prototype方法的继承 Child.prototype = createObjcet(Parent.prototype); // 修正constructor Child.prototype.constructor = Child;

参考文章
  • 原型继承
  • F.prototype
  • 6种继承方式
  • js继承的多种方式
  • 做完这48道题彻底弄懂JS继承
  • JS中的原型式继承

    推荐阅读