Một sự thật thú vị về JS __proto__

Nov 26 2022
Nếu bạn đã theo dõi tôi đủ lâu, bạn sẽ biết tôi luôn phản đối __proto__ như thế nào, tuy nhiên, vì nó đã đạt tiêu chuẩn ECMAScript từ lâu, nên vẫn có những trường hợp hiếm hoi mà tôi thấy ít nhất là cách sử dụng nó để tạo nhãn hiệu cho một đối tượng chấp nhận được: Đặt hiệu suất sang một bên và xin lưu ý rằng tôi hoàn toàn không đề xuất việc sử dụng __proto__, bài đăng này tồn tại vì những lý do khác. Vật.
Ảnh của Mark Williams trên Bapt

Nếu bạn đã theo dõi tôi đủ lâu, bạn sẽ biết __proto__tôi luôn phản đối nhiều như thế nào, tuy nhiên, vì nó đã trở thành tiêu chuẩn ECMAScript từ lâu, nên vẫn có những trường hợp hiếm hoi tôi thấy ít nhất việc sử dụng nó để tạo nhãn hiệu cho một đối tượng có thể chấp nhận được :

const factory = (fields, {prototype} = Object) => ({
  __proto__: prototype,
  ...fields
});

// mimic an <a /> reference
factory({href: '/'}, HTMLAnchorElement);

Trong Firefox, __proto__ đạt điểm cao hơn Class mới

Đặt hiệu suất sang một bên và xin lưu ý rằng tôi hoàn toàn không đề xuất việc sử dụng __proto__, bài đăng này tồn tại vì những lý do khác.

Object.prototype.__proto__

Tôi khá chắc chắn rằng mọi người đều biết trình truy cập __proto__ làm gì , vì vậy tôi muốn đề xuất cho bạn một thử thách… và vâng, đây hoàn toàn là JS hợp lệ:

class Test {}
const __proto__ = Test.prototype;

// what do these operations return?
({__proto__} instanceof Test);
({__proto__: __proto__} instanceof Test);
({"__proto__": __proto__} instanceof Test);
({["__proto__"]: __proto__} instanceof Test);

// what do these operations return?
({__proto__}.__proto__ === Test.prototype);
({__proto__: __proto__}.__proto__ === Test.prototype);
({"__proto__": __proto__}.__proto__ === Test.prototype);
({["__proto__"]: __proto__}.__proto__ === Test.prototype);

Nếu bạn chưa tự chạy những đoạn mã này để biết câu trả lời, tôi có thể giúp bạn điều đó! Trong thử thách đầu tiên, đầu ra sẽ là false, và một lần nữa true, và lý do là cả hai và được định nghĩa là thuộc tính riêng , trong khi phép gán thông qua cú pháp, không sử dụng các tính năng cú pháp đặc biệt, ngay cả khi có dấu ngoặc kép, thực sự chuyển qua trình truy cập.truefalse{__proto__}{["__proto__"]}Object.prototype.__proto__

Mặt khác, trong thử thách thứ hai (all true), việc chúng ta truy cập __proto__direct hay as không thực sự quan trọng ["__proto__"], vì vậy về cơ bản không có sự đối xứng nào trong cách chúng ta có thể kích hoạt __proto__setter, từ cách chúng ta có thể kích hoạt __proto__getter một lần nó hoặc là tài sản riêng hoặc là cổng thừa kế ma thuật.

… và không chỉ __proto__

Tôi chưa tự kiểm tra nhưng tôi tin rằng mọi trình truy cập __xxx__đặc biệt kế thừa đều chịu chung một __proto__lời nguyền, vì vậy, hãy cẩn thận khi kết hợp cú pháp JS thú vị mới nhất để gán các thuộc tính với ý định và kỳ vọng thực tế của bạn, vì mọi thứ có thể dễ dàng trở nên tồi tệ nếu bạn cố gắng hãy thông minh trong việc gán các thuộc tính này .

Và đó là tất cả mọi người!

Điều rút ra duy nhất từ ​​bài đăng này có thể được tóm tắt như sau:

  • không sử dụng các phần kế thừa chưa hoạt động của ngôn ngữ, nếu bạn muốn tránh những bất ngờ hôm nay hoặc ngày mai, về cách chúng hoạt động với cú pháp mới
  • thích rõ ràng hơn (và không may là chậm hơn) Object.setPrototypeOfbất cứ khi nào bắt buộc phải đặt nguyên mẫu của một đối tượng theo cách thủ công, nhưng hãy sử dụng các lớp trong mọi trường hợp khác bất cứ khi nào có thể
  • xóa khỏi bộ nhớ của bạn bài đăng này hoặc rút gọn nó thành một câu ngắn như: “ Tôi không bao giờ nên sử dụng __proto__mã của mình ” và tiếp tục học những thứ mới lạ không làm rối trí não hoặc cảm xúc của bạn