JavaScript 中 this 的指向问题

首发我的博客浏览器

JavaScript 中的 this ,你们都用过。可是它到底指向哪里呢?今天在阅读 《你不知道的JavaScript (上卷)》再结合本身平时看的博客,对它又有了新的认识,在此来作个小结,再碰到 this ,就不再用担忧不知道它指向哪里了。

与调用位置有关,而与定义位置无关

如下示例(在浏览器端运行)app

function sayHi(){
    var hi = 1;
    console.log(this.hi);
}

var hi = 2;

var obj = {
    hi : 3,
    sayHi : sayHi
}

// output
sayHi(); // 2
obj.sayHi(); // 3

从上述代码的执行结果咱们能够看出,直接调用 sayHi() 函数,它输出的 this.hi 不指向函数体内本身定义的 hi 变量,也就是说,this 的指向与词法做用域无关,这也是刚接触 JavaScript的同窗常犯的一个错误(包括我本身),认为 this.xx 就指向函数体里面定义的变量 xxsayHi函数的只定义了一次,但obj.sayHi()sayHi() 的输出结果不同,也偏偏证实了 函数体内this的指向与函数定义的位置无关,而与函数被调用的位置有关,至于为何输出结果不同,在下文会讲到。函数

this 的绑定规则

默认绑定

默认绑定比较常见,表现形式就是在全局做用域中独立调用,如上文中的 sayHi(),这种直接调用方式函数体内的 this 就应用了默认绑定规则,默认绑定有如下两种状况。oop

  1. 在严格模式下(指在函数声明的过程当中,处在严格模式,而不是函数调用处于严格模式),函数体内 this 绑定到 undefined
  2. 在非严格模式下,函数体内 this 指向全局对象 window
/***** 如下例子为处在严格模式下 *****/
function fn1(){
    'use strict'
    console.log(this);
}

fn1(); // undefined

/***** 如下例子处于非严格模式下被调用 *****/
function fn2(){
    console.log(this);
}

fn2(); // window

function fn3(){
    console.log(this);
}

/*
 * 这也是在非严格模式下被调用
 * 由于在函数定义时没有用严格模式
 */
'use strict'
fn3(); // window

隐式绑定

隐式绑定的常见形式为 obj.fn(),若obj对象中有 fn 这个方法(fn能够在别处定义,但必须被添加到obj中做为obj的一个属性方法),那么 fn 中的 this 就指向 obj 对象,如最开始代码中 obj.sayHi() 输出3,就是由于sayHi中的this隐式绑定到obj对象。(我的以为默认绑定中绑定到window对象时也能够归类为隐式绑定,由于在全局对象中,非严格模式且不考虑ES6的话,全部的全局变量都自动成为window的属性)。来看个具备迷惑性的例子(出自于原书)post

function foo() { 
 console.log( this.a );
}
var obj = { 
 a: 2,
 foo: foo 
};
var bar = obj.foo; // 函数别名!
var a = "oops, global"; // a 是全局对象的属性
bar(); // "oops, global"

这是个具备迷惑性的例子,obj 对象有函数 foo 这个方法,后面又在全局做用域中,bar 引用了这个方法,最后再调用 bar。咱们只须要关注函数最后被调用的位置,它是在全局做用域中被单独调用的,因此仍是为默认绑定,指向 windowthis

显式绑定

显示绑定就比较简单了,用 call,apply,bind方法,都会绑定函数中的this到传入的参数对象中code

new 绑定

所谓new绑定就是在用构造函数new一个对象的时候,其中的this指向生成的对象。这就完了嘛?尚未哦。对象

箭头函数,词法做用域中的this

简单的说,箭头函数中的this,会绑定到函数外(也就是上一层做用域中的this),函数外的this指向哪,箭头函数中的this就指向哪。(代码出自于原书)blog

function foo() {
    // 返回一个箭头函数
    return (a) => {
        //this 继承自 foo()
        console.log( this.a ); 
    };
}

var obj1 = { 
    a:2
};

var obj2 = { 
    a:3
};

var bar = foo.call( obj1 );
/*
 * foo先绑定this到obj1对象上,因此foo内的this指向obj1,
 * 返回的箭头函数根据词法做用域规则,继承了外部foo的this,
 * 因此箭头函数中的this指向obj1
 */


bar.call( obj2 ); // 2, 不是 3 !
/*
 * 箭头函数中this一但绑定,不可更改
 * 此时仍是指向obj1
 * 因此输出的是 obj1.a => 2
 */

绑定的优先级

new > 显示 > 隐式 > 默认继承

上述知识来自《你不知道的JavaScript(上卷)》

相关文章
相关标签/搜索