函数参数不一定是对象吗?

时间:2016-08-20 21:32:56

标签: javascript functional-programming

我正在学习函数式编程和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更严格的描述?

2 个答案:

答案 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);

当调用这些返回函数中的任何一个时,同样的情况发生。使用参数methoda调用方法b。因此,在函数上调用bind会返回该函数的部分应用版本,而不会像callapply那样调用它。