Создание объекта 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, описанный выше, то вам нужно быть очень осторожным при поиске на карте. Поскольку свойства и методы from 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).

doug65536
источник
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) в качестве незначительной оптимизации.
аааааа
Двойное отрицание !!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__теперь официально будет частью языка.
Чиру
1
Почему -1в arguments.length>0?arguments[0]:-1;?
happy_marmoset
@happy_marmoset поздний ответ, но похоже, что это просто ненулевой заполнитель, поэтому Objectпрототип сохраняется, если не указан первый аргумент. Имена переменных могли бы быть намного лучше здесь.
Майк Хилл
Кроме того, второй параметр должен описывать дескрипторы свойств, а не сами фактические свойства. См. Ссылку здесь: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Майк Хилл,
0

Когда вы создаете объект с Object.create (null), это означает, что вы создаете объект без прототипа. Здесь null означает конец цепочки прототипов. Тем не менее, когда вы создаете объект наподобие {}, будет добавлен прототип объекта. Следовательно, это два разных объекта, один с прототипом, другой без прототипа. Надеюсь, это поможет

user13624607
источник