this绑定规则

Wenn 于 2022-09-22 发布

this指向

  1. setTimeout/setInterval

    setTimeout(function(){console.log(this)},1000); //window
    
  2. 监听点击

    const boxDiv = document.querySelector('.box')
    boxDiv.onclick = function (){console.log(this)}; //this => boxDiv
    
  3. Array.forEach/map/filter/find

    const arr = [1,2,3]
    arr.forEach(function(item){console.log(item,this)}) 
    //1,window   2,window    3,window
    
    //Array.forEach(function(){},this)  当我们在函数后添加变量,则此时this指向该变量
    const arr = [1,2,3]
    const obj = {age : 20}
    arr.forEach(function(item){console.log(item,this)},obj)
    //1,{age:20}   2,{age:20}    3,{age:20}
    

this绑定规则优先级

  1. 默认规则最低

  2. 显示绑定高于隐式绑定

    //call、apply高于隐式绑定
    const obj = {
        foo:function(){
            cosnole.log(this)
        }
    }
    obj.foo(); //this => obj
    obj.foo.call('aaa'); //this => 'aaa'
    obj.foo.apply('bbb'); //this => 'bbb'
       
       
    //bind高于隐式绑定且高于call、apply
    function foo(){
        console.log(this)
    }
    const obj = {
        foo : foo.bind('aaa')
    }
    obj.foo(); //this => 'aaa'
    
  3. new绑定高于隐式绑定

    var obj = {
        foo:function(){
            console.log(this)
        }
    }
    var f = new obj.foo()
    //this => foo
    
  4. new绑定高于显示绑定

    //new关键字不能和apply、call一起使用
    function foo(){
        console.log(this)
    }
    var bar = foo.bind('aaa')
    var obj = new bar()  //this => foo
    
this规则之外

apply、call、bind:当传入null、undefined时,自动将this绑定为全局对象

function foo(){
    console.log(this)
}
foo.apply(null);  // this => window
foo.call(undefined);  // this => window
var bar = foo.bind(null)
bar();  //this => window

间接函数调用

var obj = {
    foo:function(){
        console.log(this)
    }
}
var obj2 = {}
obj2.bar = obj.foo
obj2.bar(); //this => obj2

//当出现这种情况时指向window
var obj1 = {
    foo:function(){
        console.log(this)
    }
}
var obj2 = {};
(obj2.bar = obj1.foo)(); //this => window
//此时相当于独立函数,即foo()
function foo(el){
    console.log(el,this)
}
var obj = {};  // <== 此处必须要加分号,否则报错,以为下一行与此处为一个整体
[1,2,3].forEach(foo,obj);
//1,obj    2,obj    3,obj

箭头函数没有自己的this,依托上层作用域的this

var obj = {
    data : [],
    foo:function(){
        setTimeout(function(){
            var result = [1,2,3]
            this.data = result  //指向window
        },1000)
    }
}

var obj = {
    data : [],
    foo : function (){
        var _this = this
        setTImeout(function(){
            var result = [1,2,3]
            _this.data = result  //指向obj中的this,闭包
        },1000)
    }
}

var obj = {
    data : [],
    foo : function(){
        setTimeout(()=>{
            var result = [1,2,3]
            this.data = result   //指向上层作用域中的this
        })
    }
}
经典面试题
var person = {
    sayName : function (){
        console.log(this)
    }
}
function sayName(){
    var sss = person.sayName;  // sss = function(){coonsole.log(this)}
    sss();  //window   独立函数 function(){console.log(this)}
    person.sayName();   //person
    (person.sayName)();   //与上一行相同  person
    b = person.sayName)();  //window  等同于function(){console.log(this)}
}
sayName();

对象不生成作用域,只有函数会有作用域

var person1 = {
    foo1 : function (){
        console.log(this)
    },
    foo2 : ()=> console.log(this),
    foo3 : function(){
        return function(){
            console.log(this)
        }
    },
	foo4 : function(){
        return ()=>console.log(this)
    }
}
var person2 = {}

person1.foo1(); //person1   隐式绑定
person1.foo.call(person2); //person2  显示绑定

person1.foo2();  //window  箭头函数依托上层作用域,此时为全局
person1.foo2.call(person2); //window

person1.foo3()();  //window  独立函数调用
person1.foo3.call(person2); //window  
person1.foo3().call(person2); //person2

peson1.foo4()(); //person1 箭头函数不绑定this,上层作用域中的this指向parson1
person1.foo4.call(person2)(); //parson2  上层作用域被显示绑定person2
person1.foo4().call(person2); //parson1
function Person (){
    this.foo1 : function (){
        console.log(this)
    },
    this.foo2 : ()=>console.log(this),
    this.foo3 : function (){
        return function (){
            console.log(this)
        }
    },
    this.foo4 : function (){
        return ()=>console.log(this)
    }
}
var person1 = new Person();
var person2 = new Person();

person1.foo1(); //person1
person1.foo1.call(person2); //person2

person1.foo2(); //person1
person1.foo2.call(person2); //person1

person1.foo3()(); //window
person1.foo3.call(person2)(); //window
person1.foo3().call(person2); //person2

person1.foo4()(); //perosn1
person1.foo4.call(person2)(); //person2
peron1.foo4().call(person2); //person1
function Person (){
    this.obj = {
        foo1 : function (){
            return function (){
                console.log(this)
            }
        },
        foo2 : function (){
            retuen ()=>console.log(this)
        }
    }
}
var person1 = new Person();
var person2 = new Person();

person1.obj.foo1()(); //window
person1.obj.foo1.call(person2)(); //window
person1.obj.foo1().call(person2); //person2

person1.obj.foo2()(); //obj
person1.obj.foo2.call(person2)(); //person2
person1.obj.foo2().call(person2); //obj