经常看到介绍call或者apply的文章,然后会以下面这种代码来举例说明 .
function identify() {
console.log("Hello,I'm " + this.name);
}
let me = {
name: "Kyle"
};
let you = {
name: "Reader"
};
identify.call(me); // Hello,I'm Kyle
identify.call(you); // Hello,I'm Reader
我有点不理解的是,实际开发的时候以参数的形式传给 indentify(obj)
方法不是更好吗,
// 传参形式
function identify(obj) {
console.log("Hello,I'm " + obj.name);
}
let me = {
name: "Kyle"
};
let you = {
name: "Reader"
};
identify(me); // Hello,I'm Kyle
identify(you); // Hello,I'm Reader
那么bind,call,apply一般在实际项目中什么地方会用到 ?
我也同意第二种方法更好。实际上我觉得JavaScript没给
this
一个正式的形参地位就是设计失误,其他函数式/面向对象混合的语言都显式给出了(以至于被Python点名嘲讽,新语言都不敢用this
这个关键字了),TypeScript如果在class
之外引用this
也是要求作为第一个形参显式声明的。编译器知道this
是隐藏参数,程序员也知道,但大家都闷声大发财,这是最糟糕的。bind
/call
/apply
干什么用的bind
可以拿来做偏函数应用,试试往后面继续填参数,这些参数会被“记住”,以便之后使用。在现代语境下,
call
/apply
的唯一作用就是把本来是隐藏参数的this
提成正式参数,允许程序员显式指定。上面举的例子Math.max.apply(null, [1, 2, 3, 4])
,推荐的做法应该是Math.max(...[1, 2, 3, 4])
,清晰明了,而且在现代浏览器里性能会略有提升。除非是引用了别人的代码,恕我直言,自愿去搅和call
/apply
的,都是文明用语行为。封装起来给别人使用/别人写的代码
个人观察,现在的大趋势也是不做文明用语行为,不在
class
以外乱搞this
,所以可以期待别人写的代码里需要call
/apply
的也会越来越少。koa 1用this
传上下文被喷了,koa 2马上改成显式形参。lodash这种工具库全是第二种方式传参的,如果想链式调用,都需要手动包装。vue一大堆
this
,其实一小撮人是有意见的,考虑到一般来说组件的函数都不通用,不存在需要call
/apply
的场合,我也就接受了。但vuex的mutations很有可能是通用的,所以也是用的第二种方式传参,要不然真的是超级文明用语。如果是自己写的代码需要别人提供this
,建议反思一下。unbound
上面有回答提到“反柯里化的实现”(实际上我觉得应该叫debound),更多是历史遗留问题的妥协方案。被设计为通用的函数,本身就不应该被绑在特定的类里面,只不过此事已经发生,ES标准又不能大改,只能将就着。像Python这种兼容性喂狗的语言,早就彻底消除了“反柯里化”这种行为的必要性,全是直接用第二种方式传参。不是因为
this
的话,没有必要自找麻烦。总结
call
/apply
是历史遗留问题的解决方案bind
的用处更广泛些,偏函数应用还是相当好使的call
/apply
还是有必要的call
/apply