JavaScript 函数调用的三剑客:bind、call 和 apply 的欢乐冒险

403 阅读3分钟

前言

在 JavaScript 的世界里,bindcallapply 是三位功能强大但又性格迥异的好朋友。它们都有一个共同的目标——改变函数内部 this 的指向,但是每个人都有自己独特的做事方式。今天,我们就来聊聊这三位小伙伴的故事,看看它们是如何帮助开发者们解决各种问题的。

在介绍这三兄弟前,我们先提前建立一个a的对象字面量,为了方便演示我们将fn通过var b=a.fn转变成普通函数,让它的this指向全局,在前端即是window,在后端环境则为global

    var a = {
      name: 'Cherry',
      fn: function (a, b) {
        console.log(this.name)
        console.log(a + b)
      }
    }
    var b=a.fn

第一章:bind —— 永远的契约者

bind 就像是一个忠诚的契约缔造者。一旦它与某个对象和参数绑定在一起,这个约定就不会改变。无论何时何地,只要你调用了由 bind 创建的新函数,它都会记得当初与你订下的约定,永远保持相同的 this 值,并且预先设定好的参数也不会变。这种特性非常适合用来创建回调函数或者需要保存特定调用上下文的情况。

var boundFn = b.bind(a, 1, 2);
boundFn(); // 输出: Cherry 3

image.png

bind 并不会立即执行函数,而是返回一个新的函数,等待你的召唤。就像一位耐心的骑士,在你需要的时候才挺身而出。

也不一定要在生成bind就赋值,也可以在调用的时候在赋值!

var boundFn2 =b.bind(a);
boundFn(12); // 也是输出: Cherry 3

image.png

第二章:call —— 立刻行动派

与 bind 不同,call 是个急性子,它喜欢立刻采取行动。当 call 接收到任务时(即被调用),它会马上根据你给定的对象和参数执行函数。而且它接受多个参数,每个参数都单独列出,就像是在传递一份精心准备的礼物清单给函数。

  • 注意call与bind都是一个个赋值的,apply则是使用数组的形式来整体赋值
b.call(a, 1, 2); // 输出: Cherry 3

call 总是直接了当,没有多余的花哨,它只关心如何快速有效地完成工作。如果你需要迅速解决问题,call 可能就是你要找的人。


这里我们我们试试以数组的形式来传递参数

image.png

让我们来分析一下为什么会输出这个?

由于我们之前说过call是一个个传递的,所以我们可以知道,[1,2]都被赋值给a,而b在函数入栈的时候被默认赋值为undefind,然后ab通过+号连接起来,由于加号两边不是简单的number所以被都被强转为字符串类型,然后合在一起输出了。


第三章:apply —— 团队合作大师

最后出场的是 apply,这位团队合作的大师擅长处理数组形式的参数列表。它不仅能够像 call 那样立即执行函数,还能轻松地将一组参数打包成一个数组传入。这使得 apply 成为了处理动态参数列表的理想选择。

b.apply(a, [1, 2]); // 输出: Cherry 3

apply 就像是一个优秀的项目经理,它懂得如何组织和分配资源,确保每个成员都能各司其职,完美协作。

结语:三位英雄的共同使命

虽然 bind、call 和 apply 各有特点,但它们共享同一个目标:让函数内的 this 关键字按照我们的意愿工作。无论是为未来的调用做准备(bind)、立即执行任务(call),还是高效管理参数列表(apply),这三个工具都能为我们提供极大的便利。下次当你面对复杂的函数调用场景时,不妨考虑一下这些得力助手吧!

20200229174423_bzukt.jpg