JavaScript漫談之執行上下文與this

圖片來自網站wallhaven

更多內容請關注 GitHub

this,即當前執行代碼的環境對象。javascript

換句話說,執行的每一個JavaScript函數都有對其當前執行上下文的引用,稱爲thisjava

1、執行上下文

執行上下文表明函數的調用方式,大多數狀況下,函數的調用方式決定了this的值。即,執行上下文決定了this的值。git

要理解這個關鍵字this只須要this取決於函數的調用方式,跟函數聲明以及聲明位置不要緊github

好比看下面這段代碼:數組

function person() {
    console.log(this.name);
}

let name = "sueRimn";
let one = {name: "八至", age: 22};
let two = {name: "小九", age: 22};

person();     // "sueRimn"
one.person(); // "八至"
two.person(); // "小九"

代碼中函數person()的執行任務是打印出this.name,即打印當前執行上下文的name屬性的值。瀏覽器

當函數person()沒有被調用時,執行上下文也沒有指定,默認爲當前全局下,this.name就是全局變量的值"sueRimn"app

one.person()是表明函數person()one調用,此時函數的執行上下文是one,即執行上下文this.name的值就是one.name的值,two.person()也是相同道理。ide

注意函數

  • this不能在函數執行期間被賦值
  • 函數每次被調用時this的值不一樣

2、this關鍵字的綁定規則

this的綁定分爲:網站

  • 默認綁定與隱式綁定
  • 顯示綁定與固定綁定

一、默認綁定和隱式綁定

  • 嚴格模式下:this的默認值是undefined
  • 非嚴格模式下:this默認指向全局對象
  • 在函數內部,this的值取決於函數被調用的方式
  • 當有一個做爲方法調用的對象屬性時,該對象是該方法的this對象或執行上下文對象,這是this關鍵字的隱式綁定

只要記住,在函數內部,this的值取決於函數被調用的方式,與函數聲明時間、地點無關

//在瀏覽器中, window對象同時也是全局對象
// this的默認綁定
console.log(this === window);//true
const AGE = 22;
console.log(window.AGE); // 22

this.b = "sueRimn";
console.log(window.b); // "sueRimn"
console.log(b); // "sueRimn"

// this的隱式綁定
let obj_1 = {
    name: "sueRimn",
    person: function () {
        console.log(this.name);
    }
}

let obj_2 = {name: "八至", person: obj_1.person};
let name = "小九";
let person = obj_1.person;

person(); // "小九"
obj_1.person(); // "sueRimn"
obj_2.person(); // "八至"

二、顯示綁定和固定綁定

要想把 this 的值從一個環境傳到另外一個,就要用 call 或者apply 方法。

call()

call()方法使用一個指定的 this` 值和單獨給出的一個或多個參數來調用一個函數

fun.call(thisArg, arg1, arg2, ...)

apply()

apply() 方法調用一個具備給定this值的函數,以及做爲一個數組(或相似數組對象)提供的參數

func.apply(thisArg, [argsArray])

區別

  • call() 方法接受的是一個參數列表
  • apply() 方法接受的是一個包含多個參數的數組
let obj = {a: 'sue'};
let a = 'suerimn';
function whatThis(arg) {
    return this.a;//this的值取決於函數的調用方式
}

whatThis();// 'suerimn'
whatThis.call(obj);//'sue'
whatThis.apply(obj);//'sue'

若是咱們使用call()apply()方法調用函數,須要把本身的第一個參數做爲執行上下文。這就是this關鍵字的綁定。

注意:在顯示綁定或固定綁定中,不管在哪裏調用,能夠強制 this對象始終相同
function add(c, d) {
    return this.a + this.b + c + d;
}

let o = {a: 1, b: 3};
//第一個參數做爲this使用的對象
//後續參數做爲參數傳遞給函數調用
add.call(o, 2, 3);//1 + 3 + 2 + 3 = 9

//第一個參數做爲this使用的對象
//第二個參數是一個數組,數組裏的元素用做函數調用時的參數
add.apply(o, [10, 20]);//1 + 3 + 10 + 20 = 34

上面代碼中,add使用call()方法調用將執行上下文對象o做爲第一個參數傳遞,將o分配給this對象並返回。這稱爲this關鍵字的顯示綁定。

3、綁定this值的方法

(1)call()apply()

上文中已經說起。

(2)bind方法

ES5引入了bind方法來設置函數的this值,而不用考慮函數如何被調用的,調用f.bind(someObject)會建立一個與f具備相同函數體和做用域的函數,可是在這個新函數中,this將永久地被綁定到了bind的第一個參數,不管這個函數是如何被調用的。

function f() {
    return this.a;
}

let g = f.bind({a: 'sueRimn'});
console.log(g()); // sueRimn

let h = g.bind({a: 'sueRimn'}); // bind只生效一次
console.log(h()); // sueRimn

let z = {a: 37, f: f, g: g, h: h};
console.log(z.f(), z.g(), z.h()); // 37 'sueRimn' 'sueRimn'

(3)箭頭函數

這是ES6新引入的,在箭頭函數中,this與封閉詞法環境的this保持一致。在全局代碼中,它將被設置爲全局對象。

let person = (name, age) => {
    console.log(name, age);
}

(4)new關鍵字

當函數做爲對象裏的方法被調用時,它們的this是調用該函數的對象。

任何函數前面的new關鍵字都會將函數調用轉換爲構造函數調用,而且當new關鍵字放在函數前面時會發生這些事情:

  • 建立一個全新的空對象
  • 新的空對象連接到該函數的prototype屬性
  • 將相同的新空對象綁定爲該函數調用的執行上下文
  • 若是該函數沒有返回任何內容,則隱式返回此對象
function person() {
    let name = "sueRimn";
    this.age = 22;
    console.log(this.name + "" + age); // undefined 23
}

let name = "八至";
let age = 23;

obj = new person();
console.log(obj.age); // 22

在上面的代碼中,使用new關鍵字調用person函數,它建立了一個新對象連接到函數原型鏈上,並綁定到該對象函數返回的對象上。

this.name

let fn = {
    prop: 37,
    f: function () {
        return this.prop;
    }
};

console.log(fn.f());//37

4、this關鍵字綁定的順序

  1. 檢查函數是否使用new關鍵字調用
  2. 檢查函數是否使用call()或者apply()調用,由於這意味着顯示綁定
  3. 檢查函數是否經過上下文對象調用(隱式綁定)
  4. 默認全局對象(在嚴格模式下未定義)
相關文章
相關標籤/搜索