this是什么?
this是一个指针,指向调用函数的对象。也就是说,谁调用了函数this就指向谁。
this的绑定规则
1:默认绑定
默认绑定:在不能应用其他绑定规则时使用的默认规则,通常时独立函数调用
function sayHi(){
console.log('Hello',this.name)
}
var name = 'wan-ti';
sayHi();
调用Hi()时,应用了默认绑定,非严格模式下this指向全局对象,严格模式下this指向undefined.但是undefined上没有this对象,会抛出错误。
2:隐式绑定
函数的调用是在某个对象上出触发的。典型的形式为:XXX.fun()
function sayHi(){
console.log('Hello',this.name);
}
var person = {
name:"wan-ti",
sayHi:sayHi
}
var name="shu-mo"
person.sayHi()//Hello,wan-ti
sayHi的函数声明在外部,严格来说并不属于Person,但是在调用sayHi时,调用位置会使用Person的上下文来引用函数,隐式绑定会把函数调用中的this(也就是sayHi函数中的this)绑定到上下文对象中。 对象属性链种之后最后一层会影响到调用位置
function sayHi(){
console.log('Hello',this.name);
}
var person2 = {
name:'Wan-Ti',
sayHi:sayHi
}
var person1 = {
name:'shu-mo',
friend:persion2
}
person1.friend.sayHi();//Hello,wan-ti
只有最后一层会确定this指向是什么,所以我们也只需要关注最后一层。
留个坑:隐式绑定的丢失会发生在回调函数中
3:显示绑定
通过call,apply,bind的方式直接指出来this是谁。
call,apply,bind的第一个参数就是对应函数的this指向的对象。call和apply的作用一样,只是传参方式不同。call和apply会执行对应的函数,但是bind方法不会
function sayHi(){
console.log('Hello',this.name);
}
ver person = {
name:"wan-ti",
sayHi:sayHi
}
var name = 'shu-mo';
var Hi= person.sayHi;
Hi.call(person);//Hello,wan-ti
Hi.apply(person);//Hello,Wan-Ti
使用显示绑定同样会发生绑定丢失,解决办法时在调用fn的时候,进行硬绑定
4:new绑定
- 创建一个新对象
- 将构造函数的作用域赋值给新对象,也就是this来指向这个新对象
- 执行构造函数中的代码
- 返回新对象
因此我们使用new来调用函数的时候,就会将新对象绑定到这个函数的this上。
function sayHi(name){
this.name = name;
}
var Hi =new sayHi('wan-ti');
console,log('Hello',Hi.name)//Hello.wan-ti
在执行var Hi= new sayHi('wan-ti')的时候,会将sayHi中的this绑定到Hi对象上
绑定优先级
new绑定> 显示绑定 > 隐式绑定 > 默认绑定
绑定例外
如果将null或undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用到的还是默认绑定规则
var foo = {
name:'wan-ti'
}
var name = 'shu-mo';
function bar(){
console.log(this.name);
}
bar.call(null);//shu-mo
箭头函数
箭头函数没有自己的this,它的this继承于外层代码库中的this
- 函数体内的this对象,继承的是外层代码块的this
- 不可以当作构造函数,也就说,不可以使用new命令,否则会抛出错误
- 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用rest参数代替
- 不可以使用yield命令,因此箭头函数不能用作Generator函数
- 箭头函数没有自己的this,所以不能用call(),apply(),bind()去改变this指向
var obj = {
hi: function(){
console.log(this);
return ()=>{
console.log(this);
}
},
sayHi: function(){
return function() {
console.log(this);
return ()=>{
console.log(this);
}
}
},
say: ()=>{
console.log(this);
}
}
let hi = obj.hi(); //输出obj对象
hi(); //输出obj对象
let sayHi = obj.sayHi();
let fun1 = sayHi(); //输出window
fun1(); //输出window
obj.say(); //输出window
如何判断this指向
- 函数是否在new中调用(new绑定),如果是,那么this绑定的是新创建的对象。
- 函数是否通过call,apply调用,或者使用了bind(即硬绑定),如果是,那么this绑定的就是指定的对象。
- 函数是否在某个上下文对象中调用(隐式绑定),如果是的话,this绑定的是那个上下文对象。一般是obj.foo()
- 如果以上都不是,那么使用默认绑定。如果在严格模式下,则绑定到undefined,否则绑定到全局对象。
- 如果把Null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。
- 如果是箭头函数,箭头函数的this继承的是外层代码块的this。