One thing that I started working on last year, but unfortunately never released, was a version of jPaq which provides the ability to pick whether or not prototypal functions are created. The reason I started working on this was to somewhat satisfy the complaints of those who feel that native prototypes should not be modified. You may wonder how a JavaScript library could be written with the option of adding the corresponding prototypal functions. The following is an example of such a library:
// EXAMPLE JAVASCRIPT LIBRARY USING PROTO
(function(slice, undefined) {
// Function that adds the specified function as a prototypal function to the
// specified class with the specified name.
function proto(theClass, fnName, fn) {
return theClass.prototype[fnName] = function() {
return fn.apply(undefined, [this].concat(slice.call(arguments, 0)));
};
}
// Array of prototypal functions to add.
var protosToAdd = [
[String, 'lstrip', trimLeft],
[String, 'rstrip', trimRight],
[String, 'strip', trim]
];
// Trim functions to be added to jPaq.
function trimLeft(s) {
return s.replace(/^\s+/, '');
}
function trimRight(s) {
return s.replace(/\s+$/, '');
}
function trim(s) {
return trimLeft(trimRight(s));
}
// Defining the library (in this case jPaq) in the global namespace. The
// library comes built-in with the trim functions but if the protoAll
// function is called the trim function will be prototypalized.
jPaq = {
proto: proto,
trimLeft: trimLeft,
trimRight: trimRight,
trim: trim,
protoAll: function() {
for (var i = protosToAdd.length; i--;) {
proto.apply(0, protosToAdd[i]);
}
}
};
})([].slice);
If you were to run the above code block, you would end up defining the scaled-down jPaq
library object. On the other hand, at the point no prototypes were actually modified. So, how does this code actually help us? The power is in the proto
function which is called by the protoAll
function. If you are a developer who doesn’t mind a native prototype being updated (String.prototype
in this case), you could execute the following:
jPaq.protoAll();
At this point, executing jPaq.protoAll
is the equivalent of the following:
jPaq.proto(String, 'lstrip', jPaq.trimLeft);
jPaq.proto(String, 'rstrip', jPaq.trimRight);
jPaq.proto(String, 'strip', jPaq.trim);
Either one of the above code blocks results in definitions for String.prototype.lstrip
, String.prototype.rstrip
, and String.prototype.strip
. These definitions use the corresponding trim functions defined in the first code block but the only difference is that the context object is passed as the first (and in this case only) argument to the corresponding function. As you may have guessed, this can be very useful, assuming that you design your non-prototypal functions to take the first argument that would be passed in as the context object in a prototypal environment.
Even though this proto
function is currently something that I have defined for an example version of jPaq, this could be really be used for almost any JavaScript library. Therefore, if you are creating your own JS library and want to distribute it with the option to add prototypal functions, the following is the function snippet that you can add:
var proto = (function(slice, undefined) {
return function(theClass, fnName, fn) {
return theClass.prototype[fnName] = function() {
return fn.apply(undefined, [this].concat(slice.call(arguments, 0)));
};
};
})([].slice);
I hope this helps. š