本文最后更新于 2024-03-23T16:32:43+00:00
                  
                  
                
              
            
            
              
                
                前置知识:14、原型与原型链 - 掘金
继承:子可以访问父的属性/方法
普通继承
原理:将父实例赋值到子构造函数的原型上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
   |  function Parent(args = {}) {   this.like = args.like || ["游泳", "足球"];
    this.sayHello = function () {     console.log("你好呀~");   }; }
  Parent.prototype.sayName = function () {   console.log(`my name is ${this.name}`); };
 
  function Child(name, address) {   this.name = name;   this.address = address; }
 
  Child.prototype = new Parent(); Child.prototype.constructor = Child; 
 
  const c1 = new Child("张三", "四川", { like: ["吃饭", "睡觉"] }); const c2 = new Child("李四", "深圳");
  console.log(JSON.stringify(c1));  console.log(JSON.stringify(c2)); 
 
  c1.like.push("喝酒"); c2.like.push("跑步");
  console.log(JSON.stringify(c1.like));  console.log(JSON.stringify(c2.like)); 
  c1.sayHello();  c2.sayHello(); 
  c1.sayName();  c2.sayName(); 
 
 
  | 
 
优点:没啥优点,最基本的继承而已
缺点:父类是共享的;父类实例创建没法传参
经典继承
原理:在子构造函数内调用父构造函数,将值绑到子实例上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
   |  function Parent(args = {}) {   this.like = args.like || ["游泳", "足球"];
    this.sayHello = function () {     console.log("你好呀~");   }; }
  Parent.prototype.sayName = function () {   console.log(`my name is ${this.name}`); };
 
  function Child(name, address, parentArgs) {      Parent.call(this, parentArgs);   
    this.name = name;   this.address = address; }
  const c1 = new Child("张三", "四川", { like: ["吃饭", "睡觉"] }); const c2 = new Child("李四", "深圳");
  c1.like.push("喝酒"); c2.like.push("跑步");
  console.log(JSON.stringify(c1));  console.log(JSON.stringify(c2)); 
  c1.sayHello();  c2.sayHello(); 
 
  c1.sayName();  c2.sayName(); 
 
 
  | 
 
优点:父的属性/方法将直属于子实例,并且支持父构造函数的传参
缺点:没法继承父构造函数原型链上的属性Parent.prototype.*
组合继承
结合普通继承,补齐经典继承的缺点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
   |  function Parent(args = {}) {   this.like = args.like || ["游泳", "足球"];
    this.sayHello = function () {     console.log("你好呀~");   }; }
  Parent.prototype.sayName = function () {   console.log(`my name is ${this.name}`); };
 
  function Child(name, address, parentArgs) {      Parent.call(this, parentArgs);   
    this.name = name;   this.address = address; }
 
  Child.prototype = new Parent(); Child.prototype.constructor = Child; 
 
  const c1 = new Child("张三", "四川", { like: ["吃饭", "睡觉"] }); const c2 = new Child("李四", "深圳");
  c1.like.push("喝酒"); c2.like.push("跑步");
  console.log(JSON.stringify(c1));  console.log(JSON.stringify(c2)); 
  c1.sayHello();  c2.sayHello(); 
  c1.sayName();  c2.sayName(); 
 
  console.log(JSON.stringify(Object.getPrototypeOf(c1))); 
 
  | 
 
优点:补齐了普通、经典继承的缺点
缺点:父构造函数调用了两次
寄生组合继承
原理:解决组合继承的第二次父构造函数的调用,不让它调用呗
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
   |  function Parent(args = {}) {   this.like = args.like || ["游泳", "足球"];
    this.sayHello = function () {     console.log("你好呀~");   }; }
  Parent.prototype.sayName = function () {   console.log(`my name is ${this.name}`); };
 
  function Child(name, address, parentArgs) {      Parent.call(this, parentArgs);   
    this.name = name;   this.address = address; }
 
  Child.prototype = Object.create(Parent.prototype);  Child.prototype.constructor = Child; 
 
  const c1 = new Child("张三", "四川", { like: ["吃饭", "睡觉"] }); const c2 = new Child("李四", "深圳");
  c1.like.push("喝酒"); c2.like.push("跑步");
  console.log(JSON.stringify(c1));  console.log(JSON.stringify(c2)); 
  c1.sayHello();  c2.sayHello(); 
  c1.sayName();  c2.sayName(); 
 
  console.log(JSON.stringify(Object.getPrototypeOf(c1))); 
 
 
  | 
 
特殊说明:Parent.call(this, parentArgs)这段代码其实就是 ES6 里面,子类继承时调用的super(args)的实现逻辑
额外补充:现在有了 ES6 的class后,继承就很简单了,一个关键词extends就解决了
多重继承
功能:一子可以访问多父的属性/方法
原理:基于寄生组件继承,多次调用父构造函数即可
1 2 3 4 5 6 7 8
   |  function Child() {   Parent1.call(this)   Parent2.call(this) }
  Child.prototype = Object.create(Object.assgin({}, Parent1.prototype, Parent2.prototype)) Child.prototype.constructor = Child; 
 
  |