การสร้างวัตถุ JS ด้วย Object.create (null)?


150

ฉันรู้ว่าหลายวิธีที่จะสร้างวัตถุ JS แต่ฉันไม่ทราบObject.create(null)'หนึ่ง

คำถาม:

มันเป็นเช่นเดียวกับ:

var p = {}

VS

var p2 = Object.create(null);

?

คำตอบ:


199

พวกเขาจะไม่เทียบเท่า {}.constructor.prototype == Object.prototypeในขณะที่Object.create(null)ไม่ได้รับมรดกจากอะไรและดังนั้นจึงไม่มีคุณสมบัติเลย

ในคำอื่น ๆ : การสืบทอดจาวาสคริปต์วัตถุจากวัตถุโดยค่าเริ่มต้นเว้นแต่ว่าคุณได้สร้างมันขึ้นมาด้วย null Object.create(null)เป็นต้นแบบของมันเช่น:

{}Object.create(Object.prototype)แทนจะเทียบเท่ากับ


ใน Chrome Devtool คุณจะเห็นว่าObject.create(null)ไม่มี__proto__คุณสมบัติในขณะ{}นั้น

ป้อนคำอธิบายรูปภาพที่นี่


99

พวกเขาไม่เทียบเท่ากันอย่างแน่นอน ฉันกำลังเขียนคำตอบนี้เพื่ออธิบายเพิ่มเติมอย่างเต็มที่ว่าทำไมจึงสร้างความแตกต่าง

  1. var p = {};

    Objectสร้างวัตถุที่สืบทอดคุณสมบัติและวิธีการจาก

  2. var p2 = Object.create(null);

    สร้างวัตถุที่ไม่สืบทอดสิ่งใด

หากคุณใช้วัตถุเป็นแผนที่และคุณสร้างวัตถุโดยใช้วิธีที่ 1 ด้านบนคุณต้องระมัดระวังเป็นพิเศษเมื่อทำการค้นหาในแผนที่ เนื่องจากคุณสมบัติและวิธีการจากObjectนั้นสืบทอดรหัสของคุณอาจทำงานในกรณีที่มีคีย์ในแผนที่ที่คุณไม่เคยใส่ ตัวอย่างเช่นหากคุณทำการค้นหาtoStringคุณจะพบฟังก์ชันแม้ว่าคุณจะไม่เคยใส่ค่านั้นลงไป คุณสามารถหลีกเลี่ยงสิ่งเหล่านี้ได้:

if (Object.prototype.hasOwnProperty.call(p, 'toString')) {
    // we actually inserted a 'toString' key into p
}

หมายเหตุว่ามันจะปรับให้บางสิ่งบางอย่างที่จะกำหนดp.toStringมันก็จะแทนที่ได้รับมรดกฟังก์ชั่นบนtoStringp

โปรดทราบว่าคุณไม่สามารถเพียงแค่ทำp.hasOwnProperty('toString')เพราะคุณอาจได้ใส่คีย์ "hasOwnProperty" ลงดังนั้นเราจึงบังคับให้ใช้ในการดำเนินงานpObject

ในทางกลับกันหากคุณใช้วิธีที่ 2 ด้านบนคุณจะไม่ต้องกังวลเกี่ยวกับสิ่งต่าง ๆ ที่จะObjectปรากฏบนแผนที่

คุณไม่สามารถตรวจสอบการมีอยู่ของอสังหาริมทรัพย์ด้วยวิธีifนี้ได้ง่ายๆ:

// Unreliable:
if (p[someKey]) {
    // ...
}

ค่าที่อาจจะเป็นสตริงว่างอาจจะมีfalseหรือnullหรือundefinedหรือ0หรือNaNฯลฯ Object.prototype.hasOwnProperty.call(p, someKey)เพื่อตรวจสอบว่าสถานที่ให้บริการที่มีอยู่ที่ทุกท่านยังคงต้องใช้


