Javascript изменить аргументы функции - PullRequest
1 голос
/ 26 ноября 2011

Я пытаюсь изменить аргументы функции в javascript.

f = function(){
    console.log(a,b,c);
};

SetArgumentList( f, ["a", "b", "c"] );

f(1,2,3);
// should print "1 2 3"

// [edit]
// alternatively SetArgumentList could also work like
f = SetArgumentList( f, ["a", "b", "c"] );

Есть ли какой-нибудь надежный способ сделать это?


Где мне это нужно? ...в основном я пытаюсь добавить проверенные функции типа:

Object.prototype.method = function( name, typedef, func ){ ... }

function Thing(){};

Thing.method("log", 
    { arr: Array, str: String }, 
    function(){
        console.log(arr, str);
    });

t = new Thing();
t.log([1,2,3], "ok");
t.log("err", "ok"); // <-- causes an exception

// I know I can do this way
Thing.method("log", 
    [Array, String], 
    function(arr, str){
        console.log(arr, str);
    });
// but that's harder to read

ПРИМЕЧАНИЕ!Я знаю, как выполнять проверку типов, но не конструкцию новой функции.

Ответы [ 6 ]

2 голосов
/ 26 ноября 2011

Как сказал Делнан в комментариях, похоже, что вы пытаетесь «переименовать» переменные, локальные для функции.Как он сказал, это невозможно (и не без причины! Можете ли вы представить, что отладка этого? Maaan ...)

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

  • Аргументы, которые передаются функции при вызове время указывается в переменной с именем arguments.

    function f() {
      console.log(arguments);
    }
    f(); // []
    f(1, 2); // [1, 2]
    
  • Вы можете вызвать функцию с произвольным списком аргументов, используя .apply, который является методом дляФункция-прототип.Требуется 2 параметра.Первый - это объект, который будет this внутри вызова функции, а второй - массив аргументов.

    f.apply(null, []); // []
    f.apply(null, [1, 2, 3]); [1, 2, 3]
    

Применяя это в вашей ситуации, возможно, это то, чтоВы после:

function f() {
    console.log.apply(console, arguments);
}
1 голос
/ 26 августа 2013

У меня есть более простое решение, подобное принятому ответу для любого, кто ищет.Работает в Chrome, Firefox, Safari, IE7 +

Решение

function SetArgList(fn, args) {

   var fnbody = fn.toString().replace(
         /^\s*function\s*[\$_a-zA-Z0-9]+\(.*\)\s*\{/, //BEWARE, removes original arguments
         ''
      ).replace(
        /\s*\}\s*$/,
        ''
      );

   return new Function(args, fnbody) 

}

Как использовать

Просто переопределите исходную функцию, как это, используя SetArgList:

function main() {
   alert(hello);
   alert(world);
}

main = SetArgList(main, 'hello,world');

main('hello', 'world');

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

1 голос
/ 26 ноября 2011

Проверено в IE7,8,9, Opera, Chrome, Firefox и Safari. Использует evil в фоновом режиме, но Я не вижу другого пути, если вы должны переименовать аргументы.

(function(){
var decompileRE = /function\s*\([\s\S]*?\)\s*\{([\s\S]*)/,
    lastBrace = /\}[^}]*$/;

    window.SetArgumentList = function( fn, argNames ) {
    var match

        if( !( match = fn.toString().match( decompileRE ) ) ) {
        return fn;
        }

    argNames.push( match[1].replace( lastBrace, "" ) );


    return Function.apply( null, argNames );
    };

})()

f = function(){
    console.log(a,b,c);
};

f = SetArgumentList( f, ["a","b","c"] );

console.log(f);

Регистрирует это во всех браузерах, упомянутых выше:

function anonymous(a,b,c) {

    console.log(a,b,c);

}
0 голосов
/ 26 ноября 2011

Как уже говорилось ранее, вы не можете делать это так, как хотите, вы нарушаете лексическую область видимости.Однако здесь есть вариант минимализма того, как вы можете его реализовать (нужно сделать много улучшений!).Единственное, что требуется, это то, что ваша функция имеет именованный параметр в аргументах.

function getType( el ) {
    // TODO
    return "";
}

function addMethod( obj, name, typedef, func ) {
    var argumentsLength = typedef.length;

    obj[ name ] = function() {
        var len = arguments.length, i = 0;

        if( argumentsLength != len )
        {
            throw new TypeError( "Wrong number of arguments for method " + name );
        }

        for( i = 0; i < len; i++ )
        {
            // TODO better type checking
            if( getType( arguments[i] ) != getType( typedef[i] ) )
            {
                throw new TypeError( "Wrong type for arguments number " + i + " for method " + name );
            }
        }

        return func.apply( obj, arguments );

    };
};


var o = {};

addMethod( o, "log", [Array, String], function( arr, str ) {
      // arguments MUST be explicitly declared above
      console.log( arr, str );
});
o.log( ["a"], "b" ); // OK
o.log( "a", "b" ); // TypeError
o.log( ["a"], "b", "c" ); // TypeError
0 голосов
/ 26 ноября 2011

Я нашел решение, которое работает только в браузерах webkit:

f = function(){ console.log(a,b,c); };
fx = eval(
    f.toString().replace(
        /^function [^\(]*\(\)/,
        "var __temp = function (a,b,c)") 
        + "; __temp");
fx(1,2,3);

Это также можно обобщить.

[edit] Это работает и для других браузеров, память подводит меня- комментарии // /**/ в некоторых браузерах отбрасываются.

0 голосов
/ 26 ноября 2011

вы можете использовать .apply: у меня это работает:

 f = function(a,b,c){ 
    console.log(a,b,c); 
}; 
var args = ["a", "b", "c"];  
f.apply(this, args); //print "abc"

используя аргументы:

f = function(){ 
    for(var key in arguments) {
        console.log(arguments[key]);
    }
}; 
var args = ["a", "b", "c"];  
f.apply(this, args); 

это то, что вы ищете?

...