Створення об'єкта JS за допомогою Object.create (null)?


150

Я знаю багато способів створення JS-об'єктів, але я не знав Object.create(null).

Питання:

це точно так само, як:

var p = {}

проти

var p2 = Object.create(null);

?

Відповіді:


199

Вони не рівноцінні. {}.constructor.prototype == Object.prototypeпри цьому Object.create(null)не успадковує ні від чого і, отже, зовсім не має властивостей.

Іншими словами: об'єкт Javascript успадковує від об'єкта за замовчуванням, якщо ви явно не створювати його з нулем в якості прототипу, як: 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, це просто перекриє спадкову toStringфункцію p.

Зауважте, що ви не можете просто зробити це, p.hasOwnProperty('toString')тому що, можливо, ви вставили в нього ключ "hasOwnProperty" p, тому ми змушуємо його використовувати реалізацію в Object.

З іншого боку, якщо ви використовуєте метод 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
Я відчуваю, що бути обережним щодо чогось такого, що має бути зайвим. Я вдячний за вашу відповідь, але документація повинна надати вам потрібні для роботи з будь-яким кодом, з яким ви працюєте. Якщо ви захоплюєте якийсь випадковий код з github, ви можете розщедрити його і бути в безпеці від менш задокументованих оновлень. Не кажучи {}вже про те, що набагато більше поширення, ніж те Object.create(null), що якщо ваш код випадково захопить успадковану властивість у цей момент, ви, швидше за все, маєте проблеми з більшими помилками. Я бачу лише людей, які використовують Object.create (null) як незначну оптимізацію.
aaaaaa

Подвійне заперечення !!p[key]добре працює Object.create(null). Але hasKey = (key, input) => Object.prototype.hasOwnProperty.call(input, key)теж непогано
andreid

> Зауважте, що ви не можете просто зробити 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__тепер офіційно буде частиною мови.
Чіру

1
Чому -1в arguments.length>0?arguments[0]:-1;?
happy_marmoset

@happy_marmoset запізніла відповідь, але схоже, що це просто ненульовий заповнювач, щоб Objectпрототип зберігався, якщо перший аргумент не наводиться. Імена змінних тут можуть бути набагато кращими.
Майк Хілл

Також другий параметр повинен описувати дескриптори властивостей, а не самі фактичні властивості. Дивіться посилання тут: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Майк Гілл

0

Коли ви створюєте Object з Object.create (null), це означає, що ви створюєте Об'єкт без прототипу. null тут означає кінець ланцюга прототипу. Тим не менш, коли ви створите такий об'єкт, як {} прототип об'єкта буде додано. Отже, це два різних об'єкти, один з прототипом, інший без прототипу

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.