js的this指向之隐式绑定和隐式丢失

1,137 阅读2分钟

隐式绑定

当一个函数a保存成某个对象A的属性时,我们称这个函数a为该对象的方法a。当这个方法a被调用时,方法a内部的this指向该方法所属的对象A。

总结一下就是,当一个函数以'方法调用模式'被调用时,this指向直接对象。

var a = 0;
function fn(){
    console.log(this.a);
}
var obj = {
    a: 1,
    myFn: fn,
    obj2: {
        a: 2,
        myFn: fn
    }
}
// 这里fn的直接对象是obj,this.a指向obj下的属性a
obj.myFn();         // 1
// 这里fn的直接对象是obj2,this.a指向obj2下的属性a
obj.obj2.myFn();    // 2

隐式丢失

被隐式绑定的函数由于某些原因丢失了绑定对象,this指向改变

原因1:函数别名

把一个隐式绑定的函数赋给了另一个变量,对这个变量进行操作造成隐式丢失,this指向window

var a = 0;
function fn(){
    console.log(this.a);
}
var obj = {
    a: 1,
    myFn: fn
}
// 隐式绑定,this.a指向直接对象obj下的属性a
obj.myFn();         // 1

//obj.myFn被赋值给bar,相当于把console.log(this.a);这句语句赋值给bar,bar与obj没有直接关系
var bar = obj.myFn;
// bar()相当于单纯的执行打印a这个操作,bar的作用域是全局,那么this就是window
// 隐式丢失,this.a指向window下的变量a
bar();              // 0

原因2:参数传递

把一个隐式绑定的函数作为参数传入另一个函数中,在另一个函数内部被调用时造成隐式丢失,this指向window

var a = 0;
function foo(){
    console.log(this.a);
}
function bar(fn){
    fn();
}
var obj = {
    a: 1,
    myFn: foo
}
// obj.myFn作为参数传入到bar函数中,在该函数内被调用,相当于在bar函数内部调用了foo(),与obj无关
// 隐式丢失,this.a指向window下的变量a
bar(obj.myFn);      // 0

原因3:内置函数

如内置函数setTimeout和setInterval,它俩的第一个参数是回调函数,这个回调函数中this指向window


setTimeout(function(){
    console.log(this);      // window
});

var a = 0;
function fn(){
    console.log(this.a);
}
var obj = {
    a: 1,
    myFn: fn
}
// obj.myFn作为内置函数setTimeout的回调函数,内置函数执行时造成隐式丢失,this.a指向window下的变量a
setTimeout(obj.myFn,1000);   // 0;

原因4:间接调用

将一个隐式绑定的函数用call(),apply()等方法间接调用时,造成隐式丢失,this指向call、apply中首个参数,若为空则指向window

var a = 0;
function fn(){
    console.log(this.a);
}
var obj = {
    a: 1,
    myFn: fn
}
var p = {
    a: 2
}

fn.call();          // 0
fn.call(obj);       // 1
p.myFn = obj.myFn;
fn.call(p);         // 2

其他原因

比如,自执行函数中this指向window

var a = 0;
function fn(){
    console.log(this.a);
}
var obj = {
    a: 1,
    myFn: fn
}
var p = {
    a: 2
}
// 相当于fn函数的立即调用,this指向window
(p.myFn = obj.myFn)()