Javascript更改函数参数

时间:2011-11-26 13:24:04

标签: javascript function metaprogramming arguments

我正在尝试在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 个答案:

答案 0 :(得分:2)

正如德尔南在评论中所说,你想要做的似乎是“重命名”函数本地的变量。就像他说的那样,这是不可能的(也是有充分理由的!你能想象调试吗?maaan ......)

无论如何,我不确切地知道为什么你想要它,但是Javascript是一种灵活的语言,你可能会使用一个更理智的方法来接近。很难确切知道你想要达到的目标,但也许这些信息可能会让你走上正轨:

  • 调用时传递给函数的参数在名为arguments的变量中引用。

    function f() {
      console.log(arguments);
    }
    f(); // []
    f(1, 2); // [1, 2]
    
  • 您可以使用.apply调用具有任意参数列表的函数,this是函数原型的一个方法。它需要2个参数。第一个是函数调用中的f.apply(null, []); // [] f.apply(null, [1, 2, 3]); [1, 2, 3] 对象,第二个是参数数组。

    function f() {
        console.log.apply(console, arguments);
    }
    

在你的情况下应用这个,也许这就是你所追求的:

{{1}}

答案 1 :(得分:1)

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

}

答案 2 :(得分:1)

我有一个更简单的解决方案,类似于那些正在寻找的人接受的答案。适用于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');

在我的解决方案中,不需要数组但你可以编辑它,我的函数只需要用逗号分隔的参数名称。

答案 3 :(得分:0)

你可以使用.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); 

你在寻找吗?

答案 4 :(得分:0)

我找到了一个仅适用于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);

这也可以概括。

[编辑] 这也适用于其他浏览器,内存让我失望 - 某些浏览器中的评论// /**/被丢弃。

答案 5 :(得分:0)

如前所述,你不能按你想要的方式去做,你正在打破词汇范围。 但是,这里有一个极简主义版本的实现方式(应该做很多改进!)。唯一需要的是你的函数在参数中有命名参数。

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