实现Underscore库invoke方法遇异常,求原理性提示
Underscore简化版invoke方法实现疑问
已实现的简化版each方法(通过所有测试)
_.each = function (collection, iteratee, context) { let keys = Object.keys(collection); if (Array.isArray(collection)) { for (let i=0; i<keys.length; i++) { iteratee.call(context, collection[keys[i]], i, collection); } } else { for (let i=0; i<keys.length; i++) { iteratee.call(context, collection[keys[i]], keys[i], collection); } } return collection; };
invoke方法需求说明
// _.invoke(collection, methodName, *arguments) // Returns an array with the results of calling the method indicated by methodName on each value in the collection. // Any extra arguments passed to invoke will be forwarded on to the method invocation.
三次实现尝试及问题
尝试1:parseInt正常工作,但join报错
function invoke1 (collection, methodName) { let resArray = []; _.each(collection, el => resArray.push(methodName(el))); return resArray; } console.log(invoke1(['1','2','3'], parseInt)); // [123] console.log(invoke1([['a','b','c'], ['d','e','f']], Array.prototype.join)); // Uncaught TypeError: Cannot convert undefined or null to object - expected ['a,b,c', 'd,e,f']
尝试2:join正常工作,但parseInt返回NaN
function invoke2 (collection, methodName) { let resArray = []; _.each(collection, el => resArray.push(methodName.apply(el))); return resArray; } console.log(invoke2(['1','2','3'], parseInt)); // [NaN, NaN, NaN] - expected [123] console.log(invoke2([['a','b','c'], ['d','e','f']], Array.prototype.join)); // ['a,b,c', 'd,e,f']
尝试3:尝试转发参数,但均报错
function invoke3 (collection, methodName, ...arg) { let resArray = []; _.each(collection, el => resArray.push(methodName.apply(el, ...arg))); return resArray; } console.log(invoke3(['1','2','3'], parseInt)); // [NaN, NaN, NaN] - expected [123] console.log(invoke3([['a','b','c'], ['d','e','f']], Array.prototype.join, '')); // Uncaught TypeError: CreateListFromArrayLike called on non-object - expected ['abc', 'def']
注:已查看相关讨论,但本次需求中methodName并非字符串,暂未采用字符串方案,希望获得原理性提示而非直接答案,以便自行解决问题。
原理性提示(无直接答案)
- 核心关注两个点:函数的调用上下文(this指向) 和 函数的参数传递规则
- 普通函数(如
parseInt)的调用上下文不影响功能,但参数数量、顺序严格固定;原型方法(如Array.prototype.join)的调用上下文必须是对应类型的实例,否则会触发类型错误 - 回忆
call/apply的双重作用:既可以改变函数的this指向,也能传递参数,注意apply的第二个参数必须是数组或类数组结构 - 思考遍历集合时,每个元素的角色:调用目标方法时,哪些元素是方法的上下文,哪些是方法的参数?
- 额外参数的转发逻辑:
invoke接收的*arguments需要正确传递给目标方法,注意参数的拼接顺序——目标方法本身的参数和转发参数的优先级、顺序关系
内容的提问来源于stack exchange,提问作者nimbus4so
相关产品推荐
相关产品推荐

