¿Crear objeto JS con Object.create (nulo)?

150

Conozco muchas formas de crear objetos JS pero no sabía cuál era Object.create(null).

Pregunta:

¿Es exactamente lo mismo que:

var p = {}

vs

var p2 = Object.create(null);

?

Royi Namir
fuente

Respuestas:

199

No son equivalentes. {}.constructor.prototype == Object.prototypewhile Object.create(null)no hereda de nada y, por lo tanto, no tiene propiedades en absoluto.

En otras palabras: JavaScript Object hereda un objeto de forma predeterminada, a menos que se crea explícitamente con null como su prototipo, como: Object.create(null).

{}en cambio sería equivalente a Object.create(Object.prototype).


En Chrome Devtool puede ver que Object.create(null)no tiene __proto__propiedad, mientras que {}sí.

ingrese la descripción de la imagen aquí

Peter Herdenborg
fuente
99

Definitivamente no son equivalentes. Estoy escribiendo esta respuesta para explicar más completamente por qué hace la diferencia.

  1. var p = {};

    Crea un objeto que hereda las propiedades y métodos de Object.

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

    Crea un objeto que no hereda nada.

Si está utilizando un objeto como mapa, y crea un objeto utilizando el método 1 anterior, debe tener mucho cuidado al realizar búsquedas en el mapa. Debido a que las propiedades y métodos de Objectse heredan, su código puede encontrarse con un caso en el que hay claves en el mapa que nunca insertó. Por ejemplo, si realiza una búsqueda toString, encontrará una función, aunque nunca ponga ese valor allí. Puedes solucionarlo así:

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

Tenga en cuenta que está bien asignar algo p.toString, simplemente anulará la toStringfunción heredada p.

Tenga en cuenta que no puede hacerlo simplemente p.hasOwnProperty('toString')porque puede haber insertado una clave "hasOwnProperty" p, por lo que lo forzamos a usar la implementación en Object.

Por otro lado, si usa el método 2 anterior, no tendrá que preocuparse de que Objectaparezcan cosas en el mapa.

No puede verificar la existencia de una propiedad con un simple ifcomo este:

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

El valor podría ser una cadena vacía, podría ser false, o null, o undefined, 0o NaN, etc. Para verificar si existe alguna propiedad, aún necesitaría usarla Object.prototype.hasOwnProperty.call(p, someKey).

doug65536
fuente
66
Una alternativa más simple para la comprobación de la existencia de una propiedad es:if (someKey in p) {
mrcrowl
2
@mrcrowl Solo si lo usaban Object.create(null). Prefiero no hacer suposiciones como esa, incluso si tuviera toda la razón de que lo usara Object.create(null), el código podría cambiar, el objeto podría reemplazarse por uno que herede Objecten algún momento. hasOwnPropertysiempre funciona
doug65536
1
Siento que tener cuidado con algo como esto debería ser innecesario. Agradezco su respuesta, pero la documentación debería proporcionarle la API necesaria para trabajar con cualquier código con el que esté trabajando. Si está obteniendo algún código aleatorio de github, puede bifurcarlo y estar a salvo de actualizaciones menos documentadas. Sin mencionar que {}es mucho más frecuente que Object.create(null), si su código toma accidentalmente una propiedad heredada en este punto, es probable que tenga que preocuparse de errores mucho más grandes. Solo puedo ver personas que usan Object.create (nulo) como una optimización menor.
aaaaaa
La doble negación !!p[key]funciona bien con Object.create(null). Pero hasKey = (key, input) => Object.prototype.hasOwnProperty.call(input, key)tampoco está mal
andreid
> Tenga en cuenta que no puede simplemente hacer p.hasOwnProperty ('toString') porque puede haber insertado una clave "hasOwnProperty" en p, por lo que lo forzamos a usar la implementación en Object. Eso es innecesario. En este caso, no puede usar ningún método pporque cada método podría insertarse y, por lo tanto, no ser seguro.
xianshenglu
1

La creación de objetos mediante el uso {}creará un objeto cuyo prototipo es el Object.prototypeque hereda las funciones básicas del Objectprototipo, mientras que la creación de objetos mediante el uso Object.create(null)creará un objeto vacío cuyo prototipo es nulo.

Praveen Kishor
fuente
0

Si alguien está buscando implementar Object.create(null), solo para saber cómo funciona. Está escrito usando lo __proto__que no es estándar y, por lo tanto, no lo recomiendo .

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 : Escribí esto, por curiosidad, y solo está escrito en términos simples, por ejemplo, no estoy transfiriendo los descriptores de propiedad del segundo objeto al objeto de retorno.

Aravind
fuente
1
Tenga en cuenta que a partir del lanzamiento de ECMAScript en verano, __proto__ahora será oficialmente parte del lenguaje.
Chiru
1
¿Por qué -1en arguments.length>0?arguments[0]:-1;?
happy_marmoset
@happy_marmoset respuesta tardía, pero parece que es solo un marcador de posición no nulo para que el Objectprototipo se conserve si no se da el primer argumento. Los nombres de las variables podrían ser mucho mejores aquí.
Mike Hill
Además, el segundo parámetro debe describir los descriptores de propiedad en lugar de las propiedades en sí mismas. Ver referencia aquí: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Mike Hill
0

Cuando crea un Objeto con Object.create (nulo) eso significa que está creando un Objeto sin prototipo. nulo aquí significa el final de la cadena del prototipo. Sin embargo, cuando cree un objeto como {} se agregará un prototipo de objeto. Por lo tanto, estos son dos objetos diferentes, uno con prototipo y otro sin prototipo. Espero que esto ayude

usuario13624607
fuente