JavaScript ES5 继承

说来惭愧,对于 JavaScript 继承我一直都半知半觉,今天我好像突然茅塞顿开了......,也许未来的某一天我也会说这话。

我相信,对于前端开发人员来说,ES5 继承大家并不陌生,让你讲你也会娓娓道来,但是如果写下来,或许可能不太熟练。

我是基于 JavaScript 高级设计程序第三版来学习的,以下是我的一些笔记,与君共享,有不对的地方望大家指出。

ES5 继承

继承是面向对象语言一个重要特性,它允许创建子类时继承父类的属性和方法,从而实现代码的复用,减少冗余并支持模块化设计。JavaScript 中的继承主要是通过原型链实现的。

说起原型链, [[Prototype]] , prototype , proto , create , setPrototypeOf , getProtetypyOf...一系列 API 会自然浮现在脑海中, JavaScript 中每个对象都有一个私有属性指向另一个名为原型(prototype)的对象。原型对象也有一个自己的原型,层层向上直到一个对象的原型为 null。它们形成的一条称为原型链(prototype chain)的玩意。

ES5 中继承分为原型链继承 , 借用构造函数继承 , 组合继承 , 原型式继承 , 寄生式继承 , 寄生组合式继承六种。看着头就大, 对吧, 但是也有记忆技巧的。

  1. 原型链继承: 子类的原型指向父类的一个实例
  2. 借用构造函数继承: 子类在构造函数中调用父类的构造函数
  3. 组合继承: 原型链继承 + 借用构造函数继承
  4. 原型式继承: 创建一个临时性的构造函数,将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例
  5. 寄生式继承: 创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象
  6. 寄生组合式继承: 集寄生式继承和组合继承的优点而存在的类

其中:

  • 1 和 4 有同样的缺点(引用类型的属性值会被统一修改)
  • 2 和 5 有同样的缺点(方法无法复用)
  • 3 是 1 和 2 的结合版, 6 是 3 的优化版, 6 优化了 3 的会调用两次超类型构造函数的缺点(减少了一次)

原型链继承

缺点: 引用类型的值会被统一修改, 无法向超类传递参数(传递的参数会被统一影响)

js 复制代码
function SuperType(){
  this.colors = ["red", "blue", "green"];
}
function SubType(age){
  this.age = age
}
SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors); // [red,blue,green,black]
var instance2 = new SubType();
console.log(instance2.colors); // [red,blue,green,black]

借用构造函数继承

缺点: 方法无法复用, 每次创建子类实例都会创建一遍方法

js 复制代码
function superType(){
  this.colors = ["red", "blue", "green"];
  // 构造函数中定义方法,无法复用(如果把方法拿到外面,然后赋值引用,虽然可以解决问题,但是全局会被污染,捡了芝麻丢了西瓜的操作不可取)
  this.showColors = function(){
    console.log(this.colors.join(","));
  }
}
function subType(){
  superType.call(this);
}
var instance1 = new subType();
instance1.colors.push("black");
console.log(instance1.colors); // [red,blue,green,black]
var instance2 = new subType();
console.log(instance2.colors); // [red,blue,green]

组合继承

缺点: 使用 call 和 new 时, 父类构造函数都会执行

js 复制代码
function SuperType(name, color) {
  this.name = name;
  this.color = color;
}

SuperType.prototype.sayName = function() {
  console.log(this.name);
};

function SubType(name, color, age) {
  // 构造函数继承:继承属性
  SuperType.call(this, name, color);
  this.age = age; // 子类特有的属性
}

// 原型链继承:继承方法
SubType.prototype = new SuperType(); // 将子类型的原型指向父类型的实例
SubType.prototype.constructor = SubType; // 修复构造函数指向

// 添加子类自己的方法
SubType.prototype.sayAge = function() {
  console.log(this.age);
};

var instance = new SubType('Tom', ['red', 'blue'], 25);
instance.sayName(); // Tom
instance.sayAge();  // 25 
console.log(instance.color); // [ 'red', 'blue' ]

原型式继承

缺点: 引用类型的值会被统一修改

js 复制代码
function object(o){
  var Fn = function(){};
  Fn.prototype = o;
  return new Fn();
}

var obj = {
  name: 'obj',
  colors:['red','blue']
}
var o1 = object(obj);
var o2 = object(obj);
o1.colors.push('black');
console.log(o2.colors); // ['red', 'blue', 'black']

寄生式继承

缺点: 方法无法复用

js 复制代码
function createAnother(original){
  var clone = Object.create(original); // 通过调用函数创建一个新对象
  clone.sayHi = function(){ // 以某种方式来增强这个对象 (这个方法无法复用)
    console.log('hi');
  };
  return clone; // 返回这个对象
}
var obj = {
  name: 'obj',
  colors:['red','blue'],
}
var o1 = createAnother(obj);
var o2 = createAnother(obj);
o1.colors.push('black');
console.log(obj.colors); // ['red', 'blue', 'black']

寄生组合式继承

ES6 class 类的语法糖

js 复制代码
function inheritPrototype(subType, superType){
  var prototype = Object.create(superType.prototype); // 创建对象
  prototype.constructor = subType; // 增强对象
  subType.prototype = prototype; // 指定对象的原型
}

function SuperType(name){
  this.name = name
  this.colos = ['red','blue']
}

SuperType.prototype.sayName = function(){
  console.log(this.name)
}

function SubType(name,age){
  SuperType.call(this,name)
  this.age = age
}

inheritPrototype(SubType,SuperType)

SubType.prototype.sayAge = function(){
  console.log(this.age)
}

var instance = new SubType('Tom', 25);
instance.sayName(); // Tom
instance.sayAge();  // 25
instance.colos.push('yellow');
console.log(instance.colos); // ['red', 'blue', 'yellow']
相关推荐
蚂蚁RichLab前端团队1 天前
🚀🚀🚀 RichLab - 花呗前端团队招贤纳士 - 【转岗/内推/社招】
前端·javascript·人工智能
孩子 你要相信光1 天前
css之一个元素可以同时应用多个动画效果
前端·css
huangql5201 天前
npm 发布流程——从创建组件到发布到 npm 仓库
前端·npm·node.js
Days20501 天前
LeaferJS好用的 Canvas 引擎
前端·开源
小白菜学前端1 天前
vue2 常用内置指令总结
前端·vue.js
林_深时见鹿1 天前
Vue + ElementPlus 自定义指令控制输入框只可以输入数字
前端·javascript·vue.js
椒盐螺丝钉1 天前
Vue组件化开发介绍
前端·javascript·vue.js
koooo~1 天前
v-model与-sync的演变和融合
前端·javascript·vue.js
matlab的学徒1 天前
Web与Nginx网站服务(改)
linux·运维·前端·nginx·tomcat
从零开始学习人工智能1 天前
快速搭建B/S架构HTML演示页:从工具选择到实战落地
前端·架构·html