JavaScript 判断函数的this 绑定

1.函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。

function fun(){
    this.age = 23;
}
var obj = new fun();

console.log(window.age);        //undefined
console.log(obj.age);        //23

 

2.函数是否通过 callapplybind显式绑定)或者硬绑定调用?如果是的话,this 绑定的是指定的对象。

var obj = {};
function fun(){
    console.log(this === obj);
}

fun();        //false
fun.apply(obj);        //true
fun.call(obj);        //true
fun.bind(obj)();        //true

 

3.函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上下文对象。

var obj = {
    fun : function(){
        console.log(this === obj);
    }
};

obj.fun();    //true

  对象属性引用链中只有最顶层或者说最后一层会影响调用位置。

function fun(){
    console.log(this === obj1);
}
var obj1 = {
    fun : fun
}
var obj2 = {
    obj1 : obj1
}
var obj3 = {
    obj2 : obj2
}

obj3.obj2.obj1.fun();        //true

 

4.如果都不是的话,使用(默认绑定)。如果在严格模式下,就绑定到 undefined,否则绑定到全局对象。

function fun(){
    console.log(this === window);
}

fun();    //true


function fun(){
    'use strict';
    console.log(this === undefined);
}

fun();    //true

  对于默认绑定来说,决定 this 绑定对象的并不是调用位置是否处于严格模式,而是函数体是否处于严格模式。如果函数体处于严格模式,this 会被绑定到 undefined,否则 this 会被绑定到全局对象。

function fun(){
    console.log(this === window);
}

(function(){
    'use strict';
    fun();
})();            //true

 

如果某个函数的调用位置应用了多条规则,那么将按照:new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定 的优先级来决定哪条规则会生效。

注意:
  一、有些调用可能在无意中使用默认绑定规则。如果想“更安全”地忽略 this 绑定,你可以使用一个 DMZ 对象,比如 ø = Object.create(null) ,以保护全局对象。
  二、window.setTimeout()和window.setInterval()的函数中的this有些特殊,里面的this默认是window对象
 
ES6 中的箭头函数并不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定this ,具体来说,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。这其实和 ES6 之前代码中的 self = this 机制一样。

箭头函数的特性一:默认绑定外层this(因为箭头函数默认不会使用自己的this,而是会和外层的this保持一致,最外层的this就是window对象。

const obj = {
    a: function() { console.log(this) }    
}
obj.a()  //打出的是obj对象


//箭头函数
const obj = {
    a: () => {
        console.log(this)
    }
}
obj.a()  //打出来的是window

箭头函数的特性二:不能用call方法修改里面的this

const obj = {
    a: () => {
        console.log(this)
    }
}
obj.a.call('123')  //打出来的结果依然是window对象

//上文我们说到window.setTimeout()中函数里的this默认是window,我们也可以通过箭头函数使它的this和外层的this保持一致
const obj = {
    a: function() {
        console.log(this)
        window.setTimeout(() => { 
            console.log(this) 
        }, 1000)
    }
}
obj.a.call(obj)  //第一个this是obj对象,第二个this还是obj对象

 

多层对象嵌套里函数的this

const obj = {
    a: function() { console.log(this) },
    b: {
        c: function() {console.log(this)}
    }
}
obj.a()  // 打出的是obj对象, 相当于obj.a.call(obj)
obj.b.c() //打出的是obj.b对象, 相当于obj.b.c.call(obj.b)

//看看箭头函数
const obj = {
    a: function() { console.log(this) },
    b: {
        c: () => {console.log(this)}
    }
}
obj.a()   //没有使用箭头函数打出的是obj
obj.b.c()  //打出的是window对象!!

MDN官方文档里面描述箭头函数this定义的时候,描述的是“箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。",所以最后一个例子,打出window对象的原因,是window对象就是它的上一层this,而多层嵌套只是对象嵌套,这时候没有作用域链的嵌套。

 

posted @ 2021-05-27 10:54  超帅的轻省回望  阅读(86)  评论(0)    收藏  举报