JS中的this

參考
English
中文

先導(dǎo)知識:

call, apply, bind

兩個概念:

調(diào)用點(call-site):代碼中函數(shù)被調(diào)用的地方而不是函數(shù)被定義的地方。
調(diào)用棧(call-stack):代碼執(zhí)行時到達當前位置的函數(shù)棧。我們care的是當前函數(shù)環(huán)境的調(diào)用位置。
舉個栗子:

function a(){
  //調(diào)用棧為'a'
  //調(diào)用點在全局作用域中
  console.log('a');
  //b的調(diào)用點
  b();
}
function b(){
  //調(diào)用棧為'a' ->'b'
  //調(diào)用點在a中
  console.log('b');
  //c的調(diào)用點
  c();
}
function c(){
  //調(diào)用棧為'a' ->'b'->'c'
  //調(diào)用點在b中
  console.log('c');
}

//a的調(diào)用點
a();

四種綁定:

默認綁定(Default Binding)

被直接(plain, un-decorated)調(diào)用的函數(shù)在非嚴格(non-strict)模式下綁定的是全局對象;在嚴格(strict)模式下undefined,報錯。
栗子:

  1. 非嚴格模式直接調(diào)用函數(shù)
function foo() {
    console.log( this.a );
}
var a = 2;
foo(); // 2
  1. 嚴格模式直接調(diào)用函數(shù)(只和函數(shù)內(nèi)部是不是嚴格模式有關(guān),而和調(diào)用點是不是嚴格模式無關(guān))
function foo() {
    "use strict";

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

隱式綁定(Implicit Binding)

調(diào)用點函數(shù)引用是否有一個環(huán)境對象(如果有多級引用,則取離函數(shù)最近的對象)
栗子:

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
//此處調(diào)用bar依然是對foo函數(shù)的直接引用,所以是默認綁定
bar(); // "oops, global"

如果不想像調(diào)用對象上的屬性函數(shù)這樣來綁定this,請看下面的顯示綁定

顯示綁定(Explicit Binding)

使用call方法和bind方法
栗子:foo.call(obj),此時foo函數(shù)中的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的函數(shù),他已經(jīng)不是foo了
//所以bar中的this不能被重載了
bar.call( window ); // 2

個人覺得You don't know JS作者將強綁定歸入顯示綁定而不是劃等號應(yīng)該是因為顯示綁定中可能就是直接以foo.call(obj)形式調(diào)用一次,而強綁定則將這個強綁定的函數(shù)保留多次調(diào)用。如有其它建議,歡迎討論。

  1. API調(diào)用環(huán)境(API call context)
    許多庫函數(shù)都可以接受一個環(huán)境參數(shù)
    栗子:
function foo(el) {
    console.log( el, this.id );
}
var obj = {
    id: "awesome"
};
// 每次調(diào)用foo函數(shù)都把obj作為this引用
[1, 2, 3].forEach( foo, obj ); // 1 awesome  2 awesome  3 awesome

new綁定(new Binding):

在JS中,構(gòu)造器(constructor)僅僅是使用new操作符調(diào)用的函數(shù)而已。它不附屬于類,沒有實例化一個類,甚至不是特殊類型的函數(shù)。它只是因為new的用法而被誤解的普通函數(shù)。
在JS中沒有構(gòu)造函數(shù),只有對函數(shù)的構(gòu)造調(diào)用。當一個函數(shù)被new操作符調(diào)用時,發(fā)生了下列操作

  1. 生成一個新對象
  2. 新對象被[[Prototype]]-linked
  3. 新對象被綁定到這次函數(shù)調(diào)用的this
  4. 除非函數(shù)返回其他對象,否則默認就返回這個新創(chuàng)建的對象的了
    栗子:
function foo(a) {
    this.a = a;
}
var bar = new foo( 2 );//this綁定到了新創(chuàng)建的對象,即bar
console.log( bar.a ); // 2

綁定例外(Binding Exceptions)

詞法this(Lexical this)

ES6的箭頭函數(shù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容