ทำไมใน JavaScript (super .__ proto__ === นี้ .__ proto__) จริง


10

ดูเหมือนว่าใน JavaScript (ES6) super.__proto__ === this.__proto__ชั้นเรียน

คุณช่วยอธิบายได้ไหมว่าทำไมในกรณีนี้ พฤติกรรมดูเหมือนว่าสอดคล้องกันในเบราว์เซอร์ที่แตกต่างกันดังนั้นฉันสงสัยว่านี่จะถูกระบุไว้ในสเป็ค

พิจารณารหัสต่อไปนี้:

class Level1 {
    myFunc() {
        console.log('Level1');
    }
}

class Level2 extends Level1 {
    myFunc() {
        console.log('Level2');
    }
}

class Level3 extends Level2 {
    myFunc() {
        console.log('Level3 BEGIN ' + Math.random()); 
        super.__proto__.myFunc();
        console.log(super.__proto__ === this.__proto__);
        console.log('Level3 END'); 
    }
}

const foo = new Level3();
foo.myFunc();

ฉันคาดว่าsuper.__proto__.myFunc();จะเรียกฟังก์ชันmyFunc()ของคลาสLevel1และสิ่งsuper.__proto__ !== this.__proto__นั้น แต่super.__proto__.myFunc();ที่จริงเรียกร้องmyFunc()ของชั้นLevel3(มันเรียกตัวเอง) และจากนั้นในการภาวนาที่สองที่เรียกว่าของชั้นเรียนmyFunc() Level2นี่เป็นสิ่งที่เข้าใจได้อย่างสมบูรณ์หากsuper.__proto__ === this.__proto__รหัสนั้นแสดงให้เห็น

คุณช่วยอธิบายเหตุผลได้ทำไมsuper.__proto__ === this.__proto__ในตัวอย่างนี้ ถ้าเป็นไปได้โปรดให้การอ้างอิงถึงส่วนที่เกี่ยวข้องของข้อมูลจำเพาะ

คำตอบ:


6

Object.prototype.__proto__เป็นทรัพย์สินที่มีความทะเยอทะยาน[1] มันทำงานกับthisมูลค่าของมัน ไม่มีsuperวัตถุจริงที่จะเป็นthisค่า (คุณไม่สามารถเขียนได้Object.getPrototypeOf(super)) เป็นsuperวิธีการค้นหาคุณสมบัติดังนั้นthis.__proto__และsuper.__proto__หมายความว่าสิ่งเดียวกันตราบใดที่__proto__ยังไม่ได้กำหนดไว้ที่ใด ๆ ในห่วงโซ่ต้นแบบ

เปรียบเทียบ:

class Parent {
    get notProto() {
        return this instanceof Child;
    }
}

class Child extends Parent {
    test() {
        console.log(super.notProto);
    }
}

new Child().test();

// bonus: [1]
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));


ฉันสงสัยแล้วว่าสิ่งนี้เกี่ยวข้องกับ__proto__การเป็นฟังก์ชั่นการเข้าถึงObject.prototypeและดำเนินการกับthisคุณค่าของพวกเขา แต่ฉันแค่นึกไม่ออกว่าsuperจริง ๆ แล้วมันถูกกำหนดให้ทำงานแบบนี้ ฉันคิดว่าsuperจะเทียบเท่าโดยประมาณthis.__proto__.__proto__ดังนั้นsuper.__proto__จะเท่ากับthis.__proto__.__proto__.__proto__ที่จะแสดงพฤติกรรมที่ฉันคาดหวัง คุณรู้หรือไม่ว่าในสเปคระบุพฤติกรรมที่แน่นอนของsuperที่ระบุ?
Jens Moser

@JensMoser: ฉันจะหาได้ในบิต แต่จินตนาการการใช้งานปกติของเช่นsuper super.setFoo('bar')คุณไม่ต้องการให้มันทำงานบนต้นแบบแทนที่จะเป็นตัวอย่าง
Ry-

@georg ฉันรู้ว่าเป็นสถานที่ให้บริการการเข้าถึงบน__proto__ Object.prototypeเมื่อผมถามสำหรับการอ้างอิงถึงสเป็คที่ผมหมายถึงการอ้างอิงถึงพฤติกรรมที่แน่นอนของคำหลักร่วมกับsuper __proto__ดูความคิดเห็นก่อนหน้าของฉัน
Jens Moser

@ Ry- ใช่ฉันทำให้มันง่ายขึ้นเล็กน้อย ความเข้าใจที่ถูกต้องของฉันจะเป็นว่ามันจะเทียบเท่ากับsuper.setFoo('bar') this.__proto__.__proto__.setFoo.call(this, 'bar')ดังนั้นจะเรียกฟังก์ชั่นที่มีความถูกต้องโดยอัตโนมัติsuper this
Jens Moser

1
@JensMoser super.__proto__(ในวิธีการของLevel3ชั้นเรียน) นั้นเทียบเท่ากับReflect.get(Object.getPrototypeOf(Level3.prototype), "__proto__", this)
Bergi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.