’类‘函数(构造函数)
之所以没有在你不知道的js—构造函数'类'文章中讲类函数,是因为必须懂原型链才能理解。因为js种没有真正的类,是使用原型链模拟的继承。
使用类函数
定义交通工具类Vehicle
function Vehicle() {
this.name = 'Vehicle'
}
Vehicle.prototype.engine = function() {
return '我是引擎';
}
Vehicle.prototype.load = function() {
return '我能载10人';
}
飞机、火车和汽车的类
function Car() {
}
Car.prototype.way = function() {
return '我在公路上';
}
function Plane() {
way() {
return '我在天上';
}
}
Plane.prototype.way = function() {
return '我在天上';
}
function Train() {
}
Train.prototype.way = function() {
return '我在轨道上';
}
类函数继承比较麻烦,也是class继承中使用extend的原理。 下面我们搞定它, 用飞机举例:
原型链继承
function Vehicle() {
this.name = 'Vehicle';
}
Vehicle.prototype.engine = function() {
return '我是引擎';
}
Vehicle.prototype.load = function() {
return '我能载10人';
}
function Plane() {
}
Plane.prototype = new Vehicle()
Plane.prototype.way = function() {
return '我在天上';
}
const plane1 = new Plane();
console.log(plane1.engine()) // 我是引擎
console.log(plane1) // 看下图
Vehicle的实例出现在Plane的实例的原型链中,Plane已经继承了Vehicle的方法,但是会有一个问题? 当父类有引用类型的数据时:
function Vehicle() {
this.paly = [1, 2, 3];
}
function Plane() {
}
Plane.prototype = new Vehicle()
const plane1 = new Plane();
const plane2 = new Plane();
plane2.paly.push(4);
console.log(plane1.paly) // [1, 2, 3, 4]
console.log(plane2.paly) // [1, 2, 3, 4]
发现改变plane2.play,但是plane1.play也改变了。因为都用了new Vehicle()产生的新对象。我们应该这样解决:
构造函数继承(对象冒充)
在执行new Plane()时,使用call调用Vehicle,改变Vehicle内的this指向。就会声明两个不同的paly数组。
function Vehicle() {
this.paly = [1, 2, 3];
}
function Plane() {
Vehicle.call(this)
}
const plane1 = new Plane();
const plane2 = new Plane();
plane2.paly.push(4);
console.log(plane1.paly) // [1, 2, 3]
console.log(plane2.paly) // [1, 2, 3, 4]
但是很明显这种方式不能继承原型链上的方法。我们可以融合原型链继承和构造函数继承。
原型链继承 + 构造函数继承
把prototype和call结合使用,组合式继承诞生。
function Vehicle() {
this.name = 'Vehicle';
this.paly = [1, 2, 3];
}
Vehicle.prototype.engine = function() {
return '我是引擎';
}
Vehicle.prototype.load = function() {
return '我能载10人';
}
function Plane() {
Vehicle.call(this)
}
Plane.prototype = new Vehicle()
Plane.prototype.way = function() {
return '我在天上';
}
const plane1 = new Plane();
console.log(plane1.paly)
console.log(plane1.engine())
但是Vehicle却执行了两次:
- new Vehicle()
- Vehicle.call(this) 这个问题也需要解决。
寄生式继承
使用Object.create的方式,即实现了原型链继承,又没有执行Vehicle。美滋滋!!!
function Vehicle() {
}
Vehicle.prototype.engine = function() {
return '我是引擎';
}
Vehicle.prototype.load = function() {
return '我能载10人';
}
function Plane() {
}
Plane.prototype = Object.create(Vehicle.prototype)
Plane.prototype.way = function() {
return '我在天上';
}
const plane1 = new Plane();
console.log(plane1.engine()) // 我是引擎
我们只需要把寄生式继承和构造函数继承组合就可以完美了。
寄生式继承和构造函数继承组合
这就完美了,class中的extends就是使用的这种方式。
function Vehicle() {
this.name = 'Vehicle';
this.paly = [1, 2, 3];
}
Vehicle.prototype.engine = function() {
return '我是引擎';
}
Vehicle.prototype.load = function() {
return '我能载10人';
}
function Plane() {
Vehicle.call(this)
}
Plane.prototype = Object.create(Vehicle.prototype)
Plane.prototype.way = function() {
return '我在天上';
}
const plane1 = new Plane();
const plane2 = new Plane();
plane2.paly.push(4)
console.log(plane1.paly)
console.log(plane2.paly)
总结
你可能还听说过原型继承,它和寄生类似,就不说了。
继承非常重要!!!它能让我们作出完美的封装。