Object#merge – Useful JavaScript Game Extensions 17

Yesterday I wrote about Object.extend, a useful method for building objects out of smaller pieces. Commenter Kieran posted a reply saying that it might be better as an Object#merge method. My initial reaction was an aversion to extending Object.prototype, so I went on a journey to figure out why I believed that.

Back in 2003, prototype.js extended Object.prototype with extra methods. There was a big outcry, “You’re breaking my [badly written] code with your library!!1”. Apparently it was common practice to use objects as hash tables and use for in iteration on them without using a check like hasOwnProperty. And jQuery didn’t exist then, and unit testing for JavaScript didn’t exist, or was never practiced, and there where thousands of badly written libraries that you could copy-paste into your app and watch it break because prototype.js extended Object.prototype.

So naturally there was a massive outcry Object.prototype is verboten, and continuing through to December 2009, Prototyping Object in Javascript breaks jQuery?. Though in the latter one the breakage was acknowledged as a bug in jQuery, the general consensus was that it was “bad practice” to extend Object.prototype, citing again for in loops primarily.

So the cautious thing to do is to never extend Object.prototype. This is most likely correct if you are distributing a library to millions of people who need to use it in diverse and hostile environments, aka the web. Are you delivering a library to millions of people who use it in diverse and hostile environments? No? Cool, continue reading then.

For my own code, that I run on my own site, I have quite a lot of control over it. I can choose to use external libraries or not, and patch them if they are using for in loops in some weird way. So I’m going to give it a shot and try extending Object.prototype.

Object.prototype.merge = function(source) {
  for(var key in source) {
    if(source.hasOwnProperty(key)) {
      this[key] = source[key];
    }
  }
 
  return this;
}
var BLT = {
  bacon: true,
  lettuce: true,
  tomato: true
};
 
var Reuben = {
  cornedBeef: true,
  russianDressing: true,
  saurkraut: true,
  swissCheese: true
};
 
var sandwich = {};
 
sandwich.merge(BLT);
sandwich.merge(Reuben);
sandwich.merge({
  name: "custom",
  price: 6
});
 
// each...? Never heard of it. (Don't worry, it's from the future).
sandwich.each(function(key, value) {
  console.log(key + " is " + value);
});
 
// bacon is true
// lettuce is true
// tomato is true
// cornedBeef is true
// russianDressing is true
// sauerkraut is true
// swissCheese is true
// name is custom
// price is 6

That doesn’t seem so bad… though if my past experience with JavaScript has taught me anything it’s that everything is likely to come back and bite me in the ass.

Extending Object.prototype provides a not-insignificant gain of clarity in the code. It also provides a potentially dangerous pitfall that can lead to trouble if used in some situations. I always think it’s a good practice to exchange real problems for hypothetical ones, so this is a trade-off I’m likely to make. I haven’t yet extended Object.prototype in a major JavaScript project yet, I guess I’m still a little gun-shy from having been burned so often by JS in the past. That said, I will definitely be trying it out and seeing for myself if the dangers are real or imagined.

2 thoughts on “Object#merge – Useful JavaScript Game Extensions 17

  1. Pingback: Object#each: Useful JavaScript Game Extension #18

  2. Pingback: Object#reverseMerge – Useful JavaScript Game Extensions #19

Leave a Reply

Your email address will not be published. Required fields are marked *