有关JavaScript继承的几种写法
程序员文章站
2022-04-11 12:50:34
...
一、通过构造函数实现继承
function Parent() {
this.name = 'name';
}
Parent.prototype.say = function () {
console.log('say');
}
function Child() {
Parent.call(this);
this.type = 'child';
}
const child = new Child();
```
这种方式通过在子类的构造函数中调用父构造函数实现继承,但是有个致命的缺点:如下图,子类实例并不能继承父类中原型对象上的属性或者方法。
这里写图片描述
## 二、通过原型对象实现继承
```js
function Parent() {
this.name = 'name';
this.favor = ['blue', 'red'];
}
Parent.prototype.say = function () {
console.log('say');
}
function Child() {
this.type = 'child';
}
Child.prototype = new Parent();
const child = new Child();
这种方式通过给子类构造函数的prototype对象赋值实现继承,如下图,无论是name属性还是say方法都能被子类实例访问到。
这里写图片描述
但是这种方式也有缺点,如下图,当父类的属性是引用类型时,子类实例继承的是同一份属性,任一实例改变该属性都会引起全局变化,无法互相隔离。
这里写图片描述
三、组合方式
function Parent() {
this.name = 'name';
this.favor = ['blue', 'red'];
}
Parent.prototype.say = function () {
console.log('say');
}
function Child() {
Parent.call(this);
this.type = 'child';
}
Child.prototype = new Parent();
const child = new Child();
结合了上两种方式,避免了上面的缺点。但是这种方式在每次实例化子类实例时,都会调用两次父类构造函数,需要优化。
四、组合优化①
function Parent() {
this.name = 'name';
this.favor = ['blue', 'red'];
}
Parent.prototype.say = function () {
console.log('say');
}
function Child() {
Parent.call(this);
this.type = 'child';
}
Child.prototype = Parent.prototype;
const child = new Child();
在给子类prototype赋值时不要采用实例化父类的方式,直接赋值父类的prototype。
其实,这种方式也有缺点:如下图,子类实例的constructor属性直接指向了父类构造函数,导致无法判断当前对象实例化自哪个构造函数。
这里写图片描述
五、组合优化②
function Parent() {
this.name = 'name';
this.favor = ['blue', 'red'];
}
Parent.prototype.say = function () {
console.log('say');
}
function Child() {
Parent.call(this);
this.type = 'child';
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const child = new Child();
终极改造完成:通过Object.create()方法指定了子类实例的__proto__属性,同时显式声明子类的constructor。
2019-06-04,先记到这里,后续还有补充。。。
上一篇: 在条形图中对X轴进行排序
下一篇: 有关继承、多态的一个实例