Tạo đối tượng JS bằng Object.create (null)?


150

Tôi biết rất nhiều cách để tạo các đối tượng JS nhưng tôi không biết cách Object.create(null)đó.

Câu hỏi:

nó có giống hệt như:

var p = {}

đấu với

var p2 = Object.create(null);

?

Câu trả lời:


199

Chúng không tương đương. {}.constructor.prototype == Object.prototypetrong khi Object.create(null)không thừa kế từ bất cứ thứ gì và do đó không có thuộc tính nào cả.

Nói cách khác: Theo mặc định, một đối tượng javascript kế thừa từ Object, trừ khi bạn rõ ràng tạo nó với null làm nguyên mẫu của nó, như : Object.create(null).

{}thay vào đó sẽ tương đương với Object.create(Object.prototype).


Trong Chrome Devtool, bạn có thể thấy rằng Object.create(null)không có thuộc __proto__tính {}.

nhập mô tả hình ảnh ở đây


99

Chúng chắc chắn không tương đương. Tôi đang viết câu trả lời này để giải thích đầy đủ hơn tại sao nó lại tạo ra sự khác biệt.

  1. var p = {};

    Tạo một đối tượng kế thừa các thuộc tính và phương thức từ đó Object.

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

    Tạo một đối tượng không kế thừa bất cứ thứ gì.

Nếu bạn đang sử dụng một đối tượng làm bản đồ và bạn tạo một đối tượng bằng phương pháp 1 ở trên, thì bạn phải hết sức cẩn thận khi thực hiện tra cứu trên bản đồ. Vì các thuộc tính và phương thức Objectđược kế thừa, mã của bạn có thể gặp trường hợp có các khóa trong bản đồ mà bạn không bao giờ chèn. Ví dụ: nếu bạn đã tra cứu toString, bạn sẽ tìm thấy một hàm, mặc dù bạn không bao giờ đặt giá trị đó ở đó. Bạn có thể làm việc xung quanh như thế này:

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

Lưu ý rằng việc gán một cái gì đó là tốt p.toString, nó sẽ đơn giản ghi đè toStringchức năng được kế thừa trên p.

Lưu ý rằng bạn không thể làm p.hasOwnProperty('toString')vì bạn có thể đã chèn khóa "hasOwnProperty" vào p, vì vậy chúng tôi buộc nó phải sử dụng triển khai Object.

Mặt khác, nếu bạn sử dụng phương pháp 2 ở trên, thì bạn sẽ không phải lo lắng về những thứ Objectxuất hiện trên bản đồ.

Bạn không thể kiểm tra sự tồn tại của một tài sản với cách đơn giản ifnhư sau:

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

Giá trị có thể là một chuỗi rỗng, có thể false, hoặc null, undefinedhoặc 0, hoặc NaN, v.v. Để kiểm tra xem một thuộc tính có tồn tại hay không, bạn vẫn sẽ cần sử dụng Object.prototype.hasOwnProperty.call(p, someKey).


6
Một cách khác đơn giản hơn để kiểm tra sự tồn tại của một tài sản là:if (someKey in p) {
mrcrowl

2
@mrcrowl Chỉ khi họ sử dụng Object.create(null). Tôi không muốn đưa ra các giả định như vậy, ngay cả khi bạn hoàn toàn đúng khi sử dụng nó Object.create(null), mã có thể thay đổi, đối tượng có thể được thay thế bằng một kế thừa Objecttại một số điểm. hasOwnPropertyluôn luôn làm việc
doug65536

1
Tôi cảm thấy cẩn thận về những thứ như thế này là không cần thiết. Tôi đánh giá cao câu trả lời của bạn nhưng tài liệu sẽ cung cấp cho bạn api cần thiết để làm việc với bất kỳ mã nào bạn đang làm việc. Nếu bạn đang lấy một số mã ngẫu nhiên từ github, thì bạn có thể phân tách nó và an toàn trước các cập nhật ít tài liệu hơn. Chưa kể {}là phổ biến hơn nhiều so với Object.create(null), nếu mã của bạn vô tình lấy một tài sản được thừa kế tại thời điểm này, bạn có thể có những lỗi lớn hơn để lo lắng. Tôi chỉ có thể xem mọi người sử dụng Object.create (null) như một tối ưu hóa nhỏ.
aaaaaa

Phủ định đôi !!p[key]hoạt động tốt với Object.create(null). Nhưng điều đó hasKey = (key, input) => Object.prototype.hasOwnProperty.call(input, key)cũng không tệ
andreid

> Lưu ý rằng bạn không thể thực hiện p.hasOwnProperty ('toString') vì bạn có thể đã chèn khóa "hasOwnProperty" vào p, vì vậy chúng tôi buộc nó phải sử dụng triển khai trong Object. Điều đó là không cần thiết. Trong trường hợp này, bạn không thể sử dụng bất kỳ phương thức nào pvì mọi phương thức đều có thể được chèn và do đó trở nên không an toàn.
xianshenglu

1

Tạo các đối tượng bằng cách sử dụng {}sẽ tạo ra một đối tượng có nguyên mẫu Object.prototypekế thừa các chức năng cơ bản từ Objectnguyên mẫu trong khi tạo các đối tượng bằng cách sử dụng Object.create(null)sẽ tạo ra một đối tượng trống có nguyên mẫu là null.


0

Nếu ai đó đang tìm kiếm để thực hiện Object.create(null), chỉ để biết làm thế nào nó hoạt động. Nó được viết bằng cách sử dụng __proto__không chuẩn và do đó, tôi không khuyên dùng nó .

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

Lưu ý : Tôi đã viết điều này, vì tò mò và nó chỉ được viết bằng các thuật ngữ đơn giản, ví dụ, tôi không chuyển các mô tả thuộc tính từ đối tượng thứ hai sang đối tượng trả về.


1
Lưu ý rằng kể từ khi phát hành ECMAScript vào mùa hè, __proto__giờ đây sẽ chính thức là một phần của ngôn ngữ.
Chiru

1
Tại sao -1trong arguments.length>0?arguments[0]:-1;?
happy_marmoset

@happy_marmoset phản hồi muộn, nhưng có vẻ như đó chỉ là một trình giữ chỗ không null để Objectnguyên mẫu được giữ lại nếu đối số đầu tiên không được đưa ra. Tên biến có thể tốt hơn rất nhiều ở đây.
Mike Hill

Ngoài ra, tham số thứ hai nên mô tả thuộc tính mô tả hơn là tính thực tế bản thân. Xem tài liệu tham khảo tại đây: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
Kẻ

0

Khi bạn tạo một Object bằng Object.create (null) có nghĩa là bạn đang tạo một Object không có nguyên mẫu. null ở đây có nghĩa là kết thúc chuỗi nguyên mẫu. Tuy nhiên, khi bạn tạo một đối tượng như {} Nguyên mẫu đối tượng sẽ được thêm vào. Do đó đây là hai đối tượng khác nhau, một đối tượng có nguyên mẫu khác không có nguyên mẫu. Hy vọng điều này sẽ giúp

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.