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']
相关推荐
枫叶梨花1 小时前
Electrobun透明窗口在Windows上的输入穿透排查
前端·electron·bun
云上工程笔记2 小时前
AstraFlow + React/Vite:如何用自然语言开发并部署一个 AI 咖啡网站原型
前端·人工智能·react.js
Q一件事2 小时前
ArcGIS中TypeError: can‘t multiply sequence by non-int of type ‘str‘错误
前端·javascript·arcgis
美狐美颜SDK开放平台3 小时前
从视频处理到实时渲染:直播APP中视频美颜SDK的关键技术解析
前端·人工智能·架构·实时互动·音视频·视频美颜sdk
yume_sibai3 小时前
ES6 核心知识点完全总结(变量 + 箭头函数 + 解构 + Promise + 模块化)
前端·ecmascript·es6
Moment3 小时前
为什么市面上的 coding agent 大多数都基于Nodejs?
前端·后端·面试
吃瓜的猹3 小时前
Gemini 3.8 Flash 是真的站起来了,一起来看看我到底做了什么吧~
前端
光影少年3 小时前
React18 对RN 的影响
android·前端·react.js·ios·前端框架
tryCbest3 小时前
Vue Router学习及使用
前端·vue.js
杉氧3 小时前
丝滑的奥秘:Reanimated 3 动画引擎与手势处理(Gesture Handler)
android·前端·react native