javascript - 原型链

时间:2017-10-16 17:28:20

标签: javascript prototype chain

请考虑这样的代码:

class a {
    constructor() {
        this.test = "test from a";
        this.testA = "X";
    }

    mimi() {
        console.log('aaaaaaaa', this.test, this.testA)
    }

}

class b extends a {
    constructor() {
        super();
        this.test = "test from b"
    }

    mimi() {
        console.log('bbbbbbbb', this.test, this.testA)
    }

}

class c extends b {
    constructor() {
        super();
        this.test = "test from c"
    }

    mimi() {
        console.log('cccccccc', this.test, this.testA)
    }

    meme() {
        var test = kalreg.__proto__.__proto__;
        test.mimi();
        var test2 = kalreg.__proto__.__proto__.__proto__;
        test2.mimi();
    }
}

var kalreg = new c(); kalreg.mimi(); kalreg.meme();

我得到的输出是:

cccccccc test from c X
bbbbbbbb undefined undefined
aaaaaaaa undefined undefined

我的对象逻辑让我使用" a "作为最通用的课程," b "这是一个孩子," c "这是" b "的孩子。我想" c "拥有" b "的所有方法和属性和" a"但是" a "的功能的一部分?被" b "覆盖所以唯一的方法" c "可能有权访问被覆盖的功能是使用原型链。 不幸的是,我的方式不起作用所以问题是:

  1. meme()函数中,如何避免使用kalreg.proto - 我被告知这种访问原型的方式对代码来说是危险且危险的。
  2. 在我看来,应该没有" undefined"然而,在输出中,有。 预期的输出是:

    来自c X的cccccccc测试

    来自b X的bbbbbbbb测试

    来自X的aaaaaaaa测试

  3. 如何实现它?

    谢谢!

1 个答案:

答案 0 :(得分:3)

  

meme() function中,如何避免使用kalreg。 proto

对于您确实需要从超类访问属性的用例,请使用super(但请注意,这对testtestA无效,因为这些不是在超类或其prototype对象上,它们位于使用new c创建的实例上;更多内容在下面。)

另外:避免__proto__。在极少数需要访问对象原型的情况下,请使用Object.getPrototypeOf

  

在我看来,输出中应该没有“未定义”但是有。预期产出是:

     

来自c X的cccccccc测试

     

来自b X的bbbbbbbb测试

     

来自X的aaaaaaaa测试

输出正确,因为您调用mimi的原型对象没有testtestA属性。只有使用new c创建的对象才具有这些属性。并且只有一个这样的对象,因此test无论您拨打"test from c"哪个mimi都是testA"X"始终为test

在评论中,您已经询问当每个构造函数中包含this.test = ...时,如何只能有一个var kalreg = new c();。一旦你完成kalreg,我们就看一下记忆中的内容:

                                         +−−−−−−−−−−−−+
a−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−>| (function) |  +−−−>(Function.prototype)
                                      |  +−−−−−−−−−−−−+  |
                                      |  | __proto__  |−−+          +−−−−−−−−−−−−−+
                                      |  | prototype  |−−−−−−−−−−+−>|  (object)   |
                                      |  +−−−−−−−−−−−−+          |  +−−−−−−−−−−−−−+
                                      |                          |  | __proto__   |−−>...
                       +−−−−−−−−−−−−+ |                          |  | constructor |−−>a
b−−−−−−−−−−−−−−−−−−−+−>| (function) | |                          |  | mimi        |−−>...
                    |  +−−−−−−−−−−−−+ |                          |  +−−−−−−−−−−−−−+
                    |  | __proto__  |−+         +−−−−−−−−−−−−−+  |
                    |  | prototype  |−−−−−−−−+−>|  (object)   |  |
                    |  +−−−−−−−−−−−−+        |  +−−−−−−−−−−−−−+  |
                    |                        |  | __proto__   |−−+
     +−−−−−−−−−−−−+ |                        |  | constructor |−−>b
c−−−>| (function) | |                        |  | mimi        |−−>...
     +−−−−−−−−−−−−+ |                        |  +−−−−−−−−−−−−−+
     | __proto__  |−+        +−−−−−−−−−−−−−+ |
     | prototype  |−−−−−−−+−>|  (object)   | |
     +−−−−−−−−−−−−+       |  +−−−−−−−−−−−−−+ |
                          |  | __proto__   |−+
                          |  | constructor |−−>c
          +−−−−−−−−−−−−+  |  | mimi        |−−>...
kalreg−−−>|  (object)  |  |  | meme        |−−>...
          +−−−−−−−−−−−−+  |  +−−−−−−−−−−−−−+
          | __proto__  |−−+
          | test       |
          | testA      |
          +−−−−−−−−−−−−+

如您所见,只有对象test指向testAthis。为什么?因为在调用每个构造函数期间,new引用该对象;这就是super()this的工作方式。所以,由于this.test = ...引用了该对象,因此每个构造函数都会执行c行,并且由于mimi中的那个是最后一个运行的,所以它“胜出”。

您可以访问test方法的超类版本,但由于它们都显示"test from c"属性,因此它们都会显示super。要显示不同的内容,他们必须要显示不同的属性。此外,使用a.prototype.mimi,您只能升级一级,所以如果您想升级两级,则可以明确使用this.__proto__.__proto__.mimi(或b,或者设置一些设施a致电mimi的{​​{1}}。

每个级别具有不同属性的示例,并b提供superMimi ca可以使用mimi class a { constructor() { this.testA = "test from a (this.testA)"; } mimi() { console.log('aaaaaaaa', this.testA); } } class b extends a { constructor() { super(); this.testB = "test from b (this.testB)"; } mimi() { console.log('bbbbbbbb', this.testB) } superMimi() { return super.mimi(); } } class c extends b { constructor() { super(); this.testC = "test from c (this.testC)"; } mimi() { console.log('cccccccc', this.testC); } meme() { super.mimi(); // Uses b's version super.superMimi(); // Uses a's version this.__proto__.__proto__.__proto__.mimi.call(this); // Also uses a's version var p = Object.getPrototypeOf(this); var p2 = Object.getPrototypeOf(p); var p3 = Object.getPrototypeOf(p2); p3.mimi.call(this); // Also uses a's version } } var kalreg = new c(); kalreg.mimi(); kalreg.meme();

{{1}}