0

说我有这个功能:

function doSomething(uno, dos, tres) {
    // do something
}

和这个对象:

{
    dos: 'foo',
    tres: 'bar',
    uno: 'baz'
}

doSomething给定这个映射,我该如何调用?我尝试使用apply,但似乎apply必须采用列表而不是对象。

4

5 回答 5

3

.您可以使用下面给出的方法引用上面给出的对象中的每个属性。

doSomething(obj.uno, obj.dos, obj.tres)
于 2013-06-05T00:31:29.653 回答
1

Function.apply只能用于将类数组对象1应用于函数调用。没有等效于 Python 的“关键字参数扩展”,这必须手动完成:

var opts = {
    dos: 'foo',
    tres: 'bar',
    uno: 'baz'
}
doSomething(opts.uno, opts.dos, opts.tres)

如果我们从一个类似数组的对象开始:

var arr = ['baz', 'foo', 'bar']
doSomething.apply(window, arr)

或者将两者放在一起(以便可以更早地处理参数序列的组合):

var arr = [opts.uno, opts.dos, opts.tres]
doSomething.apply(window, arr)

虽然可能(使用非混淆代码)使用2来提取参数名称,进行一些解析,然后编写一些代码来“应用”一个通用对象(或构造一个然后应用的数组),但这是ECMAScript 规范不直接支持。Function.toString


1类数组对象是具有length名为 和属性的对象0..length-1。(旧版本的FF有一个错误,但已经修复了很长时间。)

2规范的措辞(“函数的依赖于实现的表示被返回。这种表示具有 FunctionDeclaration 的语法。”)使我相信符合 ES5 的实现应该产生可用于此目的的输出 - 但是,这可能会因实现而异,我在实践中没有探索过这种用法。

于 2013-06-05T00:32:03.570 回答
1

您可以尝试使用:

function doSomething() {
   for (var i = 0, l = arguments.length; i<l; i++) {
      //dosomething
      console.log(arguments[i]);
   }
}

obj=['foo', 'bar', 'baz'];
doSomething.apply(null, obj);

Apply 接受数组作为第二个参数,但如果您坚持使用 object,您可以轻松将此对象转换为 Array,然后将其与 apply 一起使用。

function objectToArray(obj) {
   var arr = [];
   for (field in obj) 
      arr.push(field);
   return arr;
}
于 2013-06-05T00:44:40.447 回答
0

你可以这样做:

Function.prototype.applyNamed = function (g, argArr) {
    var self = this;    
    var argNames = self.toString().match(/function\s+\w*\s*\((.*?)\)/)[1].split(/\s*,\s*/);
    var applyArgs = [];
    for(var i=0; i<argNames.length; i++){        
        applyArgs.push(argArr[argNames[i]]);        
    }
    self.apply(self, applyArgs);
}

function doSomething(uno, dos, tres) {    
    console.log('uno = ' + uno);
    console.log('dos = ' + dos);
    console.log('tres = ' + tres);
}

var namedArgs = {
    dos: 'foo',
    tres: 'bar',
    uno: 'baz'
};

doSomething.applyNamed(this, namedArgs);

应该打印:

uno = baz  
dos = foo  
tres = bar

演示信用

于 2013-06-05T01:17:16.860 回答
0

好吧,如果你真的想要,你实际上可以使用命名参数调用一个方法,但它需要解析函数的字符串表示。你是否应该使用这种技术是有争议的,但你会这样做:

function doSomething(uno, dos, tres) {
    // do something
}

var arguments = {
    dos: 'foo',
    tres: 'bar',
    uno: 'baz'
}

function callFunction(fn, namedArguments) {
    var orderedArguments = [];
    var parameterRegExp = /\(([\s\w\$,]*)\)/;

    parameterRegExp.exec(fn.toString())[1].replace(/\s/g, '').split(',').forEach( function(parameterName) {
        orderedArguments.push(namedArguments[parameterName]);
    });

    return fn.apply(this, orderedArguments);
}

callFunction(doSomething, arguments);
于 2013-06-05T01:17:39.727 回答