饥人谷技术博客vue开发干货call apply bind

记一次错:bind() 和 call() 一起用就懵逼了

2019-01-31  本文已影响117人  写代码的海怪

今天看到一篇博客是讲怎么用 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 函数,这个函数是这样的:

  1. 它的 this 指向 unboundForEach (可以用 bind 绑定)。
  2. 这是个新的 call,不能直接用 Function.call 的那个 (可以用 bind 返回新的函数)。

所以正好这里可以用 bind() 来搞定,也就变成了下面的代码。

// 定义一个新的 call 函数,this 指向 unboundForEach
var forEach = Function.prototype.call.bind(unboundForEach);
// 调用的时候直接可以这样
forEach(nodeList, cakkback)

最后

我觉得这个例子是真的闲得蛋疼,本来好好讲 bind 搞得那么复杂,而且这样也不是一个好的实战,明明有很多方法去实现,偏要搞这种绕来绕去的。

上一篇下一篇

猜你喜欢

热点阅读