持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情
继承
在js中,继承有很多种方式,这些不同的方式也有不同的利弊,我们来了解一下继承的种类和优缺点。
原型链继承
当对象的原型对象指向了另一个对象时,那么当前对象就会继承原型对象的内容
function a (){
this.name = ['aaa']
}
a.prototype.getName = function(){
return this.name
}
function b (){
}
b.prototype = new a()
let child1 = new b()
let child2 = new b()
child1.name.push('ccc')
console.log(child2.getName())
//(2) ['aaa', 'ccc']
原型链的缺点就是引用类型的对象会被继承对象共同使用,导致修改一个对象的属性会影响到其他对象的对应属性。
经典继承
在函数内通过call函数来指向被继承对象以达到继承目的
function a (){
this.name = ['aaa']
}
function b (){
return a.call(this)
}
let child1 = new b()
let child2 = new b()
child1.name.push('bbb')
//['aaa']
console.log(child2.name)
//(2) ['aaa', 'bbb']
console.log(child1.name)
相比原型链继承来说,优点是避免了对象之间属性的互相影响,缺点则是方法都得放在构造函数里面,每次创建实例都得创建一次方法
组合继承
是经典继承和原型链继承的融合方法,继承了两者的优点避免了缺点。
function a (){
this.name = ['aaa']
}
a.prototype.getName = function(){
return this.name
}
function b (aaa){
a.call(this,aaa)
}
b.prototype = new a()
let child1 = new b()
let child2 = new b()
child1.name.push('bbb')
//['aaa']
console.log(child2.name)
//(2) ['aaa', 'bbb']
console.log(child1.name)
相比原型链继承和经典继承来说,组合继承既不会使实例之间属性互相影响,又不会导致每次创建实例都需要创建一遍方法。缺点就是会调用两次父函数的构造方法
寄生组合继承
寄生组合继承呢则是要避免组合继承中调用两次父函数的缺点。
function a (){
this.name = ['aaa']
}
a.prototype.getName = function(){
return this.name
}
function b (aaa){
a.call(this,aaa)
}
function c (){}
c.prototype = a.prototype
b.prototype = new c()
let child1 = new b()
let child2 = new b()
child1.name.push('bbb')
//['aaa']
console.log(child2.name)
//(2) ['aaa', 'bbb']
console.log(child1.name)
这种方式虽然需要创建一个空函数,但并不会多次调用父函数的构造函数。
闭包
在js的面试中,什么是闭包这个问题可以说是一个非常经典的问题了,闭包的定义是什么,目前的说法是两个条件
- 函数中有使用到自由变量即不属于函数内部的变量
- 函数在创建上下文销毁后,函数依然存在
function a () {
var aa = 'aaa'
function b (){
console.log(aa)
}
return b
}
let c = a()
// aaa
c()
那么在什么时候会出现闭包呢,当我们有一个函数返回了一个内部函数,这个内部函数又调用了函数内的变量,则就构成了闭包,那么它有什么实际应用场景呢,经典的就是防抖节流函数,我们可以通过闭包来更好的实现。