预编译过程中,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)
全局环境下,this指向window
console.log(this)
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的区别
- 三者都可以改变this的指向
- 第一个参数都为this要指向的对象,如果没有这个参数或参数为undefind或null,则默认指向window
- 三者都可以传递参数,call和bind传的是参数列表,apply传的是参数数组
- 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()