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']
相关推荐
J不A秃V头A35 分钟前
Vue3:编写一个插件(进阶)
前端·vue.js
司篂篂1 小时前
axios二次封装
前端·javascript·vue.js
姚*鸿的博客1 小时前
pinia在vue3中的使用
前端·javascript·vue.js
宇文仲竹2 小时前
edge 插件 iframe 读取
前端·edge
Kika写代码2 小时前
【基于轻量型架构的WEB开发】【章节作业】
前端·oracle·架构
天下无贼!3 小时前
2024年最新版Vue3学习笔记
前端·vue.js·笔记·学习·vue
Jiaberrr3 小时前
JS实现树形结构数据中特定节点及其子节点显示属性设置的技巧(可用于树形节点过滤筛选)
前端·javascript·tree·树形·过滤筛选
赵啸林3 小时前
npm发布插件超级简单版
前端·npm·node.js
罔闻_spider4 小时前
爬虫----webpack
前端·爬虫·webpack
吱吱鼠叔4 小时前
MATLAB数据文件读写:1.格式化读写文件
前端·数据库·matlab