深入理解 apply、call、bind

我们知道,在代码的世界里,一切皆为对象。函数也不例外,既然是对象,那么就可能有属性和方法,今天就聊一聊函数中的apply、call、bind方法。

apply

使用函数的 apply 方法,调用的时候会改变函数 this 值。是的,使用 apply,其实进行了两个操作:执行函数,改变 this 值。

apply 方法接收两个参数,第一个参数是改变 this 值的对象,第二个参数是一个数组,数组的元素会依次传入到函数的命名参数中。

看下面代码:

// 普通调用
window.name = '人类';
let person = {
    name: '柯腾',
}
function genInfo(num1, num2) {
  return `${this.name}, ${num1+num2}`
}

genInfo(10,15); // '人类, 25'

// apply方法调用
window.name = '人类';
let person = {
    name: '柯腾',
}
function genInfo(num1, num2) {
  return `${this.name}, ${num1+num2}`
}

genInfo.apply(person, [10,15]); // '柯腾, 25'

上面代码,普通调用中,因为 genColor 函数是在全局作用域上调用的,因此 this.name 就是 window.name,因此输出字符串’人类’。

而使用 apply 方法调用,apply 方法第一个参数传入person,因此会将genInfo函数的 this,也就是执行上下文替换为person对象,此时person对象中有name属性,因此返回字符串’柯腾’;

可以看到,apply 方法第二个参数传入数组[10,15],它会作为函数的参数,传入到genInfo的命名参数中,执行计算返回数值 25。

call

call 和 apply 使用的内部原理是一样的,这里就不啰嗦了。唯一不同之处就是第二个参数。call 可以传入多个参数,看下面代码

window.name = '人类';
let person = {
    name: '柯腾',
}
function genInfo(num1, num2) {
  return `${this.name}, ${num1+num2}`
}

genInfo.call(person, 10, 15); // '柯腾, 25'

可以看到,和使用 apply 的区别:“将 [10,15] 替换为 10,15”,此时10,15会依次传入到genInfo函数中,执行计算返回数值 25。

bind

bind方法和上面两个方法区别就稍微有点大了。某个函数执行 bind 方法,此时不会调用这个函数,只是改变这个函数的 this 值。因此使用 bind,其实也进行了两个操作:改变函数 this 值,返回一个新的函数实例。看下面代码:

window.name = '人类';
let person = {
    name: '柯腾',
}
function genInfo(num1, num2) {
  return `${this.name}, ${num1+num2}`
}

let bindgenInfo = genInfo.bind(person, 10, 15);
bindgenInfo(); // '柯腾, 25'(此时虽然在全局作用域上面调用bindgenInfo,但是它的 this 值是指向person的)

相同点:

三个方法都可以改变调用函数的 this 值,并且提供最大的便捷性和灵活性,不然之前要实现这样的效果,需要这样做:

window.name = '人类';
let person = {
    name: '柯腾',
}
function genInfo(num1, num2) {
  return `${this.name}, ${num1+num2}`
}
person.genInfo = genInfo;
person.genInfo(10,15) // '柯腾, 25'

此时,在person对象上动态添加genInfo方法,然后将genInfo函数的指针也复制一份给它。现在的情况是genInfo和person.genInfo都指向同一个函数,只不过各自的执行上下文不一样。

不同点:

apply 和 call 可以算是一家人,只不过是传入参数形式略有区别,具体使用哪种方式,由在开发过程中的便捷性决定;而 bind 方法,会返回一个新的函数实例,并且不会立即调用函数,参数可以是任意数量。

你可能感兴趣的:(javascript,前端,面试)