A common operation in JavaScript is to replace an object method with a new one while still calling the original method. This is often done like this:
var originalMethod = obj.method;
obj.method = function(arg) {
// call original method
originalMethod.call(this, arg);
// do my stuff new stuff
}
I’d like to create a utility function for a specific object method that handles the chaining part so that the user doesn’t need to be concerned about it. One option is to use the above design, in which each added function is wrapped in a new function that calls the previous one. Another option is to create an array of functions and make the object method just iterate over the array, calling each function in turn.
function addXyzMethod1(fn) {
if (obj.method) {
var previousMethod = obj.method;
obj.method = function(value) {
value = previousMethod.call(this, value);
return fn.call(this, value);
};
} else {
obj.method = fn;
}
}
function addXyzMethod2(fn) {
if (obj._methodList) {
obj._methodList.push(fn);
} else if (obj.method) {
obj._methodList = [obj.method, fn];
obj.method = function(value) {
for (var i = 0, n = obj._methodList.length; i < n; i++) {
value = obj._methodList[i].call(this, value);
}
return value;
};
} else {
obj.method = fn;
}
}
At this point, I can’t decide which method to use since I feel the trade-offs of each are about even. So my question here is: Which of these method is better (more natural, or accepted, or quicker) or is there another method that improves on both of these?
3
This question is quite similar, or at least comes down to a similar question here: https://stackoverflow.com/questions/660337
Reading the favored answer there, I would recommend you to stick with addXyzMethod1 if you know that you do not have to overwrite the function so often that you are running into the dangers of a stack overflow.
If you want an alternative solution (which would be desirable in my opinion), a better understanding on what you are trying to do exactly would be helpful. I have not required this technique in a long time and from my experience this is bad practice in most cases. There are design patters which help you avoid this situation. E.g. use composition. Have an object representing a collection of functions (can be a simple array of functions) and inject that one into your object via its constructor and store it as a member. Then use it in that method you originally wanted to replace. The collection you injected, you can still add and remove functions from it. This would be kind of similar to your addXyzMethod2 just without having that global util function and without the need to overwrite your object’s original method.
1
What you are trying to do is a JavaScript version of call super, which is described as a code smell by Martin Fowler.
I would suggest instead that you either
- Contain the “super” object instead of inheriting from it.
-
Use template method, such as below
templateMethod = function () { baseMethod(); if (overrideMethod) { overrideMethod(); } };
Other objects would call templateMethod. The overrideMethod is where child objects would have their code.
1