前言
在面向对象的语言中,讲究封装 继承 多态,而JavaScript这门号称万物皆对象的语言当然也有继承这一说,让我们来看看JS基于原型链的继承,和传统编程语言的区别吧!
PS:有对原型链不太了解的朋友,请移步JavaScript 原型链
原型链继承
这种继承方式是以前最经典最简单的继承方式,每一个函数对象(类)都有prototype
,返回对象原型的引用,我们可以给它赋值一个对象,就可以达到原型链继承,废多看码!
function child() {
this.age = 12;
}
function parent() {
this.name = "老王";
this.sex = "男";
this.age = 42;
}
child.prototype = new parent();
let c = new child();
console.log(c);
console.log(c.age, c.name, c.sex);
上面的例子定义了两个类,其中child
的原型指向了parent
,实现了根据原型链继承,让我们来看看效果
虽然
child
实例下没有name
sex
属性,但是由于Js原型链查找的原因,还是能够正常输出c.name
和 c.sex
,达到了我们继承的目的
-
特点
只能够继承一个父对象(但是可以链式继承)
运行速度相对较慢(有的属性需要在父对象才能找到)
this继承
这种方式是将父对象的this
拿到,获取到父对象的属性,看代码:
function child() {
Parent.call(this);
this.age = 12;
this.name = "小王";
}
function Parent() {
this.name = "老王";
this.sex = "男";
this.age = 42;
}
let c = new child();
console.log(c);
console.log(c.age, c.name, c.sex);
上方的案例中,在child
函数内部执行了父函数的call
函数,原理就是使用call
函数将Parent
的this
指向了child
,所以,看效果吧:
大家要注意,
call
的执行位置是在第一句,所以相同的属性Parent
会被child
属性覆盖,但是如果call
在下面执行,那call
上方与父对象相同的属性,则会被父对象覆盖,这取决于js代码的执行顺序
-
特点
可以多继承
运行速度较上例较快(不用在原型链中查找属性)
复制继承
大概就是把2个对象的实例遍历一次,然后把父对象的实例属性丢给子对象,嗯,大概长这样
function Parent() {
this.name = "老王";
this.sex = "男";
this.age = 42;
}
function child() {
this.extends = Parent => {
for (const key in Parent) {
console.log(key);
this[key] = Parent[key];
}
};
this.age = 12;
this.name = "小王";
}
let c = new child();
c.extends(new Parent());
console.log(c);
这种方式超级不推荐!!!!!
-
特点
能继承多个
丑,一点也不优雅
属性可能丢失,某些属性是无法遍历的
父对象会把子对象的属性覆盖
ES6继承
这是最推荐大家使用的一种方案,集所有优点于一身,且看代码:
class Parent {
constructor() {
this.name = "老王";
this.sex = "男";
this.age = 42;
}
}
class child extends Parent {
constructor() {
super();
this.age = 12;
this.name = "小王";
}
}
let c = new child();
console.log(c);
这种写法是最接近与其他语言的,看下效果吧!
-
特点
拥有上面方式的优点(除了不能继承多个)
官方推荐规范
最后一点,也是最重要的一点......帅啊 这么优雅的写法 你不动心吗??
总结
最后,希望官方早日推出多态的实现(封装,继承都已经实现了)