一文搞懂js中的继承

原型链继承(Prototypal inheritance)

1. [[Prototype]] (对象的属性)

  • [[Prototype]] 是 对象隐藏 属性
  • 它的值要么为 null,要么就是对另一个对象的引用
  • __proto__ 是 [[Prototype]] 的 getter/setter
    Object.getPrototypeOf/Object.setPrototypeOf 来取代 __proto__ 去 get/set 原型
  • 这个属性在对象继承对象时用到
    一文搞懂js中的继承_第1张图片

2. prototype (函数的属性)

  • 每个 函数 都有prototype属性
  • 它的值要么是一个对象,要么就是 null
  • 默认的 "prototype" 是一个只有属性 constructor 的对象,属性 constructor 指向函数自身
  • 如果 F.prototype 是一个对象,那么 new 操作符会使用它为新对象设置 [[Prototype]]
  • "prototype" 属性仅在设置了一个构造函数(constructor function),并通过 new 调用时,才具有这种特殊的影响。


    一文搞懂js中的继承_第2张图片
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中的原型式继承

你可能感兴趣的:(一文搞懂js中的继承)