我正在学习函数式编程和node.js,在使用Function.prototype.apply
和.bind
时遇到了这个奇怪的问题。
function Spy(target, method) {
var obj = {count: 0};
var original = target[method]
target[method] = function (){//no specified arguments
obj.count++
original.apply(this, arguments)//only arguments property passed
}
return obj;
}
module.exports = Spy
此代码有效,它成功监视target.method
。
//same code here
target[method] = function (args){//args specified
obj.count++
original.apply(this, args)//and passed here
}
//same code here
但是,这段代码没有。它会显示一条错误消息:TypeError: CreateListFromArrayLike called on non-object
。
然后最大的惊喜是,这种方法完美无缺。
//same code here
target[method] = function (args){
obj.count++
original.bind(this, args)
}
//same code here
那么为什么我会收到此错误?是因为函数参数不一定是对象吗?或者是因为apply有比bind更严格的描述?
答案 0 :(得分:1)
bind
的调用方式与call
的调用方式相同,即使它们执行的操作非常不同。
如果您真的想以这种方式使用bind
。您可以使用扩展运算符(ES2015)将参数“数组”扩展为单个参数:
original.bind(null, ...args);
这会将original
函数与数组值绑定为单独的参数。
答案 1 :(得分:1)
在此版本中:
target[method] = function (args){//args specified
obj.count++
original.apply(this, args)//and passed here
}
这里你没有拿走所有的参数,只是一个名为args
的参数。由于apply
需要一个类似于对象的数组,因此它不能使用args
,因为它只是传递给原始目标的第一个参数。
您可以将其更改为:
target[method] = function (arg){ //only one argument specified
obj.count++
original.apply(this,[arg]) //one argument passed here
}
现在它可以工作,但你只能监视一个参数函数。使用call
会更好,因为你只有一个额外的参数:
target[method] = function (arg){ //only one argument specified
obj.count++
original.call(this,arg) //one argument passed here
}
现在bind
是一种完全不同的动物。它partial applies函数,从而返回函数。想象一下,你需要发送一个不带参数的回调,但是调用一个带有一些参数的函数。您会看到如下代码:
var self = this;
return function() {
self.method(a, b);
}
好。 bind
为您做到了这一点:
return this.method.bind(this, a, b);
当调用这些返回函数中的任何一个时,同样的情况发生。使用参数method
和a
调用方法b
。因此,在函数上调用bind
会返回该函数的部分应用版本,而不会像call
或apply
那样调用它。