首頁 >web前端 >js教程 >JavaScript基礎之this的具體詳解

JavaScript基礎之this的具體詳解

黄舟
黄舟原創
2017-06-04 10:23:201271瀏覽

JavaScript函數的this物件是函數在執行時所處的作用域(例:當在網頁的全域作用域中呼叫函數時,this物件引用的就是window)。

JavaScript的this和Java等物件導向語言中的this大不一樣,bind()、call()和apply()函數更是將this的彈性度進一步延伸。

為了保證可讀性,本文採用意譯而非直譯。另外,本文版權歸原作者所有,翻譯僅用於學習。

如果對JavaScript的關鍵字this理解不夠深刻,有時候會掉入意想不到的坑。這裡我們總結了5條通用規則來幫助你判斷this到底指向什麼。雖然沒有囊括所有的情況,但日常大部分情況都可以使用這些規則來正確推論。

this的值通常是由所在函數的執行環境決定,也就是說要看函數是如何被調用的;
同一個函數每一次調用,this都可能指向不同的物件;

全域物件(Global Object)

#開啟Chrome瀏覽器開發者面板(Windows: Ctrl + Shift + J)(Mac: Cmd + Option + J),並且輸入:

console.log(this);

看看輸出了什麼?

// Window {}

window物件! 因為在全域作用域下,this指向全域物件。在瀏覽器中全域物件就是window物件。
為了讓你更清楚理解為什麼this會指向window對象,我們來看另外一個例子:

var myName = 'Brandon';
myName
// 输出 'Brandon'

其實,所有在全域定義的變數都綁定到window對象。讓我們來做以下測試:

window.myName
// 输出 'Brandon'
window.myName === myName
// 输出 true

現在我們將this放到函數內部,看看有何效果。

function test(){
 return this;
}
test();

你會發現this依然指向全域的window物件。因為this關鍵字沒有處於一個聲明的物件內部,預設指向全域window物件。這一點可能對於大部分初學者來說有點難以理解。當你讀完這篇文章,你就會豁然開朗。
注意:如果在strcit模式下,上面的例子this為undefined。

聲明的物件(Declared Object)

當this關鍵字在一個宣告物件內部使用,其值會被綁定到呼叫該this的函數的最近的父物件。我們用例子來說明這個問題:

var person = {
 first: 'John',
 last: 'Smith', 
 full: function() {
  console.log(this.first + ' ' + this.last);
 }
};
person.full();
// 输出 'John Smith'

在被宣告的物件person中的full函數裡面使用了this, 那麼呼叫this的full函數的最近的父物件就是person, 因此,this指向person。

為了更好的描述this實際上是指向person物件的,你可以拷貝如下程式碼到瀏覽器控制台,將this列印出來。

var person = {
 first: 'John',
 last: 'Smith', 
 full: function() {
  console.log(this);
 }
};
person.full();
// 输出 Object {first: "John", last: "Smith", full: function}

我們接下來看一個更複雜的例子:

var person = {
 first: 'John',
 last: 'Smith',
 full: function() {
  console.log(this.first + ' ' + this.last);
 },
 personTwo: {
  first: 'Allison',
  last: 'Jones',
  full: function() {
   console.log(this.first + ' ' + this.last);
  }
 }
};

在這裡我們有嵌套的對象,在這個時候,this分別指向誰呢? 我們將其印出來看看:

person.full();
// 输出 'John Smith'
person.personTwo.full();
// 输出 'Allison Jones'

你會發現滿足我們前面所描述的規則:其值會被綁定到呼叫this的函數的最近的父物件。

new關鍵字

當使用new關鍵字建立一個新的對象,this會綁定到這個新物件。我們來看一個例子:

function Car(make, model) {
 this.make = make;
 this.model = model;
};

根據第一條規則,你可能會推斷this指向全域物件。但是如果我們使用new關鍵字來宣告一個新的變量,Car函數中的this將會綁定一個新的空對象,然後初始化this.make和this.model的值。

var myCar = new Car('Ford', 'Escape');
console.log(myCar);
// 输出 Car {make: "Ford", model: "Escape"}

call, bind, 和apply

#我們可以顯示的在call(),bind(),apply()設定this的綁定對象。這三個函數很類似,但是我們需要注意它們微小的差異。

38ddcca26dd818c5dfda95290df96ccd

我們來看一個例子:

function add(c, d) {
 console.log(this.a + this.b + c + d);
}
add(3,4);
// 输出 NaN

add函數輸出NaN, 因為this.a和this.b未定義。

現在我們引入對象,並且使用call()和apply()來呼叫:

function add(c, d) {
 console.log(this.a + this.b + c + d);
}
var ten = {a: 1, b: 2};
add.call(ten, 3, 4);
// 输出 10
add.apply(ten, [3,4]);
// 输出 10

當我們使用add.call(),第一個參數是this需要綁定的對象,剩下的是add函數本來的參數。
因此,this.a指向ten.a,this.b指向ten.b。 add.apply()也類似,除了第二個參數是一個陣列,用來儲存add函數的參數

bind()函数和call()类似,但是bind()函数不会立即被调用。bind()函数会返回一个函数,并且将this绑定好。接下来我们来用例子来帮助理解bind()函数的应用场景:

var small = {
 a: 1,
 go: function(b,c,d){
  console.log(this.a+b+c+d);
 }
}
var large = {
 a: 100
}

执行:

small.go(2, 3, 4);
// 输出 10

如果我们想使用large.a的值,而不是small.a呢? 我们可以使用call/apply:

small.go.call(large, 2, 3, 4);
// 输出 109

但是,如果我们现在还不知道这三个参数应该传入什么值,应该怎么办呢? 我们可以使用bind:

var bindTest = small.go.bind(large, 2);

如果我们将bindTest在控制台下打印出来,我们会看到:

console.log(bindTest);
// 输出 function (b,c,d){console.log(this.a+b+c+d);}

注意:该函数已经将this绑定到large对象,并且传入了第一个参数b。所以,我们接下来是需要传入余下的参数即可:

bindTest(3, 4);
// 输出 109

箭头函数(=>)

因为需要很大的篇幅,我们会专门写一篇博客来介绍。

结论

当你读完这篇博客,你应该可以理解大多数情况下this指向的对象。
接下来我们来总结一下:

this的值通常是由当前函数的执行环境所决定;
在全局作用域,this指向全局对象 (window对象);
当使用new关键字声明,this指向新建对象;
我们可以使用call(), bind(), apply()来设置this;
箭头函数不会绑定this。

以上是JavaScript基礎之this的具體詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn