JavaScript继承
1、JS 的继承到底有多少种实现方式呢?
2、ES6 的 extends 关键字是用哪种继承方式实现的呢?
继承种类
原型链继承
function Parent1() {
this.name = 'parentl'
this.play = [1, 2, 3]
}
function Child1() {
this.type = 'child2'
}
Child1.prototype = new Parent1();
console.log(new Child1());
let child1 = new Child1();
child1.play.push(4)
let child2 = new Child1();
console.log(child1.play,child2.play)
输出:
Parent1 { type: 'child2' }
[ 1, 2, 3, 4 ] [ 1, 2, 3, 4 ]
特点
父类内存空间是共享的,当一个发生变化的时候,另外一个也随之进行了变化。
构造函数继承(借助 call)
function Parent1() {
this.name = 'parent'
}
Parent1.prototype.getName = function () {
return this.name;
}
function Child1() {
Parent1.call(this);
this.type = 'child1'
}
let child = new Child1();
console.log(child);
console.log(child.getName())
输出
Child1 { name: 'parent', type: 'child1' }
C:\Users\liyd\WebstormProjects\test\dataConvert.js:16
console.log(child.getName())
^
TypeError: child.getName is not a function
缺点:
只能继承父类的实例属性和方法。不能继承原型属性和方法。
组合继承方式(推荐)
function Parent3() {
this.name = 'parent3'
this.play =[1,2,3]
}
Parent3.prototype.getName = function () {
return this.name;
}
function Child3() {
Parent3.call(this);
this.type = 'child6'
}
// 第一次调用Parent3
Child3.prototype = new Parent3()
// 手动挂上构造器,指向自己的构造函数
Child3.prototype.constructor = Child3
var child3 = new Child3();
var child4 = new Child3();
child3.play.push(4)
console.log(child3.play,child4.play)
console.log(child3.getName())
console.log(child4.getName())
输出:
[ 1, 2, 3, 4 ] [ 1, 2, 3 ]
parent3
parent3
原型式继承
let parent4 = {
name:"parent4",
friends:["p1","p2","p3"],
getName:function () {
return this.name
}
}
let person4 = Object.create(parent4)
person4.name = "tom"
person4.friends.push("无始")
let person5 = Object.create(parent4);
person5.friends.push("狂蟒")
console.log(person4.name)
console.log(person4.name === person4.getName())
console.log(person5.name)
console.log(person4.friends)
console.log(person5.friends)
输出:
tom
true
parent4
[ 'p1', 'p2', 'p3', '无始', '狂蟒' ]
[ 'p1', 'p2', 'p3', '无始', '狂蟒' ]
寄生式继承
使用原型式继承可以获得一份目标对象的浅拷贝然后利用这个浅拷贝的能力再进行增强添加一些方法
- 寄生式继承相比于原型式继承还是在父类基础上添加了更多的方法
let parent5 = {
name:"parent5",
friends:["p1","p2","p3"],
getName:function () {
return this.name
}
}
function clone(original) {
let clone = Object.create(original)
clone.getFriends = function (){
return this.friends
}
return clone
}
let person5 = clone(parent5);
let person6 = clone(parent5);
person5.friends.push("666")
console.log(person5.getName())
console.log(person5.getFriends())
console.log(person6.getName())
console.log(person6.getFriends())
let person5 = clone(parent5);
console.log(person5.getName())
console.log(person5.getFriends())
输出:
parent5
[ 'p1', 'p2', 'p3', '666' ]
parent5
[ 'p1', 'p2', 'p3', '666' ]
寄生组合式继承(强烈推荐)
在前面这几种继承方式的优缺点基础上进行改造得出了寄生组合式的继承方式
这也是所有继承方式里面相对最优的继承方式
function clone(parent, child) {
// 这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程
child.prototype = Object.create(parent.prototype)
child.prototype.constructor = child
}
function Parent6(){
this.name = "parent6"
this.play = [1,2,3]
}
Parent6.prototype.getName = function () {
return this.name
}
function Child(){
Parent6.call(this)
this.friends = 'child6'
}
clone(Parent6,Child)
Child.prototype.getFriends = function () {
return this.friends
}
let person6 = new Child()
console.log(person6)
console.log(person6.getName())
console.log(person6.getFriends())
输出:
Child { name: 'parent6', play: [ 1, 2, 3 ], friends: 'child6' }
parent6
child6
总结
extends 实现继承(超推荐 ES6)
语法糖
class Person{
constructor(name) {
this.name = name
}
getName = function () {
console.log('Person:',this.name)
return this.name
}
}
class Gamer extends Person{
constructor(name,age) {
super(name);
this.age = age
}
}
let gamer = new Gamer("无始无终",26);
console.log(gamer.getName())
输出:
Person: 无始无终
无始无终