Real World JavaScript Part 3
Array Direct Assignment
If you have wandered through UnderscoreJS source code, you will come across array direct assignment. It uses a nice trick of assigning the value to index represented by the length of the array. In this way the values are added to the end of the array without much effort. This is handy if you are not keeping the latest index pointer to an array. This may be said as calculated direct array assignment. Its counter part, the direct array assignment, if possible, will be the speediest array assignment in modern browsers. Direct array assignment offers speed advantage over the push method of the array.
_.map = _.collect = function(obj, iterator, context) {
var results = [];
if (obj == null) return results;
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
each(obj, function(value, index, list) {
results[results.length] = iterator.call(context, value, index, list);
});
return results;
};
Closure
The once function in UnderscoreJS exemplifies a typical closure.
_.once = function(func) {
var ran = false, memo;
return function() {
if (ran) return memo;
ran = true;
memo = func.apply(this, arguments);
func = null;
return memo;
};
};
The inner function will have access to the variables defined in the outer function. In the case of once, the inner function will have access to the variables ran and memo in addition to the outer function arguments. once method returns a function and when that function is called for the first time run variable will be set to true and the return value of the original function argument will be stored in memo variable. On subsequent calls, the run variable will be true and hence the function will not be executed but the original value stored in memo will be returned.
Constructor as type conversion tool
Wrapping the primitive objects using constructors is a practice that should be avoided. These constructors for primitive objects have a different role to perform – type conversion.
var f = new Boolean(false); // never wrap primitives
if(f){
console.log("This is going to blow up");
}
var piAsString = "3.14";
var piAsNumber = Number(piAsString); // Now you have a number
When number constructor (for that matter any constructor for primitive objects) is used as function, it will type convert the passed value to the corresponding primitive value.
Number("56") // 56
Number("56.67") // 56.67
Number() // 0
Number("") // 0
Number("1.2em") // NaN
parseFloat("1.2em") // 1.2
The type conversion using Number constructor will fail if the string passed does not represent a proper number. We can resort to parseInt and parseDouble to fine tune the type conversion process.
Object.create as inheritance helper
NodeJS has this piece of code for inheritance through help from Object.create. method.
exports.inherits = function(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
The inherits method in NodeJS does not wire up the constructor chains, instead it stores the constructor of the class inheriting from in a property called super_. This is convenient as our derived class can call the base class constructor through the super_ function call.
exports.inherits = function(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
Next, the prototype of the derived class is set to an object created from the base class constructor through the Object.create function. Although setting an object as the prototype will wire up the inheritance chain, it will also reset the constructor of the derived type to the constructor of base type. Object.create takes a second parameter of property descriptor object. Through this property decriptor the constructor value is set to the derived one. By default the property will not be writable or configurable. writable and configurable are set to true to make the constructor a regular value property.