Criando objeto JS com Object.create (null)?

150

Conheço várias maneiras de criar objetos JS, mas não sabia qual Object.create(null)deles.

Questão:

é exatamente o mesmo que:

var p = {}

vs

var p2 = Object.create(null);

?

Royi Namir
fonte

Respostas:

199

Eles não são equivalentes. {}.constructor.prototype == Object.prototypeenquanto Object.create(null)não herda de nada e, portanto, não possui propriedades.

Em outras palavras: herda javascript objeto a de objeto por padrão, a menos que explicitamente criar-lo com nulo como seu protótipo, como: Object.create(null).

{}seria equivalente a Object.create(Object.prototype).


No Chrome Devtool, você pode ver que Object.create(null)não tem __proto__propriedade, enquanto o {}faz.

insira a descrição da imagem aqui

Peter Herdenborg
fonte
99

Definitivamente, eles não são equivalentes. Estou escrevendo esta resposta para explicar melhor por que isso faz a diferença.

  1. var p = {};

    Cria um objeto que herda as propriedades e métodos de Object.

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

    Cria um objeto que não herda nada.

Se você estiver usando um objeto como um mapa e criar um objeto usando o método 1 acima, precisará ter um cuidado extra ao fazer pesquisas no mapa. Como as propriedades e métodos de Objectsão herdados, seu código pode ser executado em um caso em que existem chaves no mapa que você nunca inseriu. Por exemplo, se você fizesse uma pesquisa toString, encontraria uma função, mesmo que nunca coloque esse valor lá. Você pode contornar isso assim:

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

Observe que não há problema em atribuir algo p.toString, ele simplesmente substituirá a toStringfunção herdada p.

Observe que você não pode simplesmente fazer isso p.hasOwnProperty('toString')porque pode ter inserido uma chave "hasOwnProperty" em p, portanto forçamos que ela use a implementação no Object.

Por outro lado, se você usar o método 2 acima, não precisará se preocupar com o fato de as coisas Objectaparecerem no mapa.

Você não pode verificar a existência de uma propriedade com um simples ifcomo este:

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

O valor pode ser uma sequência vazia, pode ser false, ou null, ou undefined, ou 0, ou NaN, etc. Para verificar se existe uma propriedade, você ainda precisará usar Object.prototype.hasOwnProperty.call(p, someKey).

doug65536
fonte
6
Uma alternativa mais simples para verificar a existência de uma propriedade é:if (someKey in p) {
mrcrowl
2
@mrcrowl Somente se eles usassem Object.create(null). Prefiro não fazer suposições como essa, mesmo que você estivesse absolutamente certo de que era usado Object.create(null), o código poderia mudar, o objeto poderia ser substituído por um que herda Objectem algum momento. hasOwnPropertysempre funciona.
doug65536
1
Sinto que tomar cuidado com algo assim deve ser desnecessário. Agradeço sua resposta, mas a documentação deve fornecer a API necessária para trabalhar com qualquer código com o qual você esteja trabalhando. Se você está pegando algum código aleatório do github, pode usá-lo e se proteger de atualizações menos documentadas. Sem mencionar, {}é muito mais prevalente que Object.create(null), se o seu código acidentalmente pegar uma propriedade herdada nesse momento, você provavelmente terá bugs muito maiores para se preocupar. Só consigo ver pessoas usando Object.create (null) como uma otimização menor.
aaaaaa 13/09
Negação dupla !!p[key]funciona bem com Object.create(null). Mas hasKey = (key, input) => Object.prototype.hasOwnProperty.call(input, key)também não é ruim
andreid 02/05/19
> Observe que você não pode simplesmente executar p.hasOwnProperty ('toString') porque você pode ter inserido uma chave "hasOwnProperty" em p, portanto forçamos a utilização da implementação em Object. Isso é desnecessário. Nesse caso, você não pode usar nenhum método pporque todos os métodos podem ser inseridos e, portanto, não se tornam seguros.
Xianshenglu 06/12/19
1

Criar objetos usando {}criará um objeto cujo protótipo é o Object.prototypeque herda as funções básicas do Objectprotótipo enquanto cria objetos usando Object.create(null)criará um objeto vazio cujo protótipo é nulo.

Praveen Kishor
fonte
0

Se alguém está procurando implementar Object.create(null), apenas para saber como funciona. É escrito usando o __proto__que não é padrão e, portanto, eu não o recomendo .

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

Nota : escrevi isso por curiosidade e é escrito apenas em termos simples, por exemplo, não estou transferindo os descritores de propriedade do segundo objeto para o objeto de retorno.

Aravind
fonte
1
Observe que a partir do lançamento do ECMAScript no verão, __proto__agora será oficialmente parte do idioma.
Chiru
1
Por que -1dentro arguments.length>0?arguments[0]:-1;?
22420 Happy
@happy_marmoset resposta tardia, mas parece que é apenas um espaço reservado não nulo para que o Objectprotótipo seja retido se o primeiro argumento não for fornecido. Nomes de variáveis ​​podem ser muito melhores aqui.
31317 Mike
Além disso, o segundo parâmetro deve descrever as propriedades descritores em vez dos próprios propriedades reais. Veja a referência aqui: developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Mike Hill
0

Quando você cria um Objeto com Object.create (null), isso significa que você está criando um Objeto sem protótipo. null aqui significa o fim da cadeia de protótipos. No entanto, quando você criar um objeto como {}, o protótipo de objeto será adicionado. Portanto, esses são dois objetos diferentes, um com protótipo e outro sem protótipo.

user13624607
fonte