[[HomeObject]] 到底是啥新奇玩意? --<Javascript 学习笔记 2>
Lemon1x 37 0

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 指向不变。

评论区

索引目录