Javascript 学习笔记 2
本文整理自现代 Javascript 教程
在 JS 的 class 中,继承类要用 super 进行访问父类,如果我们从原理上剖析,我们可以得到如下代码:
const Base = {
name: 'Base',
show() {
console.log(`Hello ${this.name}!`);
}
};
const Sub = {
__proto__: Base,
name: 'Sub',
show() {
this.__proto__.show();
}
};
Sub.show(); // Hello Base!
然而结果很不理想,返回的竟然是 Base 而不是 Sub,那为什么呢?因为JS的 this 是自由的,它由词法环境决定,因为此时的 show 在 Base 里执行,但我们有很多改变 this 指向的方法,比如 call:
const Sub = {
__proto__: Base,
name: 'Sub',
show() {
this.__proto__.show.call(this);
}
};
Sub.show(); // Hello Sub!
这时正确的返回了Sub,可是这时我们又想继承一个对象:
const Other = {
__proto__: Sub,
name: 'Other',
show() {
this.__proto__.show.call(this);
}
};
Other.show(); // RangeError: Maximum call stack size exceeded
什么东西?竟然报错了,其实仔细想一想就知道,这时 Other 的 this 是自己,也就是Other.proto.show.call(Other) ,再往下传递,到了 Sub 的 show 方法,因为有了 call ,this 还是 Other,于是就陷入了无限的递归中。
咋解决呢,这时就用到了 super 关键词:
const Sub = {
__proto__: Base,
name: 'Sub',
show() {
super.show();
}
};
const Other = {
__proto__: Sub,
name: 'Other',
show() {
super.show();
}
};
Other.show(); // Hello Other!
终于可以正确输出了!那么这时怎么做到的呢?实际上 super 用到了一个内部隐藏属性 [[HomeObject]],它指向本对象,实际上它把代码变成了这个样子:
const Sub = {
__proto__: Base,
name: 'Sub',
show() { // Sub.show.[[HomeObject]] = Sub
Sub.__proto__.show.call(Other);
}
};
const Other = {
__proto__: Sub,
name: 'Other',
show() { // Other.show.[[HomeObject]] = Other
Other.__proto__.show.call(Other);
}
};
[[HomeObject]]只是让JS从父类原型中获取方法,this 指向不变。