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']
相关推荐
Kika写代码36 分钟前
【微信小程序】4|搜索框-历史搜索 | 我的咖啡店-综合实训
前端·微信小程序·小程序·notepad++
egekm_sefg2 小时前
一个基于Rust适用于 Web、桌面、移动设备等的全栈应用程序框架
开发语言·前端·rust
冴羽2 小时前
Solid.js 最新官方文档翻译(13)—— Context(上下文)
前端·javascript·react.js
ObjectX前端实验室2 小时前
交互式md文档渲染实现
前端·github·markdown
励志成为大佬的小杨3 小时前
c语言中的枚举类型
java·c语言·前端
前端熊猫4 小时前
Element Plus 日期时间选择器大于当天时间置灰
前端·javascript·vue.js
傻小胖4 小时前
React 组件通信完整指南 以及 自定义事件发布订阅系统
前端·javascript·react.js
JaxNext4 小时前
开发 AI 应用的无敌配方,半小时手搓学英语利器
前端·javascript·aigc
万亿少女的梦1684 小时前
高校网络安全存在的问题与对策研究
java·开发语言·前端·网络·数据库·python
Python私教4 小时前
Vue3中的`ref`与`reactive`:定义、区别、适用场景及总结
前端·javascript·vue.js