6
ทางเลือกที่ง่ายกว่าสำหรับการตรวจสอบการมีอยู่ของคุณสมบัติคือ:if (someKey in p) {
mrcrowl

2
@mrcrowl Object.create(null)เฉพาะในกรณีที่พวกเขาใช้ ฉันไม่ชอบที่จะตั้งสมมติฐานแบบนั้นแม้ว่าคุณจะถูกต้องแน่นอนว่ามันใช้Object.create(null)รหัสสามารถเปลี่ยนแปลงวัตถุสามารถถูกแทนที่ด้วยสิ่งที่สืบทอดมาObjectในบางจุด hasOwnPropertyทำงานได้เสมอ
doug65536

1
ฉันรู้สึกระมัดระวังเกี่ยวกับบางสิ่งเช่นนี้ไม่จำเป็น ฉันขอขอบคุณคำตอบของคุณ แต่เอกสารควรให้ API ที่จำเป็นในการทำงานกับรหัสที่คุณใช้งาน หากคุณกำลังหยิบโค้ดสุ่มจาก github คุณสามารถแยกมันและปลอดภัยจากการอัพเดทที่มีเอกสารน้อย ไม่พูดถึง{}เป็นที่แพร่หลายมากขึ้นกว่าObject.create(null)ที่ว่าถ้ารหัสของคุณคว้าทรัพย์สินที่สืบทอดมาโดยบังเอิญ ณ จุดนี้คุณอาจมีข้อผิดพลาดที่ใหญ่กว่าที่จะต้องกังวล ฉันสามารถเห็นคนที่ใช้ Object.create (null) เป็นการปรับให้เหมาะสมเล็กน้อย
aaaaaa

คู่ปฏิเสธการทำงานที่ดีกับ!!p[key] Object.create(null)แต่hasKey = (key, input) => Object.prototype.hasOwnProperty.call(input, key)ก็ไม่เลวเหมือนกัน
อังเดร

> โปรดทราบว่าคุณไม่สามารถทำ p.hasOwnProperty ('toString') ได้เนื่องจากคุณอาจใส่คีย์ "hasOwnProperty" ใน p ดังนั้นเราจึงบังคับให้ใช้การนำไปใช้ใน Object นั่นไม่จำเป็น ในกรณีนี้คุณไม่สามารถใช้วิธีการใด ๆpเพราะทุกวิธีสามารถแทรกได้และไม่ปลอดภัย
xianshenglu

1

การสร้างออบเจกต์โดยใช้{}จะสร้างออบเจกต์ที่ต้นแบบObject.prototypeซึ่งสืบทอดฟังก์ชันพื้นฐานจากObjectต้นแบบในขณะที่สร้างออบเจ็กต์โดยใช้Object.create(null)จะสร้างออบเจ็กต์ว่างที่มีต้นแบบเป็นโมฆะ


0

หากใครบางคนกำลังมองหาการใช้งานObject.create(null)เพียงแค่รู้วิธีการ มันเขียนไว้ใช้__proto__ซึ่งเป็นที่ไม่ได้มาตรฐานและด้วยเหตุนี้ผมไม่แนะนำให้มัน

function objectCreateMimic()
{
  /*optional parameters: prototype_object, own_properties*/
  var P = arguments.length>0?arguments[0]:-1;
  var Q = arguments.length>1?arguments[1]:null;
  var o = {};
  if(P!==null && typeof P === "object")
  {
    o.__proto__ = P;
  }
  else if(P===null)
  {
    o.__proto__ = null;
  }
  if(Q!==null && typeof Q === "object")
  {
   for(var key in Q)
   {
     o[key] = Q[key];
   }
  }
  return o;
}

หมายเหตุ : ฉันเขียนสิ่งนี้ออกมาจากความอยากรู้อยากเห็นและเขียนเป็นคำง่าย ๆ เท่านั้นเช่นฉันไม่ถ่ายโอนตัวบอกคุณสมบัติจากวัตถุที่สองไปยังวัตถุที่ส่งคืน


1
โปรดทราบว่าในช่วงฤดูร้อนของการเปิดตัว ECMAScript __proto__ตอนนี้จะเป็นส่วนหนึ่งของภาษาอย่างเป็นทางการ
Chiru

1
ทำไม-1ในarguments.length>0?arguments[0]:-1;?
happy_marmoset

@happy_marmoset ตอบกลับช้า แต่ดูเหมือนว่าเป็นเพียงตัวยึดตำแหน่งที่ไม่ใช่ค่า null เพื่อให้Objectต้นแบบถูกเก็บรักษาไว้หากไม่ได้รับอาร์กิวเมนต์แรก ชื่อตัวแปรอาจดีกว่ามากที่นี่
Mike Hill

นอกจากนี้พารามิเตอร์ตัวที่สองควรอธิบายคุณสมบัติตัวอธิบายมากกว่าคุณสมบัติจริงด้วยตนเอง ดูการอ้างอิงได้ที่นี่: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ......
Mike Hill

0

เมื่อคุณสร้างวัตถุที่มี Object.create (null) นั่นหมายความว่าคุณกำลังสร้างวัตถุที่ไม่มีต้นแบบ nullที่นี่หมายถึงจุดสิ้นสุดของเชนต้นแบบ อย่างไรก็ตามเมื่อคุณสร้างวัตถุเช่น {} วัตถุต้นแบบจะถูกเพิ่ม ดังนั้นสิ่งเหล่านี้จึงเป็นวัตถุสองแบบที่แตกต่างกันอย่างหนึ่งกับต้นแบบอีกชิ้นที่ไม่มีต้นแบบหวังว่านี่จะช่วยได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.