当前位置: 首页 > article >正文

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

ES5 实现继承的几种方式

1. 原型链继承(Prototype Chaining)

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. 构造函数继承(借用构造函数)

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. 组合继承(最常用方式)

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

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); // 第二次调用Parentthis.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(); // 10const child2 = new Child('Jerry', 8);
console.log(child2.colors); // ['red', 'blue'] (不共享)

优点

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

缺点

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

4. 原型式继承

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. 寄生式继承

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. 寄生组合式继承(最佳方式)

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

function inheritPrototype(child, parent) {const prototype = Object.create(parent.prototype); // 创建父类原型的副本prototype.constructor = child; // 修正constructorchild.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()
http://www.lryc.cn/news/2401822.html

相关文章:

  • 【数据结构】树形结构--二叉树(二)
  • JavaScript性能优化实战:深入探讨JavaScript性能瓶颈与优化技巧
  • 在 CentOS 上将 Ansible 项目推送到 GitHub 的完整指南
  • 深度学习题目1
  • Spring @Scheduled vs XXL-JOB vs DolphinScheduler vs Airflow:任务调度框架全景对比
  • 【Oracle】锁
  • 共识算法Raft系列(1)——什么是Raft?
  • JS逆向爬虫教程与实战技巧
  • Neovim - LSP 底层原理,难点配置(二)
  • 【Redis】Redis 的常见客户端汇总
  • 关于akka官方quickstart示例程序(scala)的记录
  • 2025年渗透测试面试题总结-腾讯[实习]玄武实验室-安全工程师(题目+回答)
  • 网站首页菜单两种布局vue+elementui顶部和左侧栏导航
  • AWS之迁移与传输服务
  • @Builder的用法
  • Unity3D 逻辑代码性能优化策略
  • 【Python Cookbook】文件与 IO(二)
  • vue实现点击按钮input保持聚焦状态
  • [蓝桥杯]取球博弈
  • Spring Security入门:创建第一个安全REST端点项目
  • [Java 基础]数组
  • fastadmin fildList 动态下拉框默认选中
  • java学习笔记——数组和二维数组
  • ‘pnpm‘ 不是内部或外部命令,也不是可运行的程序
  • Android Test2 获取系统android id
  • webpack打包学习
  • 基于Java(Jsp+servelet+Javabean)+MySQL实现图书管理系统
  • 服务器CPU被WMI Provider Host系统进程占用过高,导致系统偶尔卡顿的排查处理方案
  • JavaSwing之--JMenuBar
  • vue3+elementplus表格表头加图标及文字提示