引言
嘿!如果你正在准备 JavaScript 面试或者已经在日常编码中遇到过apply、call和bind这三个家伙,那今天就是你的幸运日。在这篇文章中我们将一起揭开它们神秘的底层原理,看看它们到底有什么区别,为什么有些面试官会执着于这三个毫不起眼的方法?
改变 this 的指向
通过改变this的指向,我们可以更加灵活地处理函数调用,使代码更加模块化、可重用,并且更容易维护。而apply、call和bind恰好就是改变this指向的一把好手,那么我们接下来就分别对它们进行介绍。
call 方法
call 方法允许我们指定一个对象作为当前正在执行的函数内部 this 的值,并立即调用该函数。此外,call 还能接收额外的参数,这些参数会按顺序传递给被调用的函数。例如:
var a = {
name: 'Cherry',
fn: function(a, b){
console.log(this.name); // 输出 "Cherry"
console.log(a + b); // 输出 3
}
}
var b = a.fn;
b.call(a, 1, 2); // 模板:call(thisArg, arg1, arg2, ...)
在这里我们通过call将this指向了a,并且传入(1,2)两个参数执行输出参数之和
apply 方法
apply 方法与 call 类似,同样用于改变函数执行时的 this 值并立即调用函数。不过,apply 接受的是一个参数数组(或类数组对象),而不是一系列独立的参数。例如:
// 在上述代码中的call替换为
console.log(b.apply(a, [1, 2])); // 模板:apply(thisArg, [argsArray])
bind 方法
bind 创建一个新的函数实例,在这个新函数中,this 被永久绑定到指定的对象上。这使得我们可以创建预设了部分参数的新函数,而不需要立即执行它们。例如:
// 替换为以下代码
console.log(b.bind(a, 1, 2)()); // 输出 "Cherry" 和 3
假如我们要决定一个方法去邀请别人来参加活动,而apply、call和bind就像是三种不同的邀请方式,例如:
apply喜欢直接邀请一群人(参数数组)一起出现。call则更倾向于直接点名邀请(一个个列出参数)。bind先不说定邀请谁,而是把邀请函留着(创建函数),等到时候再揭晓(再看是否调用)。
这样我们就初步了解了apply、call和bind这三个方法各自的作用,但是我们不妨将它们串起来,看下会摩擦出什么样的火花吧
示例:
来看下面的一串代码:
var a = {
name: 'Cherry',
fn: function(a, b){
console.log(this.name)
console.log(a + b)
}
}
var b = a.fn; // 普通函数
console.log(b.apply(a, [1, 2]))
console.log(b.call(a, [1, 2]))
console.log(b.bind(a, 1, 2))
在上述代码中我们发现调用这三个方法的形态极其相似,那么打印结果有什么区别吗?
我们可以看到this的指向都没有问题,通过这三个方法我们的成功让this指向了a。但是我们也发现了一丝异常。
- 异常一 : 为什么会打印这么多
undefined? - 异常二 : 调用
call()的结果为什么是打印了一串字符串?
异常一:
首先先打印undefined是因为我们通过这句代码var b = a.fn;将b定义为了函数,但是我们发现在a中的fn函数本身没有返回任何值,所以就会隐式返回undefined,在进行输出时就会将undefined打印出。如果改为:
b.apply(a, [1, 2]);
b.call(a, [1, 2]);
b.bind(a, 1, 2)();
这样就不会打印undefined了。
异常二:
我们知道call()对于参数是一个一个调用的,但是我们这里直接传入一个数组进去,这里就发生了变化,执行fn()时的参数就变成了fn(a=[1,2],b),对于b我们并没有传参进去,所以其默认为undefined,然后对a、b进行加法运算符,但是数组和undefined怎么加呀?
在 JS 中,当数组与其他类型进行加法运算时,数组会被隐式地执行 [].toString()转化为字符串。同理undefined与string进行加法运算时,undefined会被隐式地执行 String(undefined)转化为字符串。所以加法的功能就从数字相加变成了拼接字符串,即"1,2"+"undefined"。这就有了最后输出的"1,2undefined"
结论:
回顾上述内容,this、call、apply 和 bind 都是 JavaScript 中非常重要的概念。熟练运用它们可以帮助我们更好地控制函数的执行环境,从而编写出更加优雅和高效的代码。
---欢迎各位点赞、收藏、关注,如果觉得有收获或者需要改进的地方,希望评论在下方,不定期更新