今天看到一篇博客是讲怎么用 bind() 的。大家都知道讲 bind() 嘛,不就是绑定 this 这个鬼东西嘛,然后在 setTimeout 里用用就好了。哎,我也是这么想的,直到看到最后一个例子:
因为 NodeList 原型不是 Array,所以要用 forEach 的话,我们可以从 Array.prototype 里把 forEach 偷过来用。
var unboundForEach = Array.prototype.forEach
var forEach = Function.prototype.call.bind(unboundForEach);
forEach(document.querySelectorAll('div'), function (el) {
console.log(el)
});
(为了简化我改成了 console.log)woc,这是个什么鬼头啊,bind 我知道怎么绑了个函数?返回一个新的 call
函数又是什么鬼,更诡异的是后面调用的时候好像看懂了,但是就是第二行不知道干了啥。
我搜了一下 StackOverflow 才发现有人也有这个问题。下面就从我的理解说说这第二行是个什么鬼。
目的
在搞清这个之前我们先明确一下我们的目的,就是想用 Array.prototype.forEach
函数然后遍历 NodeList。你可能会说为啥不做个狠人直接 NodeList.prototype.forEach = Array.prototype.forEach
,但是这改变了 prototype 不太好,所以我们期望的代码是这样的:
document.querySelectorAll('div').forEach((el) => {
console.log(el)
})
第一波反推
我们先不想上面的奇怪代码,先从我们的目的地开始做反推。为了方便,我先简化一下:
var nodeList = document.querySelectorAll('div')
var callback = (el) => {
console.log(el)
}
// 目的调用形式变成这样
nodeList.forEach(callback)
根据学过的 this
,一般来说哈(注意:这里我用了一般来说这四个字),对于 forEach
,里面的 this
就是 nodeList
。而 call
函数就是用来定义函数里的 this
的,所以可以写成这样:
forEach.call(nodeList, callback)
因为我们是要使用 Array.prototype.forEach
的,所以再多做一点扩展,和 Array.prototype.forEach
衔接一下:
Array.prototype.forEach.call(nodeList, callback)
第二波反推
我们把 Array.prototype.forEach
提取出来,免得写太长:
var unboundForEach = Array.prototype.forEach
上面的形式可以简写成这样:
unboundForEach.call(nodeList, callback)
我们再仔细看看这个 call
函数,对于 call
它的 this
应该是 unboundForEach
,所以我们可以搞一个新的 call
函数,这个函数是这样的:
- 它的
this
指向unboundForEach
(可以用 bind 绑定)。 - 这是个新的
call
,不能直接用 Function.call 的那个 (可以用 bind 返回新的函数)。
所以正好这里可以用 bind()
来搞定,也就变成了下面的代码。
// 定义一个新的 call 函数,this 指向 unboundForEach
var forEach = Function.prototype.call.bind(unboundForEach);
// 调用的时候直接可以这样
forEach(nodeList, cakkback)
最后
我觉得这个例子是真的闲得蛋疼,本来好好讲 bind
搞得那么复杂,而且这样也不是一个好的实战,明明有很多方法去实现,偏要搞这种绕来绕去的。
网友评论