首頁 > web前端 > js教程 > JavaScript中神奇的this到底是啥?

JavaScript中神奇的this到底是啥?

藏色散人
發布: 2021-09-25 17:27:37
轉載
1951 人瀏覽過
this 關鍵字是 JavaScript 中最複雜的機制之一。它是一個很特別的關鍵字,被自動定義在所有函數的作用域中。但即使是非常有經驗的 JavaScript 開發者也很難說清它到底指向什麼。

this是什麼?

指向函數本身?

光從字面意思來看,很容易讓人覺得this就是指向函數本身,事實上真是這樣嗎?我們可以看一個例子。

function foo() {
    this.count = this.count ? this.count + 1 : 1;
}

for (let i = 0; i < 5; i++) {
    foo();
}
console.log(foo.count); // undefined
登入後複製

可以看到,foo.count輸出的不是我們期待的5,而是一開始賦值的0。也就是說this其實並沒有指向函數本身

指向作用域?

還有一種比較常見的誤解是,this指向了函數的作用域。

function foo() {
    var a = 2;
    bar();
}
function bar() {
    console.log(this.a);
}

foo(); // undefined
登入後複製

這段程式碼中,bar在foo中運行,輸出this.a得到的卻是undefined。也就是說this也不是指向函數的作用域的

這也不是,那也不是,this到底是什麼呢? 在函數執行過程中,會建立一個執行上下文(一個記錄),this就是這個上下文中的一個屬性,在執行過程中被使用。而this的指向則是取決於函數在哪裡被呼叫。

this的綁定規則

this的綁定有四個可以遵循的規則,下面將一一介紹。

1.預設綁定

獨立函數調用,非嚴格模式下,指向window;嚴格模式下指向undefined。 這裡說的獨立函數可以理解成除開後面三種情況的一般函數呼叫。

// 非严格模式
var name = &#39;Willem&#39;;
function foo() {
    console.log(this.name);
}
foo(); // Willem

// 执行时启用严格模式
(function() {
    &#39;use strict&#39;;
    foo(); // Willem
    bar(); // Cannot read property &#39;name&#39; of undefined
})();

// 函数体使用严格模式
function bar() {
    &#39;use strict&#39;;
    console.log(this.name);
}
登入後複製

上述程式碼中,分別在一般環境中輸出Willem,說明指向的確實是window物件。需要特別注意的一點是:嚴格模式下指向undefined指的是函數體內啟用了嚴格模式,而不是呼叫時。

2. 隱式綁定

隱式綁定說的是,在函數執行時,是否被某個物件擁有或包含。換句話說,在函數運行時,是否是作為某個物件的屬性的方式運行的,這樣說還是不是很清楚,來個栗子:

function foo() {
    console.log(this.a);
}
var a = 1;
var obj = {
    a: 2,
    foo
};
obj.foo(); // 2
var obj2 = {
    a: 3,
    obj
};
obj2.obj.foo(); // 2
登入後複製

範例中,foo被當做了obj的一個屬性進行執行,此時obj作為了函數的上下文,此時this指向了obj,this.a等價於obj.a。在物件屬性鍊式的呼叫中,只有最後一層會對呼叫位置產生影響,也就是說最後一層會影響this指向。

有很多前端的小夥伴面試時或許還見過這樣的題:

function foo() {
    console.log(this.a);
}
var a = 1;
var obj = {
    a: 2,
    foo
};
var bar = obj.foo;
bar(); // 1
登入後複製

這是隱式綁定最常見的一個問題,隱式遺失:被隱式綁定的函數會遺失綁定物件。雖然bar是obj.foo的一個引用,但實際上引用的還是foo函數本身,bar函數就是一個獨立函數的調用,參考第一條,此時this指向了window|undefined

還有一種經典的回呼函數的this指向問題也是隱式遺失。

function foo() {
    console.log(this.a);
}
function doFoo(fn) {
    fn();
}
var a = 1;
var obj = {
    a: 2,
    foo
};
doFoo(obj.foo); // 1
登入後複製

小結:在隱式綁定中,賦值的情況下(回呼是隱式賦值)需要特別注意隱式遺失的問題 。

3. 顯示綁定

JavaScript中的Function提供了兩個方法callapply,傳入的第一個參數是一個對象,會把this綁定到這個對象。如果是傳入的是原始值(字串、數字、布林),會轉換成它的物件形式(new String(), new Boolean(), new Number())。

function foo() {
    console.log(this.a);
}
var obj = {
    a: 1
};
foo.call(obj); // 1
登入後複製

雖然我們可以使用callapply明確指定this的指向,但是還是會存在遺失綁定的問題。可以用所謂的硬綁定(bind函數)來解決,這裡就不過多贅述了。

4. new

最後要介紹的是使用new來做this的綁定的修改,有手動實現過new的童鞋應該比較清楚,js中的new和其他語言的new完全不同。
new的執行過程:

  1. 建立一個空物件
  2. 目前空物件執行原型對接
  3. 回傳函數執行結果或目前這個空物件
function Foo(a) {
    this.a = a;
}

var bar = new Foo(2);
bar.a; // 2
登入後複製

使用new 來呼叫函數時,我們會建構一個新物件並把它綁定到函數呼叫中的this上。

優先權

最後簡單說一下優先權的關係:new > 顯示綁定 > 隱含綁定 > 預設綁定。

推薦學習:《javascript基礎教學

#

以上是JavaScript中神奇的this到底是啥?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:segmentfault.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板