Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it bad practice to use Object.create(null) versus {}?

Tags:

javascript

By not inheriting from Object.prototype with Object.create(null), your object no longer has the methods on the object prototype. So the obvious question is, what are the methods on that prototype, and do you need them?

The methods are:

  • hasOwnProperty
  • isPrototypeOf
  • propertyIsEnumerable
  • toString/toLocaleString
  • valueOf

hasOwnProperty seems kind of useless because if there is no prototype, all properties on the created object are by definition own properties. However, it's conceivable that some library or other piece of code might be iterating over the object's properties with for...in and using the if (o.hasOwnProperty(key)) idiom. It is probably too much to hope for that it would use the more correct Object.prototype.hasOwnProperty.call(o, key). Such code would now fail. Or, you might be creating a sub-object with the created object as prototype, and be interested in knowing whether a property is an own property of the sub-object or comes from the prototype.

isPrototypeOf might or might not be useful if you plan to use the created object as the prototype for other objects, and for some reason want to check if the created object is or is not in the prototype chain of such other objects.

propertyIsEnumerable would not be used too much, but then again, we cannot predict what other code in the system is going to do. If it tries to call this method on the created object, or any objects created with it as a prototype, it will fail.

The same holds for toString. Who knows who might try to call it on your created object? For instance, some libraries might try to test a value's type by doing a toString and seeing if the result is "[object Object]". Hopefully they do a safe Object.prototype.toString.call(o), but...

valueOf is rarely used explicitly, but is called by the engine if it needs to coerce the object to a primitive. If it is missing, the code could break:

> o2 = Object.create(null)
> o2 + 1
Uncaught TypeError: Cannot convert object to primitive value

Of course, there is also the possibility that someone has added methods to the Object prototype, in which case Object.create({}) will pick them up. Probably you don't want or need them. On the other hand, they are most likely harmless.

Given all of this, it seems that Object.create(null) should be limited to specific cases where it is provable that none of the above issues could occur. For instance, where the object is never even passed outside its local context, or is never going to be used as a prototype for another object. Even in that case, the performance advantage will be very small, or even zero.

I'm interested to know if others use Object.create(null)? Is it SOP in JavaScript land?

I don't think it could be called SOP.


To the best of my knowledge,

{} == Object.create(Object.prototype);

Also,

To me (Only me) I feel like Object.create(null) gives you more clarity that your object is not going to inherit anything i.e its (purely) empty map.


Also,

In both cases you can use object as dictionary.


Also,

It depend upto you what you supposed to do with your object.


When,

  1. {} == Object.create(Object.prototype); // you inherit all object properties

  2. o = Object.create(null); // you do not inherit anything. this is completely blank object.

If you are using an object as a map, and you create an object using method 1 above, then you have to be extra careful when doing lookups in the map. Because the properties and methods from Object are inherited, your code may run into a case where there are keys in the map that you never inserted.

For example, if you did a lookup on toString, you would find a function, even though you never put that value there. You can work around that like this:

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

Note that you can't just do object.hasOwnProperty('toString') because you may have inserted a key "hasOwnProperty" into object, so we force it to use the implementation in Object.

On the other hand, if you use method 2 above, then you won't have to worry about things from Object appearing in the map.

You can't check for the existence of a property with a simple if like this:

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

SO,

To use object as a Map most of the people on planet use

Object.create(null) // no overhead to worry about inherited properties.

In all other cases you simply use,

var myObject = {}

MDN - Object.create

MSDN - Object.create


From the book You Don't Know JS: this & Object Prototypes:

Object.create(null) is similar to {}, but without the delegation to Object.prototype, so it's "more empty" than just {}.

Object.create(null) is a good practice in case that you need a DMZ (empty object for explicit binding: apply & call, bind).


I'd like to refer to the Mozilla doc about Objects and maps compared here to give Map a chance as a better practice nowaday.

Objects are similar to Maps in that both let you set keys to values, retrieve those values, delete keys, and detect whether something is stored at a key. Because of this (and because there were no built-in alternatives), Objects have been used as Maps historically; however, there are important differences that make using a Map preferable in certain cases:

  • The keys of an Object are Strings and Symbols, whereas they can be any value for a Map, including functions, objects, and any primitive.
  • You can get the size of a Map easily with the size property, while the number of properties in an Object must be determined manually.
  • A Map is an iterable and can thus be directly iterated, whereas iterating over an Object requires obtaining its keys in some fashion and iterating over them.
  • An Object has a prototype, so there are default keys in the map that could collide with your keys if you're not careful. As of ES5 this can be bypassed by using map = Object.create(null), but this is seldom done.
  • A Map may perform better in scenarios involving frequent addition and removal of key pairs.