javascript中的继承

基本术语

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

原型链

基本思想

  1. 构造函数生成的对象有一个指针(proto)指向构造函数的原型。
  2. 如果将构造函数1的原型指向另一个构造函数2的实例,则构造函数1的实例__proto__.proto 指向了构造函数2的原型。原型2和实例1之间构成了一条原型。
jsx 复制代码
function Super() {};
function Sub() {};
Super.prototype.sayHi = function () { console.log('hi') };
Sub.prototype = new Super();

const supInstance1 = new Sub();
supInstance1.sayHi(); // hi

缺点

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

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

基本思想

  1. 在new一个构造函数1的时候,通过在构造函数1中调用另一个构造函数2来实现继承。
  2. 通过调用构造函数2,将构造函数2中的实例属性复制到构造函数1的实例中。
jsx 复制代码
function Car(wheels) {
    this.wheels = wheels;
}

function ElectricCar(wheels, type) {
    Cat.call(this, wheels);
    this.type = type;
}

缺点

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

组合继承(伪经典继承)

基本思想

  1. 将子类原型指向父类实例,通过原型链来实现子类继承父类原型上的方法。
  2. 通过盗用构造函数来继承实例的属性。
jsx 复制代码
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的原型中,有无用变量title:undefined
  2. 在进行原型链的链接时,会执行new Super() 过程,如果构造函数Super是一个有副作用的函数,会有不可预知的问题。(两次调用Super函数)
  3. 子类的原型的constructor属性指向丢失。

原型式继承

基本思想

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

实现

es5的Object.create函数

jsx 复制代码
// 返回一个对象,对象.__proto__ 指向 o
function objectCreate(o) {
	function F() {};
	F.prototype = o;
	return new F();
}

寄生式继承

基本思想

  1. 通过工厂模式创建新对象,构造函数中通过原型式继承来获取目标对象的能力。
jsx 复制代码
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. 重写子构造函数的原型,将构造函数原型的[[prototype]]指向从默认Object改为父构造函数的原型。实现原型属性的继承。
  2. 在子构造函数调用父构造函数,实现实例属性的复用。
jsx 复制代码
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. 实现起来冗长

es6的继承

extends关键字

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

jsx 复制代码
// 可以实现和寄生式组合继承完全相同的效果
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/)
相关推荐
binishuaio几秒前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE2 分钟前
【Java SE】StringBuffer
java·开发语言
就是有点傻6 分钟前
WPF中的依赖属性
开发语言·wpf
洋24015 分钟前
C语言常用标准库函数
c语言·开发语言
进击的六角龙16 分钟前
Python中处理Excel的基本概念(如工作簿、工作表等)
开发语言·python·excel
wrx繁星点点17 分钟前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式
熊的猫25 分钟前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
NoneCoder35 分钟前
Java企业级开发系列(1)
java·开发语言·spring·团队开发·开发
苏三有春35 分钟前
PyQt5实战——UTF-8编码器功能的实现(六)
开发语言·qt
Aniay_ivy42 分钟前
深入探索 Java 8 Stream 流:高效操作与应用场景
java·开发语言·python