Créer un objet JS avec Object.create (null)?


150

Je connais beaucoup de façons de créer des objets JS mais je ne connaissais pas Object.create(null)celui de.

Question:

est-ce exactement la même chose que:

var p = {}

contre

var p2 = Object.create(null);

?

Réponses:


199

Ils ne sont pas équivalents. {}.constructor.prototype == Object.prototypewhile Object.create(null)n'hérite de rien et n'a donc aucune propriété.

En d' autres termes: un objet javascript hérite de l' objet par défaut, sauf si vous créez explicitement avec NULL comme son prototype, comme: Object.create(null).

{}serait plutôt équivalent à Object.create(Object.prototype).


Dans Chrome Devtool, vous pouvez voir que cela Object.create(null)n'a pas de __proto__propriété, alors que c'est le {}cas.

entrez la description de l'image ici


99

Ils ne sont certainement pas équivalents. J'écris cette réponse pour expliquer plus en détail pourquoi cela fait une différence.

  1. var p = {};

    Crée un objet qui hérite des propriétés et des méthodes de Object.

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

    Crée un objet qui n'hérite de rien.

Si vous utilisez un objet comme carte et que vous créez un objet à l'aide de la méthode 1 ci-dessus, vous devez faire très attention lorsque vous effectuez des recherches sur la carte. Étant donné que les propriétés et les méthodes de Objectsont héritées, votre code peut s'exécuter dans un cas où il y a des clés dans la carte que vous n'avez jamais insérées. Par exemple, si vous effectuez une recherche sur toString, vous trouverez une fonction, même si vous n'y mettez jamais cette valeur. Vous pouvez contourner cela comme ceci:

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

Notez que vous pouvez attribuer quelque chose à p.toString, cela remplacera simplement la toStringfonction héritée sur p.

Notez que vous ne pouvez pas le faire simplement p.hasOwnProperty('toString')parce que vous avez peut-être inséré une clé "hasOwnProperty" dans p, nous le forçons donc à utiliser l'implémentation dans Object.

D'un autre côté, si vous utilisez la méthode 2 ci-dessus, vous n'aurez pas à vous soucier de l' Objectapparition d'éléments sur la carte.

Vous ne pouvez pas vérifier l'existence d'une propriété avec un simple ifcomme celui-ci:

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

La valeur peut être une chaîne vide, peut être false, ou null, ou undefined, ou 0, ou NaN, etc. Pour vérifier si une propriété existe, vous devez toujours l'utiliser Object.prototype.hasOwnProperty.call(p, someKey).


6
Une alternative plus simple pour vérifier l'existence d'une propriété est:if (someKey in p) {
mrcrowl

2
@mrcrowl Uniquement s'ils ont utilisé Object.create(null). Je préfère ne pas faire d'hypothèses comme ça, même si vous aviez tout à fait raison de dire qu'il utilisait Object.create(null), le code pourrait changer, l'objet pourrait être remplacé par un qui hérite Objectà un moment donné. hasOwnPropertyfonctionne toujours.
doug65536

1
Je pense que faire attention à quelque chose comme ça ne devrait pas être nécessaire. J'apprécie votre réponse, mais la documentation devrait vous donner l'API nécessaire pour travailler avec le code avec lequel vous travaillez. Si vous récupérez du code aléatoire sur github, vous pouvez le bifurquer et être à l'abri des mises à jour moins documentées. Sans oublier qu'il {}est tellement plus répandu Object.create(null)que si votre code saisit accidentellement une propriété héritée à ce stade, vous avez probablement des bogues beaucoup plus importants à craindre. Je ne vois que des personnes utilisant Object.create (null) comme une optimisation mineure.
aaaaaa

La double négation !!p[key]fonctionne bien avec Object.create(null). Mais ce hasKey = (key, input) => Object.prototype.hasOwnProperty.call(input, key)n'est pas mal non plus
andreid

> Notez que vous ne pouvez pas simplement faire p.hasOwnProperty ('toString') parce que vous avez peut-être inséré une clé "hasOwnProperty" dans p, nous le forçons donc à utiliser l'implémentation dans Object. C'est inutile. Dans ce cas, vous ne pouvez utiliser aucune méthode pcar chaque méthode pourrait être insérée et ainsi devenir dangereuse.
xianshenglu

1

La création d'objets à l'aide de {}créera un objet dont le prototype Object.prototypehérite des fonctions de base du Objectprototype tandis que la création d'objets à l'aide de Object.create(null)créera un objet vide dont le prototype est nul.


0

Si quelqu'un cherche à mettre en œuvre Object.create(null), juste pour savoir comment cela fonctionne. Il est écrit en utilisant __proto__ce qui n'est pas standard et, par conséquent, je ne le recommande pas .

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

Remarque : j'ai écrit ceci, par curiosité, et il n'est écrit qu'en termes simples, par exemple, je ne transfère pas les descripteurs de propriété du deuxième objet à l'objet de retour.


1
Notez qu'à partir de la sortie d'ECMAScript cet été, __proto__fera désormais officiellement partie du langage.
Chiru

1
Pourquoi -1en arguments.length>0?arguments[0]:-1;?
happy_marmoset

@happy_marmoset réponse tardive, mais il semble que ce soit juste un espace réservé non nul afin que le Objectprototype soit conservé si le premier argument n'est pas donné. Les noms de variables pourraient être bien meilleurs ici.
Mike Hill

En outre, le deuxième paramètre doit décrire les descripteurs de propriété plutôt que les propriétés réelles elles-mêmes. Voir la référence ici: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Mike Hill

0

Lorsque vous créez un objet avec Object.create (null), cela signifie que vous créez un objet sans prototype. null signifie ici la fin de la chaîne de prototypes. Néanmoins, lorsque vous créez un objet comme {} Object prototype sera ajouté. Il s'agit donc de deux objets différents, l'un avec un prototype, l'autre sans prototype.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.