this不是指自身,它是一个指针,指向调用函数的对象。
1.默认绑定
默认绑定,在不能应用绑定规则时使用的默认规则,通常是独立函数调用。
function sayHi(){
console.log("My name is "+ this.name)
}
var name = 'Li Lei'
sayHi() // My name is Li Lei
在调用sayHi()时,使用了默认绑定,this指向全局对象(非严格模式),如果是严格模式(“use strict”),this指向undefined,undefined上没有this对象,会抛出错误
2.隐式绑定
函数的调用是在某个对象上触发的,即调用位置上存在上下文对象。典型的形式是XX.fun()。我们来看一段代码:
function sayHi(){
console.log("My name is "+ this.name)
}
var person = {
name: 'Li Yang',
sayHi:sayHi,
}
var name = 'Li Lei'
person.sayHi() // My name is Li Yang
sayHi函数声明在外部,严格来说并不属于person,但是在调用sayHi时,调用位置会使用person的上下文来引用函数,隐式绑定会把函数调用中的this(即此例sayHi函数中的this)绑定到这个上下文对象(即此例中的person)
注意:对象属性链中只有最后一层会影响到调用位置。
隐式调用丢失:
a.如果链式用本地的一个变量接受,就要看改变量的上下文。如下:
function sayHi(){
console.log("My name is "+ this.name)
}
var person = {
name: 'Li Yang',
sayHi:sayHi,
}
var name = 'Li Lei'
var Hi = person.sayHi
Hi() // My name is Li Lei
b.回调函数
function sayHi(){
console.log("Hello",this.name)
}
var person1 = {
name:"Li Yang",
sayHi:function(){
setTimeout(function(){
console.log("Hello",this.name)
})
}
}
var person2 = {
name:"Li Mei",
sayHi:sayHi,
}
var name = "Li Tao";
person1.sayHi();
setTimeout(person2.sayHi,100)
setTimeout(function(){
person2.sayHi()
}, 200);
// Hello , Li Tao
// Hello , Li Tao
// Hello , Li Mei
第一条,setTimeout的回调函数中,this使用的默认绑定,非严格模式下,执行的是全局对象
第二条,XX.fun()的时候,fun中的this指向的是XX,为什么不是这样?setTimeout(fn,delay){ fn(); },相当于是将person2.sayHi赋值给了一个变量,最后执行了变量,这个时候,sayHi中的this显然和person2就没有关系了。
第三条,虽然也是在setTimeout的回调中,但是我们可以看出,这是执行的是person2.sayHi()使用的是隐式绑定,因此这是this指向的是person2,跟当前的作用域没有任何关系。
3.显示绑定
显式绑定比较好理解,就是通过call,apply,bind的方式,显式的指定this所指向的对象。
function sayHi(){
console.log("Hello",this.name)
}
var person = {
name:"Li Yang",
sayHi:sayHi
}
var name = "Li Mei";
var Hi = person.sayHi;
Hi()
Hi.call(person) // Hi.apply(person)
// Hello Li Mei
// Hello Li Yang
使用硬绑定明确将this绑定在了person上
4.new绑定
使用new来调用函数,会自动执行下面的操作;
1.创建一个新对象;
2.将构造函数的作用域赋值给一个新对象,即this指向这个新对象;
3.执行构造函数中的代码;
4.返回新对象
function sayHi(name){
this.name = name ;
}
var Hi = new sayHi("Li Mei")
console.log("Hello",Hi.name)
箭头函数
箭头函数是ES6中新增的,它和普通函数有一定区别,箭头函数没有自己的this,它的this继承于外层代码库的this
1.函数体内的this对象,继承的是外层代码块的this;
2.不可能当作构造函数,也就是说,不可以使用new命令;
3.不可以使用arguments对象,改对象在函数体内不存在。如果要用,可以用rest参数代替;
4.不可以使用yield,因此箭头函数体不能作用Generater函数;
5.箭头函数没有自己的this,所以不能使用call(),apply() 或bind()来改变this指向
var obj = {
hi:function(){
console.log(this,"Hi");
return ()=>{
console.log(this,"Hi=>()")
}
},
}
let fun1 = obj.hi();
fun1();
// hi
// hi