JavaScript code... Don't really know what is happening here...
extend(obj, id) {
obj.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
id: id
});
};
})(obj.toObject);
}
This is the formatted code.
function extend(obj, id) {
obj.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {id: id});
};
})(obj.toObject);
}
Now lets simplify it..
Core method
fabric.util.object.extend(toObject.call(this), {id: id}); //some fabric lib specific method
Now,
function extend(obj, id) {
obj.toObject = (somefunction(toObject))(obj.toObject);
}
An IIFE expression which executes when obj.toObject is initiated.obj.toObject object is passed to somefunction()
Now this IIFE is returning an closure.
return fabric.util.object.extend(toObject.call(this), {id: id});.
So basically your function will assigntoObject function to any object passed to extend
fabric.util.object.extend is the same as Object.assign, which kind of makes the code cognitively simpler to understand.
Aside from that, it looks like it masks to old obj.toObject function, which is assumed to exist and return an object prior to calling extend(obj, someId), with another function called toObject, which calls to old toObject, which returns some object, that assigned the properties found in the second parameter object, which is just id, with the value id that was passed to extend.
When you call extend with some object that doesn't contain a toObject function, it throws a TypeError: Cannot read property 'call' of undefined at Object.obj.toObject.toObject
extend function is adding a method called toObject on the obj object that is passed in, which is immediately invoked (IIFE) and in turn presumably "extends" it by adding a special fabric.util.object. Just a guess...

see here fabricjs.com/fabric-intro-part-3
Aakash Mallik
S/W Engineer @ Samsung R&D Delhi
Ibrahim Tanyalcin
{intrst:"Scnc&Art",msc:"admin@MutaFrame",strive:"Experiment&Learn",loves:"ES5",hates:"bandwagon",lang:"Javascript",twttr:"@ibrhmTanyalcin"}
This is called monkey patching. Although I don't recommend to go over the board with this, I'll start from a simpler example. Let's assume you want to change console.log of the browser, then you do:
console.log = (function(consoleLog){ return function(a){ consoleLog(a+"_HaHa") } }(console.log)); console.log("hoho") //hoho_HaHaThe idea of a monkey patch is to:
Moving from the example you have given, I will create a similar demonstration (it can be written much shorter but just to keep resemblance to your original example):
//PREPARATION CODE var obj = {a:0}, obj2 = {b:-1}, fabric = {util:{object:obj}}; obj.toObject = function(){this.a++}; function extend(obj, id) { console.log("called"); obj2.b++; obj && (obj.toObject = (function(toObject) { return function() { return fabric.util.object.extend(toObject.call(this), {id: id}); }; })(obj.toObject)); } obj.extend = extend //CALL EXTEND ONCE extend(obj,"x") //id doesnt matter here //NOW CALL obj.toObject() to increment both a and b obj.toObject(); obj.a //1 obj2.b //1So we have modified the original toObject method to do something else without modifying what it originally did.
Once last word about iief and monkey patches is that if you are using them in your daily routines for lazily computing values or to get values that will be available at some point during runtime it is OK.
But if you are constantly using monkey patches to modify existing behavior of many predefined objects you are getting yourself into a ever tangling cat-mouse game. Duration of the game usually depends on the how well you remember what have you done in the past.
It is akin to playing with fire, though it can actually be useful and fun, unless you don't know when to stop.