Dynamically bind argument and default value to existing function in Javascript
开发者_JAVA技巧Let's suppose you have some function someFunc() already defined in javascript, that may or may not have its own argument set defined. Is it possible to write another function to add a required argument and set that argument to a default for someFunc()? Something like:
var someFunc = function(arg1, arg2 ...){ Do stuff...}
var addRequired = function(argName, argValue, fn) {
Add the required default arg to a function...
}
addRequired("x", 20, someFunc);
Now someFunc would be defined roughly like so:
someFunc = function(x, arg1, arg2...) {
x = 20;
Do stuff...
}
What I am really seeking is to not only bind a this value to a function (which I already know how to achieve), but also bind another object reference to that same function (the function not being known ahead of time, as a user will define it, but then the user's code has access to this second object reference for use in their own function). So in my simple example above, the "20" value will actually be an object reference.
Thanks for any help you can offer.
Like this:
function addParameter(func, argIndex, argValue) {
return function() {
arguments[argIndex] = argValue;
arguments.length = Math.max(arguments.length, argIndex);
return func.apply(this, arguments);
};
}
someFunc = function(x, arg1, arg2...) {
Do stuff...
}
someFunc = addParameter(someFunc, 0, someValue);
I believe I found an answer, though in the process, I came to realize that I don't really need to add an argument for my purpose, I just need to add the reference into the function. Anyway, for purposes of an answer that achieves what I originally thought I desired, I came up with:
var someFunc = function(arg1,arg2){document.write(x+'<br />'+arg1+'<br />'+arg2)};
var addRequired = function(argName, argValue, fn){
var funcString = String(fn)
var paramPattern = new RegExp ('^function\\s*\\([^\\)]*\\b'+argName+'\\b[^\\)]*\\)');
var alreadyExists= paramPattern.test(funcString);
if(!alreadyExists) {
var insertPoint1 = funcString.indexOf('(')+1;
var insertPoint2 = funcString.indexOf('{')+1;
var newFunc = funcString.slice(0,insertPoint1)+argName+',' +funcString.slice(insertPoint1, insertPoint2)+argName+' = '+argValue+';' +funcString.slice(insertPoint2);
return eval('fn = '+newFunc);
}
}
someFunc = addRequired('x', 20, someFunc);
someFunc(1,2,3);
Which tests to see if the arg already exists, and if not, outputs:
20
2
3
So it achieved the addition of an argument with the value desired. I don't know if this is the 'best' way of achieving it, but it worked.
Edited 7/9/10 to add this info:
I found the above had a 'bug' when I went to apply it to a different situation than my example above (I don't recall now what the bug was, that was a few weeks ago). I came up with something that did work. NOTE, the following does not do any kind of check to see if the argument already exists for the function passed in, and in fact, currently it expects a function that DOES NOT TAKE ARGUMENTS ITSELF (I am certain this could be rewritten to accommodate a function with arguments, similar to what I did above). Here is a simple layout of what I actually used:
var addRequired = function(thisObj, func) {
/*Here I write a string that contains additional functions to add to the
passed in function ('func' argument above). In this case, I just show
a simple addition function for the example.*/
var str = 'myAddedFunction = function(x, y) {return x+y}';
/*Here I am taking the string for that new function I want to add, and
appending the old function to it as a string after I have stripped it
of its 'function () {' at the beginning and its '}' at the end. NOTE:
If I did not care about adding a function, but just arguments, I would
have just assigned 'str' the value after the '+' sign below */
str = str + String(func).replace(/^function\s*\([^\)]*\)[\s\n]*{/, ' ').replace(/}$/, '');
/*Here I create a new function using the actual new Function declaration so
I can define my arguments, and using the new string I created that has
my new functionality in it along with the user supplied functionality*/
var newFunc = new Function('myArg1', 'myArg2', str);
/*Now I return an anonymous function that itself returns the new function
with the object that is supposed to be the 'this' of the new function
which was passed in as the 'thisObj' argument*/
return function() {return newFunc.apply(thisObj, arguments)};
}
The return value is assigned to the original passed in function, so:
var userFunc = function() { *do some stuff* }; //representation only
userFunc = addRequired(someObj, userFunc); //overwrite with new functionality
What this allows me to do is have the user write a function, knowing ahead of time that they will have access to the function I am supplying (the myAddedFunction
) as well as the parameters I am supplying (the myArg1
, myArg2
) within their function. This may seem really abstract, like "why would I ever need that," but for a project I am working on, I (and the user) need it, as I utilize the user's function (with my additions) to perform some operations for the user based off parameters I am supplying.
I forgot to mention, that for my purposes, I did not need to pass in the string that I was going to make into the new variables (it's always the same variables I am adding), but if I had, I would have done something like what was done in the first part of my post, where I passed in (probably an array) of strings to make into the argument values, and used those to build my newFunc
with.
精彩评论