由于JavaScript语言特性,它的继承类的继承方式是通过原型配合构造函数完成的,即使是ES6中出现的所谓的class和extends关键字,也仅仅是一种语法糖而已!
Quick Start
es5的继承
es5中属性的继续通过子类调用父类的构造函数(一般通过call的方式),方法的继承通过原型(子类的prototype指向父类的实例)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| function Feather(name, age){ this.name = name; this.age = age; }
Feather.prototype.sayHello = function(){ console.log("大家好,我叫" + this.name); }
function Son(name, age, score){ Feather.call(this, name, age); this.score = score; }
Son.prototype = new Feather(); Son.prototype.constructor = Son; Son.prototype.study = function(){ console.log(this.name + "在学习!"); }
const f = new Feather("老王", 50); const s = new Son("小王", 20, 90);
console.log(f); console.log(s); f.sayHello(); s.sayHello(); s.study();
|
显然子类的原型上没有sayHello方法,但子类的实例却能直接调用父类原型上的方法
es6的继承
es6提出了class、extends关键字,写起来更加的方便简洁,更像传统面向对象语言(比如Java、C++、Python等)的语法,但这也仅仅是一种语法糖而已,并没有改变其基于原型的本质。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Feather { constructor(name, age){ this.name = name; this.age = age; } sayHello(){ console.log("我是" + this.name + ",我" + this.age + "岁了。"); } } class Son extends Feather{ constructor(name, age, score){ super(name, age); this.score = score; } study(){ console.log(this.name + "在学习。"); } }
const f = new Feather("老李", 40); const s = new Son("小李", 10, 93);
console.log(f); console.log(s); f.sayHello(); s.sayHello(); s.study();
|
基于ES6的继承
总结
ES6的class加extend是继承方式本质仍然是ES5的原型方式,只是看起来更加简洁方便,而且更贴切传统面向对象语言的特点。还有就是ES5中继承方式有一个点必须注意:子类的原型由于改成了父类的一个实例,那么子类的原型的construct也就自然随之指向了父类的构造函数,这是不符合规范的(这个时候对子类原型添加的方法会影响父类)。所以必须进行矫正,让子类原型的construct从新指向子类自己的构造函数:Son.prototype.constructor = Son;在ES6这种语法糖的情况下就不需要考虑这么多细节了。这也是语法糖的一个特点:写法更加简单,但本质却没有改变。至于ES5中用到的call方法和ES6中用到的super方法要先理解new关键字执行背后的原理了!!