apply、call、bind改变函数上下文

112 阅读2分钟

「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战

this 的指向

首先可以通过以下代码执行下,看下 this 所指向的是什么?

// 普通函数 this 指向 window 
function func1(){
    console.log(`普通函数的this: ${this}`)
  }
  
// 构造函数 this 指向但获取当前 person实例对象
function Person(){}
Person.prototype.sayHi = function(){
​
}
var person = new Person();
​
// 对象方法 this 指向当前 tom 实例对象
var tom = {
    sayHi: function(){
        console.log(`对象方法的this: ${this}`)
    }
}
​
// 绑定事件 this 指向函数调用者
var btn = document.getElementById('btnId');
btn.onclick = function() {
    console.log('绑定事件函数的this:' + this);
};
// 定时器函数 this 指向的是 window 对象
setTimeout(function() {
    console.log('定时器的this:' + this);
}, 1000);
// 立即执行函数 this 指向的是 window 对象
(function() {
    console.log('立即执行函数的this' + this);
})();
​

基本以上几种调用方式,this 指向也是不同的,但一般都是指向调用者的。

  1. 普通函数调用时,this 指向 window
  2. 构造函数调用时,this 指向 实例对象
  3. 对象方法调用时,this 指向该方法所属的对象
  4. 事件绑定时,this 指向绑定事件对象
  5. 定时器函数和立即执行函数,this 指向的是 window

在 JavaScript 中,函数在定义时和运行时,其上下文 this 有时候需要作相应的变化。而 Function 自带的三个方法 bind、apply、 call就是为了改变函数中 this 的指向而存在的。

call

call(thisArgs [,args...])

call() 方法参数有两个:

  • thisArgs 是函数在运行期的调用者(即是 this )。

    • 当 thisArgs 参数不传或者传null,undefined, this 指向 window 对象;
    • 当是另一个函数的函数名,this 指向该函数;
    • 当是字符串、数值或布尔类型等基础类型, this 指向其对应的包装对象,如 String、Number、Boolean;
    • 当是一个对象, this 指向这个对象
  • 参数列表是会被传入调用函数中。

使用场景:用来实现继承

apply

apply(thisArgs [,args[]])

call 方法第二个参数和 apply方法不同,第一个参数和call 一样,第二个参数必须是数组。

使用场景:和数组有关系

var o = {
  name: 'andy'
}
 function fn(a, b) {
      console.log(this);
      console.log(a+b)
};
fn()// 此时的this指向的是window
fn.apply(o,[1,2])//此时的this指向的是对象o,参数使用数组传递

bind

bind(thisArgs [,args...])

bind 是 ES5新增的方法,传参和call方法相同,但是bind不会执行对应的函数,只是返回函数的引用,这和call和apply方法不同,它们会自动执行。

使用场景:事件的绑定,只改变 this 执行而不执行函数。

var person ={
  name :'tom'
}
function sayHi(a, b) {
  console.log(this);
  console.log(a + b);
};
//this指向的是对象person 参数使用逗号隔开
var f_say = sayHi.bind(person, 1, 2); //此处的f是bind返回的新函数
f_say(); // 只有重新调用才会执行