• javascript中的继承


    基本术语

    本文中,proto === [[Prototype]]

    原型链

    基本思想

    1. 构造函数生成的对象有一个指针(proto)指向构造函数的原型。
    2. 如果将构造函数1的原型指向另一个构造函数2的实例,则构造函数1的实例__proto__.proto 指向了构造函数2的原型。原型2和实例1之间构成了一条原型。
    function Super() {};
    function Sub() {};
    Super.prototype.sayHi = function () { console.log('hi') };
    Sub.prototype = new Super();
    
    const supInstance1 = new Sub();
    supInstance1.sayHi(); // hi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    缺点

    1. Sub.prototype.constructor 被改变。
    2. Sub.prototype = new Sub(),new的过程可能会有副作用。

    盗用构造函数(经典继承)

    基本思想

    1. 在new一个构造函数1的时候,通过在构造函数1中调用另一个构造函数2来实现继承。
    2. 通过调用构造函数2,将构造函数2中的实例属性复制到构造函数1的实例中。
    function Car(wheels) {
        this.wheels = wheels;
    }
    
    function ElectricCar(wheels, type) {
        Cat.call(this, wheels);
        this.type = type;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    缺点

    1. 子类的实例不能访问父类原型上的方法。
    2. 必须在构造函数中定义方法,因此函数(构造函数1)不能重用。

    组合继承(伪经典继承)

    基本思想

    1. 将子类原型指向父类实例,通过原型链来实现子类继承父类原型上的方法。
    2. 通过盗用构造函数来继承实例的属性。
    function Super(title) {
      this.title = title;
    }
    Super.prototype.sayHi = function () {
      console.log(this.title, " <- Super title");
    };
    
    function Sub(superTitle, subTitle) {
      Super.call(this, superTitle);
      this.subTitlte = subTitle;
    }
    
    Sub.prototype = new Super();
    
    const subInstance = new Sub("superTitle in instance", "subTitle in instance");
    
    subInstance.sayHi(); // ****subtitle in instance  <- this title****
    
    /* subInstance结构类型
    **{
        "title": "superTitle in instance",
        "subTitlte": "subTitle in instance",
        [[Prototype]]: Super
    }
    
    --- 在[[Prototype]]:Super中
    --- Super的结构类型
    
    {
        title: undefined,
       [[Prototype]]: Object,
    }**
    */
    
    • 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

    缺点

    1. 在构造函数2的原型中,有无用变量title:undefined
    2. 在进行原型链的链接时,会执行new Super() 过程,如果构造函数Super是一个有副作用的函数,会有不可预知的问题。(两次调用Super函数)
    3. 子类的原型的constructor属性指向丢失。

    原型式继承

    基本思想

    对象间构造原型链实现属性的共享。

    实现

    es5的Object.create函数

    // 返回一个对象,对象.__proto__ 指向 o
    function objectCreate(o) {
    	function F() {};
    	F.prototype = o;
    	return new F();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    寄生式继承

    基本思想

    1. 通过工厂模式创建新对象,构造函数中通过原型式继承来获取目标对象的能力。
    function createSub(originObject) {
    	const newObject = Object.create(originObject);
    	newObject.sayHi = function() { console.log('hi') };
      return newObject;
    }
    
    const person = { 
    	name: '张三',
    	friends: ['李四', '赵武', '甲一']
    };
    
    const personA = createSub(person);
    personA.sayHi();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    优缺点

    ???感觉没有使用的场景

    寄生式组合继承(目前比较完美的解决方案)

    基本思想

    1. 重写子构造函数的原型,将构造函数原型的[[prototype]]指向从默认Object改为父构造函数的原型。实现原型属性的继承。
    2. 在子构造函数调用父构造函数,实现实例属性的复用。
    function Super(name) {
    		this.name = name;
    }
    Super.prototype.sayHi = function() { console.log(`hi this is super and name is ${this.name}`)};
    
    function Sub(name, age) {
    	Super.call(this, name);
    	this.age = age;
    }
    
    Sub.prototype = Object.create(Super.prototype, {
    	constructor: {
        value: Sub,
        enumerable: false,
        writable: true,
        configurable: true,
      },
    });
    // 这里同样可以用es6中的 setPrototypeOf 来设置原型链的链接
    
    Sub.prototype.sayAge = function () { console.log(`the age of ${this.name} is ${this.age}`); }
    
    const subInstance = new Sub('Sub instance', 12);
    
    subInstance.sayHi(); // hi this is super and name is Sub instance
    subInstance.sayAge(); // **the age of Sub instance is 12**
    
    
    • 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

    优缺点

    1. 功能上没有缺点
    2. 实现起来冗长

    es6的继承

    extends关键字

    es6的继承本质上是es5继承的语法糖。

    // 可以实现和寄生式组合继承完全相同的效果
    class Super {
    	constructor(name) {
    		this.name = name;
    	}
    
    	sayHi() {
    		 console.log(`hi this is super and name is ${this.name}`)
    	}
    }
    
    class Sub extends Super {
    	constructor(name,  age) {
    		super(name);
    		this.age = age;
    	}
    	sayAge() {
    		 console.log(`the age of ${this.name} is ${this.age}`)
    	}
    
    }
    
    const subInstance = new Sub('Sub instance', 12);
    
    subInstance.sayHi(); // hi this is super and name is Sub instance
    subInstance.sayAge(); // **the age of Sub instance is 12**
    
    参考数据:
    - [1] [你不知道的JavaScript]
    - [2] [JavaScript高级程序设计]
    - [3] [[mdn](https://developer.mozilla.org/)](https://developer.mozilla.org/)
    
    • 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
  • 相关阅读:
    qcow2、raw、vmdk等镜像格式工具
    第八章-项目质量管理
    推荐一款.NET开源的轻量级分布式服务框架
    软件设计师 下午题第6题
    【python爬虫】—图片爬取
    [附源码]JAVA毕业设计日常办公管理系统(系统+LW)
    集合转json json转集合
    Flink系列之Flink中StateBackend深入剖析和应用
    产品经理基础--04流程图与结构图
    ptyhon flask SSE 浏览器和服务器实时通信-例子实时推送随机数到前端画echart曲线图
  • 原文地址:https://blog.csdn.net/weixin_43154931/article/details/134042265