Before we go on, with common commonly used functions, we may refactor them to a utility library; then we can use it directly. In order to manage the namespace, let's start from the following skeleton.
(function(global) {All utility functions use XD as the namespace. It's just a plain JavaScript object where features will rest on. Utility functions may be properties of this object. The first one we add to it is an XD.trim function used to return a string copy, with leading and trailing whitespace omitted.
var XD = {
};
global.XD = XD;
})(this);
(function(global) {Then, XD.isArray and XD.isFunction is used to respectively determine if the argument passed is an array or a function.
var XD = {
trim: function(text) {
return (text || '').replace( /^(\\s|\\u00A0)+|(\\s|\\u00A0)+\$/g, '');
},
...
};
global.XD = XD;
})(this);
(function(global) {Here, we use the default implementation of the toString function of an Object instance to conform to the ECMAScript specification. After that, we define XD.each. Although interpreters, such as Rhino, allow an Array instance to use the forEach function, Internet Explorer doesn't provide one. And, the XD.each here is more general; it can iterate not only all index or values of an array or array-like object but also properties and values of a plain object.
var XD = {
...
isArray: function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
},
isFunction: function(obj) {
return Object.prototype.toString.call(obj) === '[object Function]';
},
...
};
global.XD = XD;
})(this);
(function(global) {The XD.each function accepts an object. If it doesn't own a length property, or it's a function, use for in to iterate it; or, use for with index. The first parameter of the callback function accepts the property value; the second parameter accepts the property name. If you want to interrupt the iteration, return false from the callback function.
var XD = {
...
each: function(obj, callback) {
var length = obj.length,
isObj = (length === undefined) || this.isFunction(obj);
if (isObj) {
for(var name in obj) {
if(callback.call(obj[name], obj[name], name) === false ) {
break;
}
}
}
else {
for(var i = 0, value = obj[0];
i < length && callback.call(obj[i], value, i) !== false;
value = obj[++i] ) {}
}
return obj;
},
...
};
global.XD = XD;
})(this);
In JavaScript, many objects are not Array instances, yet they own a length property and numeric properties. Sometimes, transforming these array-like objects into Array instances will get more convenience. So, we define an XD.makeArray function in our utility library.
(function(global) {The Array.prototype.slice function splits an array-like object according to their length property and numeric properties. Consider the object with a length property but without numeric properties, we filter out undefined elements.
var XD = {
...
makeArray: function(arrayLike) {
if(arrayLike.length != null) {
return Array.prototype.slice.call(arrayLike, 0)
.filter(function(ele) { return ele !== undefined; });
}
return [];
}
};
global.XD = XD;
})(this);
The code above is currently written in a file named gossip-0.1.js. Below is the total content.
(function(global) {
var XD = {
trim: function(text) {
return (text || '').replace( /^(\\s|\\u00A0)+|(\\s|\\u00A0)+\$/g, '');
},
isArray: function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
},
isFunction: function(obj) {
return Object.prototype.toString.call(obj) === '[object Function]';
},
each: function(obj, callback) {
var length = obj.length,
isObj = (length === undefined) || this.isFunction(obj);
if (isObj) {
for(var name in obj) {
if(callback.call(obj[name], obj[name], name) === false ) {
break;
}
}
}
else {
for(var i = 0, value = obj[0];
i < length && callback.call(obj[i], value, i) !== false;
value = obj[++i] ) {}
}
return obj;
},
makeArray: function(arrayLike) {
if(arrayLike.length != null) {
return Array.prototype.slice.call(arrayLike, 0)
.filter(function(ele) { return ele != undefined; });
}
return [];
}
};
global.XD = XD;
})(this);
Someday, if you want to write a utility function, you can add it to XD. For example, for some reason, you have being creating array-like objects frequently, you are considering write an arrayLike funciton; you may write the following code in your own js file.
(function(XD) {After including gossip-0.1.js and your js file, you may use XD.arrayLike as follows:
XD.arrayLike = function() {
var obj = { length : arguments.length };
XD.each(arguments, function(ele, i) {
obj[i] = ele;
});
return obj;
};
})(this.XD);
var obj = XD.arrayLike(1, 2, 3, 4);In Rhino Shell, the code will display 1 to 4.
XD.each(obj, function(element) {
print(element);
});