从头开始创建.invoke().为什么函数工作,但方法返回未定义



我正在为一所基于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的函数。例如(来自Mocha测试套件):

var reverse = function(){
  return this.split('').reverse().join('');
};
var reversedStrings = _.invoke(['dog', 'cat'], reverse);
reseversedStrings = "['god', tac']; //YAY!!

然而,当它涉及到传递一个方法,如toUpperCase,我得到错误消息:"TypeError: undefined不是一个函数"。任何建议,感谢!

EDIT:发现失败的测试:

var upperCasedStrings = _.invoke(['dog', 'cat'], 'toUpperCase');
expect(upperCasedStrings).to.eql(['DOG', 'CAT']);
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);
        });
  };

然而,当它涉及到传递一个方法,如toUpperCase,我得到错误消息:"TypeError: undefined is not a function"

嗯,你不是在传递一个"方法"。关于如何传递绑定函数,请参阅@elclarns的答案。

你传递的是一个属性名,这是一个字符串-当functionOrKey是字符串'toUpperCase'时,它没有apply方法。您需要检查该参数的类型,并采取相应的行动。当它是一个字符串时,你会想要使用

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

map回调。

顺便说一句,你的args参数不应该是一个数组,而应该从动态的arguments对象构建。如果您想"作弊"(或查看完整的解决方案),请查看下划线的注释源代码。

我不确定我完全理解你的问题,但也许它可以更简单。如果您想调用一个方法,并为数组中的每一项调用它,您可以简单地使用内置的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']

我认为这解决了你的特定问题,但invoke不转发任何额外的参数到它调用的函数,按下划线文档。在这种情况下,您可以尝试使用到目前为止获得的内容加上上述帮助器,并捕获任何附加参数。

最新更新