JS中的this

参考
English
中文

先导知识:

call, apply, bind

两个概念:

调用点(call-site):代码中函数被调用的地方而不是函数被定义的地方。
调用栈(call-stack):代码执行时到达当前位置的函数栈。我们care的是当前函数环境的调用位置。
举个栗子:

function a(){
  //调用栈为'a'
  //调用点在全局作用域中
  console.log('a');
  //b的调用点
  b();
}
function b(){
  //调用栈为'a' ->'b'
  //调用点在a中
  console.log('b');
  //c的调用点
  c();
}
function c(){
  //调用栈为'a' ->'b'->'c'
  //调用点在b中
  console.log('c');
}

//a的调用点
a();

四种绑定:

默认绑定(Default Binding)

被直接(plain, un-decorated)调用的函数在非严格(non-strict)模式下绑定的是全局对象;在严格(strict)模式下undefined,报错。
栗子:

  1. 非严格模式直接调用函数
function foo() {
    console.log( this.a );
}
var a = 2;
foo(); // 2
  1. 严格模式直接调用函数(只和函数内部是不是严格模式有关,而和调用点是不是严格模式无关)
function foo() {
    "use strict";

    console.log( this.a );
}
var a = 2;
foo(); // TypeError: `this` is `undefined`

隐式绑定(Implicit Binding)

调用点函数引用是否有一个环境对象(如果有多级引用,则取离函数最近的对象)
栗子:

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

var obj = {
    a: 2,
    foo: foo
};

obj.foo(); // 2

番栗子:

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

var obj = {
    a: 2,
    foo: foo
};

var bar = obj.foo; // function reference/alias!

var a = "oops, global"; // `a` also property on global object
//此处调用bar依然是对foo函数的直接引用,所以是默认绑定
bar(); // "oops, global"

如果不想像调用对象上的属性函数这样来绑定this,请看下面的显示绑定

显示绑定(Explicit Binding)

使用call方法和bind方法
栗子:foo.call(obj),此时foo函数中的this引用的就是obj

  1. 强绑定(Hard Binding)
    栗子:
function foo() {
    console.log( this.a );
}
var obj = {
    a: 2
};
var bar = function() {
    foo.call( obj );
};
bar(); // 2
setTimeout( bar, 100 ); // 2
// bar是一个将this强绑定为obj的函数,他已经不是foo了
//所以bar中的this不能被重载了
bar.call( window ); // 2

个人觉得You don't know JS作者将强绑定归入显示绑定而不是划等号应该是因为显示绑定中可能就是直接以foo.call(obj)形式调用一次,而强绑定则将这个强绑定的函数保留多次调用。如有其它建议,欢迎讨论。

  1. API调用环境(API call context)
    许多库函数都可以接受一个环境参数
    栗子:
function foo(el) {
    console.log( el, this.id );
}
var obj = {
    id: "awesome"
};
// 每次调用foo函数都把obj作为this引用
[1, 2, 3].forEach( foo, obj ); // 1 awesome  2 awesome  3 awesome

new绑定(new Binding):

在JS中,构造器(constructor)仅仅是使用new操作符调用的函数而已。它不附属于类,没有实例化一个类,甚至不是特殊类型的函数。它只是因为new的用法而被误解的普通函数。
在JS中没有构造函数,只有对函数的构造调用。当一个函数被new操作符调用时,发生了下列操作

  1. 生成一个新对象
  2. 新对象被[[Prototype]]-linked
  3. 新对象被绑定到这次函数调用的this
  4. 除非函数返回其他对象,否则默认就返回这个新创建的对象的了
    栗子:
function foo(a) {
    this.a = a;
}
var bar = new foo( 2 );//this绑定到了新创建的对象,即bar
console.log( bar.a ); // 2

绑定例外(Binding Exceptions)

词法this(Lexical this)

ES6的箭头函数

你可能感兴趣的:(JS中的this)