ข้อเท็จจริง JS __proto__ “สนุก”

Nov 26 2022
หากคุณติดตามฉันมานานพอ คุณรู้อยู่แล้วว่าฉันต่อต้าน __proto__ มากแค่ไหน และตั้งแต่นั้นมามันได้มาตรฐาน ECMAScript เมื่อนานมาแล้ว ก็ยังมีบางโอกาสที่ฉันพบว่าอย่างน้อยการใช้มันเพื่อสร้างแบรนด์วัตถุ ยอมรับได้: มองข้ามประสิทธิภาพ และโปรดทราบว่าฉันไม่ได้แนะนำให้ใช้ __proto__ แต่อย่างใด โพสต์นี้มีอยู่ด้วยเหตุผลอื่น วัตถุ.
ภาพถ่ายโดย Mark Williams บน Unsplash

หากคุณติดตามฉันมานานพอ คุณรู้อยู่แล้วว่าฉันต่อต้าน__proto__ฉันมากแค่ไหน และเนื่องจากมันได้มาตรฐาน ECMAScriptเมื่อนานมาแล้ว ก็ยังมีบางโอกาสที่ฉันพบว่าอย่างน้อยการใช้มันเพื่อสร้างแบรนด์ให้กับวัตถุที่ยอมรับได้ :

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

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

ใน Firefox __proto__ ทำคะแนนได้ดีกว่าคลาสใหม่

นอกเหนือจากประสิทธิภาพแล้ว และโปรดทราบว่าฉันไม่ได้แนะนำการใช้งาน แบบทั่วไป __proto__เลย โพสต์นี้มีอยู่ด้วยเหตุผลอื่น

Object.prototype.__proto__

ฉันค่อนข้างแน่ใจว่าทุกคนรู้ว่า __proto__ accessor ทำอะไรดังนั้นฉันอยากจะเสนอความท้าทายให้คุณ … และใช่ ทั้งหมดนี้เป็น JS ที่ถูกต้อง:

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

หากคุณยังไม่ได้เรียกใช้ตัวอย่างข้อมูลเหล่านี้ด้วยตัวเองเพื่อทราบคำตอบ เราช่วยคุณได้! ในความท้าทายแรก ผลลัพธ์จะเป็นfalse, true, trueและfalseอีกครั้ง และเหตุผลก็คือทั้งคู่{__proto__}และ{["__proto__"]}ถูกกำหนดให้เป็นคุณสมบัติของตัวเองในขณะที่การกำหนดผ่านไวยากรณ์ โดยไม่ได้ใช้คุณสมบัติไวยากรณ์พิเศษ แม้ว่าจะใส่เครื่องหมายอัญประกาศอยู่ก็ตาม จริง ๆ แล้วผ่านตัวObject.prototype.__proto__เข้าถึง

ในทางกลับกัน ในความท้าทายที่สอง (ทั้งหมดtrue) มันไม่สำคัญว่าเราจะเข้าถึง__proto__โดยตรงหรือเป็น["__proto__"]ดังนั้นโดยพื้นฐานแล้วจะไม่มีสมมาตรเป็นศูนย์ในวิธีที่เราสามารถเรียกใช้__proto__setter จากวิธีที่เราสามารถเรียกใช้__proto__getter เพียงครั้งเดียว เป็นทรัพย์สินของตัวเองหรือประตูมรดกเวทมนตร์

… และไม่ใช่แค่ __proto__

__xxx__ฉันไม่ได้ตรวจสอบตัวเอง แต่ฉันเชื่อว่า accessor พิเศษแบบดั้งเดิมทุกตัว ต้องทนทุกข์ทรมานกับ __proto__คำสาปเดียวกัน ดังนั้นโปรดใช้ความระมัดระวังในการผสมไวยากรณ์ JS สุดเจ๋งล่าสุดเพื่อกำหนดคุณสมบัติด้วยความตั้งใจและความคาดหวังที่แท้จริงของคุณ เนื่องจากสิ่งต่าง ๆ อาจกลายเป็นเรื่องกล้วย ๆ หากคุณพยายาม ฉลาดในการกำหนดคุณสมบัติเหล่านี้

และนั่นคือทั้งหมด!

ข้อสรุปเดียวจากโพสต์นี้น่าจะสรุปได้ดังนี้:

  • อย่าใช้ส่วนที่ล้าสมัยแต่ยังใช้งานได้ของภาษา หากคุณต้องการหลีกเลี่ยงความประหลาดใจในวันนี้หรือพรุ่งนี้ เกี่ยวกับลักษณะการทำงานของสิ่งเหล่านี้ด้วยไวยากรณ์ใหม่
  • ชอบความชัดเจน (และน่าเสียดายที่ช้ากว่า) Object.setPrototypeOfเมื่อใดก็ตามที่จำเป็นต้องมีการตั้งค่าต้นแบบของวัตถุด้วยตนเองอย่างเคร่งครัด แต่ให้ใช้คลาสในทุก ๆ กรณีทุกครั้งที่เป็นไปได้
  • ลบโพสต์นี้ออกจากความทรงจำของคุณหรือย่อให้เป็นประโยคสั้นๆ เช่น “ ฉันไม่ควรใช้__proto__ในโค้ดของฉัน ” และเรียนรู้สิ่งใหม่ๆ แฟนซีที่ไม่ทำให้สมองหรือความรู้สึกของคุณยุ่งเหยิง