持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第14天,点击查看活动详情
一。Javascript如何实现继承?
是什么:继承(inheritance)是面向对象软件技术当中的一个概念。
如果一个类别B“继承自”另一个类别A,就把这个B称为“A的子类”,而把A称为“B的父类”也可以称“A是B的超类”
继承的优点:
继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码,也就是代码复用。
举例:
// 汽车
class Car{
constructor(color,speed){
this.color = color
this.speed = speed
}
}
// 货车
class Truck extends Car{
constructor(color,speed){
super(color,speed)
this.Container = true // 货箱
}
}
// 货车是汽车,用于汽车的颜色和速度属性,同时货车有一个自己的属性是货箱。
实现方式:
-
原型链继承
function Parent() { this.name = 'parent1'; this.play = [1, 2, 3] } function Child() { this.type = 'child2'; } Child.prototype = new Parent() var s1 = new Child2(); var s2 = new Child2(); s1.play.push(4); // s2的play属性变量化了,这是因为两个实例使用的是同一个原型对象,内存空间是共享的 console.log(s2.play) -
构造函数继承(借助 call)
function Parent(){ this.name = 'parent'; } Parent.prototype.getName = function () { return this.name; } function Child(){ // 执行Parent方法,将当前方法的this传进去 // 注意:call只是改变了Parent方法,内部this的指向 Parent.call(this); this.type = 'child' } let child = new Child(); console.log(child.name) // 可以 console.log(child.getName()) // 报错,因为获取不到Parent原型上定义的成员 -
组合继承
function Parent() { this.name = 'parent'; this.play = [1, 2, 3]; } Parent.prototype.getName = function () { return this.name; } function Child() { // 获取到Parent本身的成员 Parent.call(this); this.type = 'child' } // 获取到Parent原型上定义的成员 Child.prototype = new Parent() // 校正构造函数指向 Child.prototype.constructor = Child; let c1 = new Child() let c2 = new Child() c1.play.push(4) console.log(c2.play); console.log(c2.getName()); -
原型式继承
这里主要借助
Object.create方法实现普通对象的继承let obj1 = { name:'张三', age:20, arr:[1,2,3] } // 将obj2的原型对象指向obj1 let obj2 = Object.create(obj1) let obj3 = Object.create(obj1) obj2.arr.push(4) console.log(obj3.arr); // 因为Object.create方法实现的是浅拷贝,多个实例的引用类型属性指向相同的内存,存在篡改的可能 -
寄生式继承
寄生式继承在上面继承基础上进行优化,利用这个浅拷贝的能力再进行增强,添加一些方法
let obj1 = { name:'张三', age:20, arr:[1,2,3] } // 封装一个方法,实现继承 function clone(original) { let clone = Object.create(original); clone.getName = function() { return this.name; }; return clone; } let obj2 = clone(obj1) console.log(obj2.getName()); -
寄生组合式继承
寄生组合式继承,借助解决普通对象的继承问题的
Object.create方法,在前面几种继承方式的优缺点基础上进行改造,这也是所有继承方式里面相对最优的继承方式function clone (parent, child) { // 这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程 child.prototype = Object.create(parent.prototype); // 校正构造函数指向 child.prototype.constructor = child; } function Parent() { this.name = 'parent'; this.play = [1, 2, 3]; } Parent.prototype.getName = function () { return this.name; } function Child() { // 改变Parent方法中this的指向,目的是获取Parent方法中的成员 Parent.call(this); this.friends = 'child5'; } // 将Child的原型对象指向Parent的原型对象 clone(Parent, Child); // 在Child原型对象上添加一个成员 Child.prototype.getFriends = function () { return this.friends; } // 不会修改Parent的原型对象 console.log(Parent.prototype); -
ES6 中
extends关键字直接实现JavaScript的继承class Person { constructor(name) { this.name = name } // 原型方法 // 即 Person.prototype.getName = function() { } // 下面可以简写为 getName() {...} getName = function () { console.log('Person:', this.name) } } class Gamer extends Person { constructor(name, age) { // 子类中存在构造函数,则需要在使用“this”之前首先调用 super()。 super(name) this.age = age } } const asuna = new Gamer('Asuna', 20) asuna.getName() // 成功访问到父类的方法