Evil Genius 101: The Hidden Power of JavaScript Object prototype

New language features are often welcomed, but if they are working against the language nature… Huston, we have a problem!


To say the truth, you are a nice guy. You are showing that by writing excellent code to please your company, delivering stories on time, estimating truthfully and generally being a good officemate. But you know, maybe one day something in you will snap. Bad, repeatable tasks can change you slowly. You will go into passive-aggressive mode, and while at the first blink of an eye everything will be normal, in your mind the vision of overall chaos will emerge. You could take an axe and start chopping desks around, but that’s not like you. Too fast and too dirty. You are not only a nice guy, you are also kinda clever (evil genius is still a genius). Your vengeance will be long-term. You will start using Object.create somewhere inside your JavaScript code and start observing rising fear on the faces of your teammates when code start to behave unpredictably…

… or you just think “What a great tool!” and sincerely want to make everyone’s life easier and code more securely — the effect is the same. Chaos is proud of you, dear apprentice.

New ECMAScript, new features…

I probably exaggerated, but a story like that materialized in my mind during reading Mozilla Developers Network about a new features from ECMAScript 5.1. Those additions to Object prototype are powerful and… dangerous. Especially when working in teams where everybody sometimes needs to touch, but not everyone is an expert.

As data structures, Object Literals are quite likeable — easy to create, you can put something to in them simply any moment and they are mapped flawlessly on API calls — if you need to work with an endpoint which “cannot into JSON”, let me hug you with sympathy. Everything is easy, but sometimes hard to tame — every part of code could change inner state of object in any moment. To solve that problem, from the EcmaScript 5.1 (so, quite long ago I would say) JavaScript Object prototype contains a few really interesting helpers methods.

The first one was already mentioned Object.create. Instead of using rather skewed inheritance implementations in JS, it lets you create your new object on existing prototype in a clean way. Let’s do this with a basic one:

var firstObject = Object.create(Object.prototype, { 
  x:{
     value:”value x”
  });
}

It’s quite obvious that firstObject.x will print value x when called. In this form, it’s just a verbose version of normal literal definition.

… and new quirks

But we just saw a tip of iceberg. Our property can also have parameters different than value. Let’s have some fun with writable, and enumerable.

We can try to declare our property with writable set to false (which we already did — it’s default behavior).

var firstObject = Object.create(Object.prototype,{
x:{
value:"value x",
writable:false
});
}

It’s easy to predict what will happen there — our value cannot be changed. Cool feature, isn’t it ? At last we are able to make something durable while writing JavaScript. It would be handy, but there is one problem. Do you know what happens when you do something like this:

Nothing. Absolutely nothing. No value change, no error, no indication that something is wrong. JavaScript will silently continue executing instructions with the wrong value.

It can be quite easy to spot if code is all yours and you can easily find where your firstObject was defined in the first place. But if object like that will come from one of your dependencies and you have no deep knowledge about or control on, debugging can be an enlightening experience (trust me, been there, done that — I’m pointing at you, React.js). That is definitely something that is going to catch you for a longer time when you see it for the first time.

I can’t find my property anywhere!

That’s not all. Our property is also not enumerable by default. If we use popular iteration from Crockford’s JavaScript: Good Parts (IMHO one of the most obsolete books still suggested as “must read” for new developers):

var firstObject = Object.create(Object.prototype, {

x: {
value: “value x”,
enumerable: false
}
});
for (var property in firstObject) {
if (firstObject.hasOwnProperty(property)) {
console.log(property)
}
}

we will be startled — our x won’t be printed due to enumerable set to false. I would also call it unexpected. It also makes your property invisible in browsers JS REPL’s (like JSBin or Repl.it) while printing object — unfortunately, no tool is perfect.

Objects frozen with fear

But that’s not all. We can also easily seal and freeze our objects. The first one (with the use of Object.seal) doesn’t let you add any new properties. The second makes your object frozen, which means that also the value (or being more specific — reference. You can still change values of subproperties from frozen object property, which is another interesting place for sabotage) of any property cannot be changed.

Yes, you are right; if you try to do that, an error will show up. It wouldn’t be that bad, but the the worst thing is that we can do that in exactly any moment. For example, in code like that:

function nobodyExpectedFreezeThere(a){
Object.freeze(a);
var secondObject={
a: "value a"
}
}
youNotSuspectAnything(secondObject)
secondObject.a=”value a1"
secondObject.a // writes “value a”

I don’t need to add that nobodyExpectedFreezeThere can be some util function from one of your dependencies, somewhere deep in your callstack? And there will be no error, no info, no anything?

And these are not all the additions to Object prototype.You also have things like getters and setters, which can entirely change how your properties behave in the way transparent to the user.

Great power, great responsibility

I don’t want you to misunderstand me. It’s great that JavaScript adds new features known from strongly typed languages, like better encapsulation or accessors. But this language is already complicated and has too many quirks. There are places where using showed methods would definitely be beneficial. But everything comes with a price to pay — remember, you are fighting not only with possible state-changes errors. You are confronting years of habits of people who used literals as a substitution of namespaces and trashcans for everything that can be needed later. Even though presented language features are with us since June 2011, they were not described in the popular books like JavaScript: Good Part or Effective JavaScript and many JavaScript developers don’t have any knowledge of them.

And that’s a great field for unexpected and hard to catch errors.

To save a day!

But you are not defenseless. Fortunately, we have one superpower while fighting evil geniuses. Most of the upper problems will throw a proper errors if you use Strict Mode — real godsend for JavaScript developers. If you will ever decide to omit it on purpose, you are opening your application to the very weird behavior.

And remember that the faster you are informed that something is wrong , the faster you can react to potential issues. You can never know, maybe you are sitting with one of the evil geniuses without knowing it… or maybe one is sleeping deep in your heart and will one day wake up with a roar.

And once again: Strict Mode is your friend and ally. Use it whenever possible.

Originally published at www.schibsted.pl on March 31, 2015.