【JS进阶】ES5 实现继承的几种方式

ES5 实现继承的几种方式

1. 原型链继承(Prototype Chaining)

javascript 复制代码
function Parent(name) {
  this.name = name || 'Parent';
  this.colors = ['red', 'blue'];
}

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

function Child() {}

// 关键:将子类的原型指向父类的实例
Child.prototype = new Parent();

const child1 = new Child();
child1.sayName(); // "Parent"

问题

  • 父类实例属性成为子类原型属性,会被所有子类实例共享
  • 无法向父类构造函数传参

2. 构造函数继承(借用构造函数)

javascript 复制代码
function Parent(name) {
  this.name = name || 'Parent';
  this.colors = ['red', 'blue'];
}

function Child(name) {
  // 关键:在子类构造函数中调用父类构造函数
  Parent.call(this, name);
}

const child1 = new Child('Child1');
console.log(child1.name); // "Child1"

优点

  • 可以向父类传参
  • 避免了引用属性共享问题

缺点

  • 无法继承父类原型上的方法
  • 方法都在构造函数中定义,无法复用

3. 组合继承(最常用方式)

结合原型链继承和构造函数继承:

javascript 复制代码
function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue'];
}

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

function Child(name, age) {
  // 继承实例属性
  Parent.call(this, name); // 第二次调用Parent
  this.age = age;
}

// 继承原型方法
Child.prototype = new Parent(); // 第一次调用Parent
Child.prototype.constructor = Child; // 修正constructor
Child.prototype.sayAge = function() {
  console.log(this.age);
};

const child1 = new Child('Tom', 10);
child1.colors.push('green');
console.log(child1.colors); // ['red', 'blue', 'green']
child1.sayName(); // "Tom"
child1.sayAge(); // 10

const child2 = new Child('Jerry', 8);
console.log(child2.colors); // ['red', 'blue'] (不共享)

优点

  • 实例属性独立
  • 可以继承原型方法
  • 可以向父类传参

缺点

  • 调用了两次父类构造函数

4. 原型式继承

javascript 复制代码
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

const parent = {
  name: 'Parent',
  colors: ['red', 'blue']
};

const child1 = object(parent);
child1.name = 'Child1';
child1.colors.push('green');

const child2 = object(parent);
console.log(child2.colors); // ['red', 'blue', 'green'] (共享引用属性)

类似于 Object.create(),ES5 中新增了 Object.create() 方法实现相同功能。

5. 寄生式继承

javascript 复制代码
function createAnother(original) {
  const clone = Object.create(original); // 创建新对象
  clone.sayHi = function() { // 增强对象
    console.log('Hi');
  };
  return clone;
}

const parent = {
  name: 'Parent'
};

const child = createAnother(parent);
child.sayHi(); // "Hi"

6. 寄生组合式继承(最佳方式)

解决组合继承调用两次父类构造函数的问题:

javascript 复制代码
function inheritPrototype(child, parent) {
  const prototype = Object.create(parent.prototype); // 创建父类原型的副本
  prototype.constructor = child; // 修正constructor
  child.prototype = prototype; // 赋值给子类原型
}

function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue'];
}

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

function Child(name, age) {
  Parent.call(this, name); // 只调用一次Parent构造函数
  this.age = age;
}

inheritPrototype(Child, Parent); // 实现原型继承

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

const child1 = new Child('Tom', 10);
child1.sayName(); // "Tom"
child1.sayAge(); // 10

优点

  • 只调用一次父类构造函数
  • 原型链保持不变
  • 能够正常使用 instanceofisPrototypeOf()
相关推荐
haaaaaaarry5 分钟前
Element Plus常见基础组件(一)
java·前端·javascript·vue.js
qingyingWin19 分钟前
原生微信小程序研发,如何对图片进行统一管理?
前端·微信小程序
不懂英语的程序猿29 分钟前
【JEECG】JVxeTable表格拖拽排序功能
前端·后端
拾光拾趣录35 分钟前
前端灵魂拷问:从URL到Redux,17个常见问题
前端·面试
萌萌哒草头将军42 分钟前
Prisma ORM 又双叒叕发布新版本了!🚀🚀🚀
前端·javascript·node.js
mldong1 小时前
推荐一款超高颜值的后台管理模板!Art-Design-Pro!开源!免费!
前端·vue.js·架构
草字1 小时前
uniapp 如果进入页面输入框自动聚焦,此时快速返回页面或者跳转到下一个页面,输入法顶上来的页面出现半屏的黑屏问题。
java·前端·uni-app
SiYuanFeng1 小时前
【问题未解决-寻求帮助】VS Code 中使用 Conda 环境,运行 Python 后 PowerShell 终端输出内容立即消失
开发语言·python·conda
我是ed.2 小时前
cocos Js 使用 webview 通过 postMessage 进行通信
开发语言·javascript·ecmascript
程序视点2 小时前
Wise Duplicate Finder 重复文件查找工具 - 永久免费专业版文件去重工具
前端·windows