es6为我们提供了一个新鲜的东西“class",其它中一个super关键字,今天我的主要目的就是想要研究一下super它到底做了一些什么,至于怎么用,这是基础~
一个假设
首先,我要假设super是基于原型链来进行的,即this._proto_.xxx,下面来做一个小例子:
let Person = {
name:"person",
eatFood(){
console.log(`${this.name} can eat food`)
}
}
let Man = {
__proto__:Person,
name:'man',
eatFood(){
this.__proto__.eatFood.call(this)
}
}
let Women = {
__proto__:Man,
name:"women",
eatFood(){
this.__proto__.eatFood.call(this)
}
}
Women.eatFood()
这样的一段代码可以符合我们的期望并输出“women can eat food”吗,答案是否定的,它会报如下错误:
VM46624:12 Uncaught RangeError: Maximum call stack size exceeded
at Object.eatFood (<anonymous>:12:10)
at Object.eatFood (<anonymous>:12:28)
at Object.eatFood (<anonymous>:12:28)
at Object.eatFood (<anonymous>:12:28)
at Object.eatFood (<anonymous>:12:28)
at Object.eatFood (<anonymous>:12:28)
at Object.eatFood (<anonymous>:12:28)
at Object.eatFood (<anonymous>:12:28)
at Object.eatFood (<anonymous>:12:28)
at Object.eatFood (<anonymous>:12:28)
我的浏览器器提示我们,这是一个 RangeError ,超出了最大调用堆栈的大小,一般这种错误提示我们第一想到的,应该是发生一个死循环。
现在让我们来分析一下这段代码,首先,我们执行了 ** Women.eatFood() ** 那么我们会进入到以下步骤里:
Women.eatFood()的方法中为我们提供的this指向了Women对象 可以理解为:
Women.__Proto__.eatFood.call(this)
而我们的Women.__proto__ === Man
那么这段代码我们可以直接理解为:Man.eatFood.call(this)
现在,我们缕清了Women.eatFood()中执行的其实是Man.eatFood.call(this),那么我们就需要再缕一下接下来执行了些什么
前文说到 this 指向的是 Women对象,那么问题来了,
Man.eatFood.call(this)中的this依然会指向我们的Women对象 即this.__proto__.eatFood.call(this)===Women.__proto__.eatFood.call(this)===Man.eatFood.call(this)
这是一个无限循环的过程,我们的Man.eatFood()在一直不停地调用着自身
[[HomeObject]]
在这个时候,我们已经发现我们之前的假设是行不通的,我们仅仅通过this并不能将我们的对象记住~
幸运的是,javascript为函数添加了一个内部属性[[HomeObject]],[HomeObject]是函数作为方法绑定到的对象,而我们可以通过使用super来解析对象的原型及方法
同样地,我们还是使用上面的这个例子进行简单的改造:
let Person = {
name:"person",
eatFood(){
console.log(`${this.name} can eat food`)
}
}
let Man = {
__proto__:Person,
name:'man',
eatFood(){
super.eatFood()
}
}
let Women = {
__proto__:Man,
name:"women",
eatFood(){
super.eatFood();
}
}
Women.eatFood()
而关于[[HomeObject]]的一些描述,我们可以在ECMA-262的文档中进行查找 adfadfaa
[[HomeObject]]是一个永久性的绑定,并且我们并能对它进行更改。
也就是说,如果我们复制一个使用super的函数,那么它的[[HomeObject]]并不会随着你的复制而更改,对于这种情况,我们往往可能会得到不如预期的结果
还有一点需要注意的是,在对象中使用的时候,对于使用函表达式声明的方法是不会具有[[HomeObject]]的,说人话就是这种情况下使用super会报:
Uncaught SyntaxError: 'super' keyword unexpected here