Tại sao trong JavaScript là (super .__ proto__ === này .__ proto__) đúng?


10

Có vẻ như trong các lớp JavaScript (ES6) super.__proto__ === this.__proto__.

Bạn có thể giải thích tại sao đây là trường hợp? Hành vi có vẻ nhất quán trên các trình duyệt khác nhau, vì vậy tôi nghi ngờ điều này được chỉ định ở đâu đó trong thông số kỹ thuật.

Hãy xem xét các mã sau đây:

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();

Tôi đã mong đợi rằng super.__proto__.myFunc();sẽ gọi chức năng myFunc()của lớp Level1và đó super.__proto__ !== this.__proto__. Thay vào đó super.__proto__.myFunc();thực sự gọi myFunc()các lớp Level3(nó gọi chính nó) và sau đó trong lần gọi thứ hai, nó gọi myFunc()lớp Level2. Điều này là hoàn toàn dễ hiểu nếu super.__proto__ === this.__proto__mã mà chứng minh.

Bạn có thể giải thích lý do tại sao super.__proto__ === this.__proto__trong ví dụ này? Nếu có thể, vui lòng cung cấp tài liệu tham khảo cho phần có liên quan của thông số kỹ thuật.

Câu trả lời:


6

Object.prototype.__proto__là một tài sản với một getter [1] . Nó hoạt động dựa trên thisgiá trị của nó . Không có superđối tượng thực sự là một thisgiá trị (bạn không thể viết Object.getPrototypeOf(super)), chỉ là một supercách tìm kiếm các thuộc tính, this.__proto__super.__proto__có nghĩa là điều tương tự miễn __proto__là cũng không được định nghĩa ở bất cứ đâu thấp hơn trong chuỗi nguyên mẫu.

Đối chiếu:

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__'));


Tôi đã nghi ngờ rằng điều này có liên quan đến việc __proto__thực sự là các hàm truy cập Object.prototypevà hoạt động dựa trên thisgiá trị của chúng . Nhưng tôi chỉ không tưởng tượng rằng nó superthực sự được chỉ định để làm việc theo cách này. Tôi nghĩ rằng supernó gần tương đương với this.__proto__.__proto__, vì vậy super.__proto__sẽ tương đương với this.__proto__.__proto__.__proto__hành vi mà tôi mong đợi. Bạn có biết, nơi supercụ thể hành vi chính xác được chỉ định?
Jens Moser

@JensMoser: Tôi sẽ tìm thấy nó một chút, nhưng hãy tưởng tượng việc sử dụng bình thường super, như thế nào super.setFoo('bar'). Bạn sẽ không muốn điều đó hoạt động trên một nguyên mẫu thay vì thể hiện.
Ry-

@georg Tôi biết rằng đó __proto__là một tài sản truy cập trên Object.prototype. Khi tôi yêu cầu tham chiếu đến thông số kỹ thuật, tôi có nghĩa là một tham chiếu đến hành vi chính xác của supertừ khóa kết hợp với __proto__. Xem bình luận trước của tôi.
Jens Moser

@ Ry- Vâng, tôi đã đơn giản hóa một chút. Sự hiểu biết chính xác của tôi super.setFoo('bar')sẽ là, nó tương đương với this.__proto__.__proto__.setFoo.call(this, 'bar'). Vì vậy, supertự động gọi các chức năng với chính xác this.
Jens Moser

1
@JensMoser super.__proto__(theo phương thức của Level3lớp) hoàn toàn tương đương vớiReflect.get(Object.getPrototypeOf(Level3.prototype), "__proto__", this)
Bergi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.