我是如何理解this的

163 阅读4分钟

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。