从头开始创建.invoke()。为什么函数工作但方法返回undefined?

时间:2014-07-19 00:54:12

标签: javascript function methods underscore.js

我正在为基于JavaScript的编程学校做前期工作而且我遇到了问题。该 赋值是从头开始重写一些underscore.js方法,这样我们就知道它们是如何工作的,而不是盲目地依赖它们。 我的_.invoke会传递函数引用,但不传递方法名称。

这是原始问题:

// Calls the method named by functionOrKey on each value in the list.
// Note: you will nead to learn a bit about .apply to complete this.

_.invoke = function(collection, functionOrKey, args) {
};

到目前为止,我的解决方案是使用_.map()我之前写的(通过了自己的测试):

_.invoke = function(collection, functionOrKey, args) { return _.map(collection, function(value) { return functionOrKey.apply(value, args); }); };

我的解决方案支持传递functionOrKey的函数。例如(来自摩卡测试套件):

var reverse = function(){
  return this.split('').reverse().join('');
};

var reversedStrings = _.invoke(['dog', 'cat'], reverse);

reseversedStrings = "['god', tac']; //YAY!!

但是,当涉及传递方法时,例如toUpperCase,我收到错误消息:" TypeError:undefined不是函数"。任何建议表示赞赏!

编辑:找到失败的测试:

var upperCasedStrings = _.invoke(['dog', 'cat'], 'toUpperCase');

expect(upperCasedStrings).to.eql(['DOG', 'CAT']);

3 个答案:

答案 0 :(得分:2)

My solution would be:
_.invoke = function(collection, functionOrKey, args) {
//invoke when provided a method name
        if(typeof functionOrKey === 'string'){
          return _.map(collection, function(val){
            return val[functionOrKey](args);
          });
        }
//invoke when provided a function reference
        return _.map(collection, function(val){
          return functionOrKey.apply(val, args);
        });
  };

答案 1 :(得分:1)

我不确定我是否完全理解你的问题,但也许它可以更简单。如果你想调用一个方法并为数组中的每个项调用它,你可以像这样简单地使用内置map

var invoke = Function.bind.bind(Function.call)

var reverse = function() {
  return this.split('').reverse().join('')
}

var result = ['dog', 'cat'].map(invoke(reverse)) //=> ['god', 'tac']

您也可以使用内置方法:

['dog', 'cat'].map(invoke(''.toUpperCase)) //=> ['DOG', 'CAT']

我认为这解决了您的特定问题,但根据Underscore文档,invoke不会向其调用的函数转发任何其他参数。在这种情况下,您可以尝试使用您迄今为止所获得的内容以及上述帮助程序,并捕获任何其他参数。

答案 2 :(得分:1)

  

但是,当涉及传递方法时,例如toUpperCase,我收到错误消息:“TypeError:undefined不是函数”

嗯,你没有传递“方法”。请参阅@elclarns的答案,了解如何传递绑定函数。

您传递的是属性名称,这是一个字符串 - 当functionOrKey是字符串'toUpperCase'时,它没有apply method。您需要检查type of该参数,并采取相应措施。当它是一个字符串时,你会想要使用

return value[key].apply(value, args);

map回调中。

顺便说一下,您的args参数不应该是数组,而应该是从动态arguments object构建的。如果您想“作弊”(或查看完整解决方案),请查看annotated source code of Underscore