【JS系列】- this绑定

63 阅读2分钟

在 JavaScript中,this 是在**运行时而不是编写时绑定**的。

  1. 隐式绑定
    当我们把对象里的方法赋值给一个全局变量时,这种绑定就消失了
function logger() {
    console.log( this.a );
}

var obj = {
    a: 3,
    logger: logger
};

var a = 2;

var objLogger = obj.logger; 

objLogger(); // 2
  1. 显示绑定:call 或者 apply
  2. 硬性绑定:bind

无论后续我们怎么调用 hardBinding 函数,logger 都会把 obj 当做 this 来获取它的 a 属性的值。

function logger() {
    console.log( this.a );
}

var obj = {
    a: 3
};

var hardBinding = logger.bind( obj );

setTimeout( hardBinding, 1000 ); // 3

hardBinding.call( window ); // 3
  1. new 绑定

function logger(a) {
    this.a = a;
}

var obj1 = {};

var hardBinding = logger.bind( obj1 );

hardBinding( 2 );

console.log( obj1.a ); // 2

var obj2 = new logger( 3 );

console.log( obj1.a ); // 2
console.log( obj2.a ); // 3
  1. 箭头函数
    我们使用箭头函数的时候,this 是在词法域里面的,而不是根据函数执行时的上下文。
    箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承 this

function logger() {
    return (a) => {
        console.log( this.a );
    };
}
var obj1 = {
    a: 2
};

var obj2 = {
    a: 3
};

var logger1 = logger.call( obj1 );

logger1.call( obj2 ); // 2

setTimeout 场景使用

function logger() {
    setTimeout(() => {
        console.log( this); // {a: 2}
    },1000);
}
var obj = {
    a: 2
};
function logger() {
    setTimeout(function() {
        console.log( this); // Window 
    },1000);
}
var obj = {
    a: 2
};

function logger() {
    var self = this; 
    setTimeout( function(){
        console.log( self.a );  // 2
    }, 1000 );
}
var obj = {
    a: 2
};
logger.call( obj ); 

常见错误

JavaScript 新手经常犯的一个错误是**将一个方法从对象中拿出来,然后再调用**
期望方法中的 this 是原来的对象(比如在回调中传入这个方法)。
如果不做特殊处理的话,一般会丢失原来的对象。
基于这个函数,用原始的对象创建一个绑定函数,巧妙地解决了这个问题:

this.x = 9;    // 在浏览器中,this 指向全局的 "window" 对象
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX();
// 返回 9 - 因为函数是在全局作用域中调用的

// 创建一个新函数,把 'this' 绑定到 module 对象
// 新手可能会将全局变量 x 与 module 的属性 x 混淆
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81