### JS继承的实现方式 JavaScript作为一种灵活且功能强大的编程语言,支持多种继承模式。下面将详细介绍几种常见的继承实现方式,并探讨它们的特点与应用场景。 #### 一、原型链继承 **核心思想**: 将父类的实例设置为子类的原型。 **实现方式**: ```javascript function Animal(name) { this.name = name || 'Animal'; this.sleep = function() { console.log(this.name + ' 正在睡觉!'); }; } Animal.prototype.eat = function(food) { console.log(this.name + ' 正在吃:' + food); }; function Cat() { // 通过这种方式,让Cat的prototype指向一个新的Animal实例 Cat.prototype = new Animal(); Cat.prototype.name = 'cat'; } // 测试代码 var cat = new Cat(); console.log(cat.name); // 输出 "cat" console.log(cat.eat('fish')); // 输出 "cat 正在吃:fish" console.log(cat.sleep()); // 输出 "cat 正在睡觉!" console.log(cat instanceof Animal); // 输出 true console.log(cat instanceof Cat); // 输出 true ``` **特点**: - 实例既是子类的实例,也是父类的实例。 - 父类新增的原型方法/属性,子类都能访问到。 - 实现简单,易于理解。 **缺点**: - 子类无法在构造函数中添加实例属性。 - 无法实现多继承。 - 共享的引用属性问题:所有子类实例会共享同一个引用。 - 创建子类实例时,无法向父类构造函数传参。 #### 二、构造继承 **核心思想**: 使用父类的构造函数来初始化子类的属性。 **实现方式**: ```javascript function Animal(name) { this.name = name || 'Animal'; this.sleep = function() { console.log(this.name + ' 正在睡觉!'); }; } function Cat(name) { // 在子类构造函数内部使用call方法调用父类构造函数 Animal.call(this, name); this.name = name || 'Tom'; } // 测试代码 var cat = new Cat('Tom'); console.log(cat.name); // 输出 "Tom" console.log(cat.sleep()); // 输出 "Tom 正在睡觉!" console.log(cat instanceof Animal); // 输出 false console.log(cat instanceof Cat); // 输出 true ``` **特点**: - 解决了原型链继承中子类实例共享父类引用属性的问题。 - 可以在创建子类实例时向父类传递参数。 - 支持多继承。 **缺点**: - 实例只属于子类。 - 只能继承父类的实例属性和方法,不能继承原型属性或方法。 - 每个子类都有父类实例函数的副本,影响性能。 #### 三、实例继承 **核心思想**: 通过创建父类的一个实例,然后为这个实例添加新的特性并返回。 **实现方式**: ```javascript function Animal(name) { this.name = name || 'Animal'; this.sleep = function() { console.log(this.name + ' 正在睡觉!'); }; } function Cat(name) { var instance = new Animal(); instance.name = name || 'Tom'; return instance; } // 测试代码 var cat = new Cat('Tom'); console.log(cat.name); // 输出 "Tom" console.log(cat.sleep()); // 输出 "Tom 正在睡觉!" console.log(cat instanceof Animal); // 输出 true console.log(cat instanceof Cat); // 输出 false ``` **特点**: - 不论是通过`new`关键字还是直接调用,返回的对象效果相同。 **缺点**: - 实例是父类的实例,不是子类的实例。 - 不支持多继承。 #### 四、拷贝继承 **核心思想**: 直接拷贝父类的所有属性到子类的原型中。 **实现方式**: ```javascript function Animal(name) { this.name = name || 'Animal'; this.sleep = function() { console.log(this.name + ' 正在睡觉!'); }; } function Cat(name) { var animal = new Animal(); for (var p in animal) { Cat.prototype[p] = animal[p]; } Cat.prototype.name = name || 'Tom'; } // 测试代码 var cat = new Cat('Tom'); console.log(cat.name); // 输出 "Tom" console.log(cat.sleep()); // 输出 "Tom 正在睡觉!" console.log(cat instanceof Animal); // 输出 false console.log(cat instanceof Cat); // 输出 true ``` **特点**: - 支持多继承。 **缺点**: - 效率低,内存占用高,因为需要拷贝父类的所有属性。 - 无法获取父类的不可枚举方法。 ### 结论 每种继承方式都有其适用场景。在实际开发中,可以根据项目的具体需求选择合适的继承方式。例如,在需要简洁且快速的实现时,可以选择构造继承;而在需要严格遵循继承关系且对性能要求不高的情况下,原型链继承可能是个不错的选择。
剩余6页未读,继续阅读
- 粉丝: 0
- 资源: 16
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助