1.Function.apply.bind(…)
我在学习promise部分的时候遇到了这样的代码:
Promise.resolve([10,20]).then(Function.apply.bind(function(x, y){
console.log(x, y);
}, null)); // 10,20
看到这里我已经蒙圈了,Function.apply.bind(…)是个什么操作?可能很多人和我一样之前只接触过Function.bind.apply(…)。
于是查了一下文档,大致明白了其中的含义。先撇开Promise不谈,直接来看Function.apply.bind(…):
var sum = function(x, y) {
console.log(x, y);
}
var foo = Function.apply.bind(sum, null);
foo([10, 20]); // 10, 20
这里我们有一个函数sum,通过Function.apply.bind(sum, null)我们创建了一个新的函数foo(…)。
我们一步步分析Function.apply.bind(sum, null)这段代码。
sum.apply(null, [10, 20])这句代码将第一个参数置为null,第二个参数是一个数组,用于拆开后作为sum的最终参数。
熟悉sum.apply(…)方法的朋友一定知道,如果将sum.apply(…)的第一个参数设置为null,那么就意味着我们并不关心sum在执行时其内部的this指向谁。而Function.apply.bind(sum, null)目的就是将sum.apply(…)的第一个参数固定为null(其中,Function.apply.bind(sum, null)等价于sum.apply.bind(sum, null))。
所以最终我们得到的foo函数就是sum.apply(null, [10, 20]); [10,20]会拆开成10和20传递给sum(…)。
那么我们再回到最开始的那个Promise的例子,传递给.then()的Promise决议值就是数组[10,20],.then函数的第一个参数(通常我们称之为fulfilled(…)函数)就相当于我们刚才创建的foo(…),执行foo([10, 20])输出结果就是10,20。
2.Function.bind.apply(…)
那么类似的问题就还剩Function.bind.apply(…)。
我第一次见到这样的代码是在《你不知道的JS》中卷的2.4小节。讲回调的时候。针对回调的调用过早的问题,有经验的开发者们给出了这样的解决方式(当然ES6之后解决回调函数调用过早的问题还是倾向于借助Promise机制):
function asyncify(fn) {
var orig_fn = fn,
intv = setTimeout( function(){
intv = null;
if (fn) fn();
}, 0 )
; fn = null; return function() {
// 触发太快,在定时器intv触发指示异步转换发生之前?
if (intv) {
fn = orig_fn.bind.apply(
orig_fn,
// 将包装函数的`this`加入`bind(..)`调用的
// 参数,同时currying其他所有的传入参数
[this].concat( [].slice.call( arguments ) )
);
}
// 说明没有过早触发,这里已经是异步
else {
// 调用原来的函数
orig_fn.apply( this, arguments );
}
};
}
和前面类似,我们将orig_fn.bind.apply(orig_fn, args)拆成两部分来看:函数orig_fn.bind(…)和.apply(orig_fn, args)。根据.apply(…)的定义,orig_fn.bind.apply(orig_fn, args)其实就意味着我们将orig_fn.bind(…)函数的this指向orig_fn,然后.apply(orig_fn, args)的第二个参数会将剩下的参数传递给orig_fn.bind(…)函数。
那么我们现在分析一下剩下的参数([this].concat( [].slice.call( arguments ))都是什么吧,首先arguments是外界传入的其余参数(return function(…)这个函数传入的参数),接下来我们借助[].slice.call( arguments )将其转化为一个参数数组,备用。由于.bind(…)的第一个参数为在 origin_fn 调用中用到的 this (我们在前一段就已经提到过,这个this其实就指向orig_fn),所以使用 [this] 将构造的参数数组中的第一个参数设置为 this 。[this]再与我们前面的备用数组拼接起来,一同传递给.bind(…)。
此时,.bind(…)的第一个参数就是this,剩余参数就是外界传入的参数。所以,除了传递给orig_fn.bind(…)的第一个参数this,其余的参数都会作为柯里化参数(预设值)。
在这里的关键点是:.bind(…) 函数是通过 .apply(…) 调用的,所以 .bind(…) 自身所需要的 this 对象是一个函数(函数也是对象,在这里即 origin_fn)。
---------------------
版权声明:本文为CSDN博主「Typhoonnnnn」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_37787381/article/details/81509361