Creating and assigning the same object in JavaScript

Today I ran into an interesting quirk in JavaScript that caused me hours of investigation, and I thought I’d share it with you. The issue revolves around two methods on the JavaScript Object: create and assign.

You would use create to create a copy of an existing object. It does so by creating an object with the source object as its prototype. You can access all the source object’s properties from the new object, and they are all included when iterating over the object. For all intents and purposes, it is a copy of the source.

However, there are two cases when it is noticeably not the same. The first is hasOwnProperty. It is a common pattern (ever since prototype manipulation became a thing) when iterating over an object, to check that the property is owned by the object before using it.

for(var a in obj){
    if(obj.hasOwnProperty(a)){
        // do something with obj[a]
    }
}

If the object was created with Object.create, none of the source object’s properties will pass the test.

It is also a common pattern in libraries these days to use Object.assign on config options passed into the library. It is a really neat way to provide a default set of config, and guarantee the shape of the config object for the rest of your code.

let defaultConfig = { /* set some default config */ };
let config = Object.assign({}, defaultConfig, configPassedIn);

Unfortunately for us, this also falls prey to our issue. Object.assign will only assign properties that the object itself owns, not those of its prototype(s).

There isn’t much we can do about this, except avoid using Object.create for config, or anything you won’t have complete control over for the whole of its life.

Lesson learned.