this的指向及call、apply、bind的区别

65 阅读3分钟

预编译过程中,this指向window

function test(c){
    let a = 123
    function b(){
        console.log(this);
    }
    b()
    console.log(this);
}
// AO{
//     arguments:[1],
//     this:window
//     a:undefined,
//     b:function b(){},
//     c:1
// }

test(1)

image.png

全局环境下,this指向window

console.log(this)

image.png

this == window //true

call、apply、bind能改变this的指向

call()

当执行一个函数时,例如test(),其实内部会经历一个变化为test.call()

正常写test.call()和test()得到的是一样的效果

而如果传入参数,则将改变this指向

function Person(name,age){
    //this = obj
    this.name = name
    this.age = age
    console.log(this);
}
let person = new Person('tom',18) //Person {name: 'tom', age: 18}

let obj = {}
//将Person里面所有的this全部变成obj
Person.call(obj)  //{name: undefined, age: undefined}
// 那么Person在执行时就会变成obj.name,obj.age

// 传参数从第二位开始传,并且传入的是参数列表
Person.call(obj,'tony',33)  //{name: 'tony', age: 33}

call.(thisArg,arg1...argn)

第一位传入的指定的this值,第二位及以后的参数就是函数的参数,是一个参数列表。

返回值就是函数的返回值,因为它就是调用函数。

应用:

function Person(name,age){
    this.name = name
    this.age = age
}

function Student(name,age,sex,grade){
    Person.call(this,name,age)
    this.sex = sex
    this.grade = grade
}

let student = new Student('tom','18','male',2024)
//Student的功能涵盖了Person的功能,想要Student直接使用Person的功能

apply()

apply与call相似,唯一的区别是apply需要将参数作为数组传递

apply(thisArg,[argsArray])

第一位传入的是指定的this值,第二位传递的是参数数组。

返回值就是函数的返回值,因为它就是调用函数。

function Person(name,age){
    this.name = name
    this.age = age
    console.log(this);
}
let person = new Person('tom',18) //Person {name: 'tom', age: 18}

let obj = {}
Person.apply(obj,['tony',30])  //{name: 'tony', age: 30}

应用场景:apply主要和数组有关系,比如使用Math.max求数组的最大值,也可以求最小值

//当没使用扩展运算符时,使用apply,求数组的最大值
const arr = [1,2,3,4]
let max = Math.max.apply(null,arr)
console.log(max);

bind()

bind与call和apply不同的时,bind不会调用函数,但是能够改变this指向

bind(thisArg,arg1,...argn)

返回由指定的this值和初始化参数改造的原函数拷贝,返回一个新函数

function Person(name,age){
    this.name = name
    this.age = age
    console.log(this);
}
let person = new Person('tom',18) //Person {name: 'tom', age: 18}

let obj = {}
Person.bind()  //不会调用函数

//bind返回一个新函数
let fun = Person.bind(obj,'tony',18)
fun()  //{name: 'tony', age: 18}

应用场景:改变定时器里的this

// 有一个按钮,点击立马就禁用,两秒后开启
let btn = document.querySelector('button')
btn.addEventListener('click',function(){
    this.disabled = true  //禁用按钮
    //定时器不使用箭头函数
    setTimeout(function(){
        this.disabled = false
        console.log(this);
    }.bind(this),2000)
},false)

//bind里的this是指向btn的

小结:call、apply、bind的区别

  1. 三者都可以改变this的指向
  2. 第一个参数都为this要指向的对象,如果没有这个参数或参数为undefind或null,则默认指向window
  3. 三者都可以传递参数,call和bind传的是参数列表,apply传的是参数数组
  4. call和apply会立马执行函数,并且返回函数的值,bind不会调用函数,并且返回修改this后的新函数

obj.fn(); fn()里面的this指向obj

简单来说,谁调用这个方法,这个方法里的this就是谁

let obj = {
    a: function(){
        console.log(this.name);
    },
    name:'tom'
}
obj.a()  //tom

构造函数中的this指向当前实例化的对象

function Test(){
    console.log(this);
//this指向的就是Test
}
let test = new Test()