What does MooTools' Function.prototype.overloadSetter() do?

javascript, mootools

Solution

overloadSetter

`overloadSetter`, together with `overloadGetter`, are two function decorator methods. The `overloadSetter` function is used to transform functions that have the signature `fn(key, value)` to functions that could accept object arguments, ie: `fn({key: value})`.

In order to do this, `overloadSetter` must wrap the original function. This wrapper function has the signature `fn(a, b)` which is a shortcut for `fn(key, value)`. This effectively becomes the new overloaded version of the original function.

First thing this overloaded function does is check whether the passed `key` argument (`a`) is of the string type or not. If it's not a string, the function assumes that we're passing an object. So it iterates over each key-value pair in the object and applies the original function to it. If it's a string, on the other hand, it simply applies the function to the values of the `a` and `b` arguments.

Example

To illustrate, let's say we have the following function:

var fnOrig = function(key, value){
    console.log(key + ': ' + value); 
};

var fnOver = fnOrig.overloadSetter();

fnOver('fruit', 'banana');
fnOver({'fruit': 'banana', 'vegetable': 'carrot'});

In the first invocation, the `fnOver` function is invoked with two arguments, a key and a value. When the function checks the type of the `a` argument value, it'll see that it is a string. Therefore, it will simply invoke the original `fnOrig` function: `fnOrig.call(this, 'fruit', 'banana')`. Our console output is `'fruit: banana'`.

For the second invocation, the `fnOver` function is invoked with an object argument. Since we passed an object instead of a string, `fnOver` will iterate through the members of this object and invoke the `fnOrig` function for each one of them. Thus, `fnOrig` will be invoked twice in this case: `fnOrig.call(this, 'fruit', 'banana')` and `fnOrig.call(this, 'vegetable', 'carrot')`. Our console output is `'fruit: banana'` and `'vegetable: carrot'`.

Extras

Inside the wrapper function, you'll see that there's an check for the value of `usePlural`. This is an argument for the `overloadSetter` method itself. If you set this value to `true`, the new function will treat all arguments as object. This means that even if you pass a string key argument, it will still be processed as an object.

The other thing, the `enumerables` code that preludes the actual method declaration, is there because it fixes an issue with some browsers wherein the native `Object` methods are not enumerated in `for/in` loops even if the object itself implements its own version of it.

Problem

I'm looking through the MooTools source to try and understand its `.implement()` and `.extend()` utilities. The definition of each refers to a function defined like this: ``` var enumerables = true; for (var i in {toString: 1}) enumerables = null; if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor']; Function.prototype.overloadSetter = function(usePlural){ var self = this; return function(a, b){ if (a == null) return this; if (usePlural || typeof a != 'string'){ for (var k in a) self.call(this, k, a[k]); if (enumerables) for (var i = enumerables.length; i--;){ k = enumerables[i]; if (a.hasOwnProperty(k)) self.call(this, k, a[k]); } } else { self.call(this, a, b); } return this; }; }; ``` However, I am having a tough time understanding what it does. Can you explain how this function works and what it does?

Original source