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/)
相关推荐
weixin_472339462 小时前
高效处理大体积Excel文件的Java技术方案解析
java·开发语言·excel
枯萎穿心攻击2 小时前
响应式编程入门教程第二节:构建 ObservableProperty<T> — 封装 ReactiveProperty 的高级用法
开发语言·unity·c#·游戏引擎
Eiceblue4 小时前
【免费.NET方案】CSV到PDF与DataTable的快速转换
开发语言·pdf·c#·.net
m0_555762904 小时前
Matlab 频谱分析 (Spectral Analysis)
开发语言·matlab
像风一样自由20204 小时前
HTML与JavaScript:构建动态交互式Web页面的基石
前端·javascript·html
浪裡遊5 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
lzb_kkk6 小时前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节
好开心啊没烦恼6 小时前
Python 数据分析:numpy,说人话,说说数组维度。听故事学知识点怎么这么容易?
开发语言·人工智能·python·数据挖掘·数据分析·numpy
面朝大海,春不暖,花不开6 小时前
使用 Python 实现 ETL 流程:从文本文件提取到数据处理的全面指南
python·etl·原型模式
简佐义的博客6 小时前
破解非模式物种GO/KEGG注释难题
开发语言·数据库·后端·oracle·golang