Динамически привязывать аргумент и значение по умолчанию к существующей функции в Javascript - PullRequest
4 голосов
/ 17 июня 2010

Предположим, у вас уже есть некоторая функция someFunc () , уже определенная в javascript, которая может иметь или не иметь свой собственный набор аргументов. Можно ли написать другую функцию для добавления обязательного аргумента и установить для этого аргумента значение по умолчанию для someFunc () ? Что-то вроде:

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);

Теперь someFunc будет определен примерно так:

someFunc = function(x, arg1, arg2...) {
    x = 20;
    Do stuff...
}

Что я действительно ищу, так это не только привязка этого значения к функции (которую я уже знаю, как достичь), но также привязка другого объекта к той же функция (функция не известна заранее, так как пользователь определит ее, но затем код пользователя получит доступ к этой второй ссылке на объект для использования в своей собственной функции). Так что в моем простом примере выше значение «20» фактически будет ссылкой на объект.

Спасибо за любую помощь, которую вы можете предложить.

Ответы [ 2 ]

5 голосов
/ 17 июня 2010

Как это:

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);
1 голос
/ 18 июня 2010

Я думаю, что нашел ответ, хотя в процессе я понял, что мне не нужно добавлять аргумент для моей цели, мне просто нужно добавить ссылку в функцию. Во всяком случае, в целях ответа, который достигает того, что я первоначально думал, что я хотел, я придумал:

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);

Какой тест проверяет, существует ли arg, и если нет, выводит:

20
2
3

Таким образом, было достигнуто добавление аргумента с желаемым значением. Я не знаю, является ли это «лучшим» способом достижения этого, но это сработало.

Отредактировано 9/9/10, чтобы добавить эту информацию:

Я обнаружил, что вышеописанное имело «ошибку», когда я применил ее в ситуации, отличной от моего примера выше (сейчас я не помню, что это была за ошибка, которая была несколько недель назад). Я придумал что-то, что сработало. ПРИМЕЧАНИЕ: следующее не выполняет какой-либо проверки, чтобы увидеть, существует ли уже аргумент для переданной функции, и на самом деле, в настоящее время он ожидает функцию, которая НЕ БЕРЕТ СВОИХ АРГУМЕНТОВ (я уверен, что это можно переписать, чтобы приспособить функция с аргументами, аналогичными тому, что я делал выше). Вот простая схема того, что я на самом деле использовал:

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)};
}

Возвращаемое значение присваивается оригиналу, переданному в функции, поэтому:

var userFunc = function() { *do some stuff* }; //representation only
userFunc = addRequired(someObj, userFunc); //overwrite with new functionality

Это позволяет мне написать пользователю функцию, заранее зная, что у него будет доступ к функции, которую я предоставляю (myAddedFunction), а также к параметрам, которые я предоставляю (* 1020). *, myArg2) в пределах своей функции. Это может показаться очень абстрактным, например, «зачем мне это нужно», но для проекта, над которым я работаю, он (и пользователь) нужен, так как я использую функцию пользователя (с моими дополнениями) для выполнения некоторых операций для пользователь на основе параметров, которые я предоставляю.

Я забыл упомянуть, что для моих целей мне не нужно было передавать строку, которую я собирался сделать, в новые переменные (это всегда те же переменные, которые я добавляю), но если бы я это сделал, я бы сделал что-то вроде того, что было сделано в первой части моего поста, где я передал (вероятно, массив) строк для преобразования в значения аргумента и использовал их для построения моего newFunc с помощью.

...