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']
相关推荐
y先森4 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy4 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189114 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿5 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡6 小时前
commitlint校验git提交信息
前端
虾球xz7 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇7 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒7 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员7 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐7 小时前
前端图像处理(一)
前端