搜尋
首頁web前端js教程關於 this 你想知道的一切都在這裡

關於 this 你想知道的一切都在這裡

Jan 23, 2017 pm 04:12 PM
javascript前端

無論在 javascript 的日常使用中還是前端面試過程中,this 的出鏡率都極高。這無疑說明了,this 的重要性。但 this 非常靈活,導致許多人覺得 this 的行為難以理解。本文從為什麼要有 this 作為切入點,總結了 this 的六大規則,希望能幫助你解答困惑。

簡介

this 實際上相當於一個參數,這個參數可能是開發中手動傳入的,也可能是 JS 或第三方傳入的。
這個參數,通常指向的是函數執行時的「擁有者」。 this 的機制,可以讓函數設計的更簡潔,而且多用性更好。

this 是在函數執行時進行綁定的,綁定規則一共六條,分別是:

●new 綁定:使用 new 關鍵字建立物件時,this 會綁定到已建立的物件上。

●明確綁定:使用 call、apply 或 bind 方法明確綁定時, this 為其第一個參數。

●隱式綁定:當函數掛在物件上執行時,系統會隱含地將 this 綁定到該物件上。

●預設綁定:當函數獨立執行時,嚴格模式 this 的預設綁定值為 undefined,否則為全域物件。

●箭頭函數綁定:使用箭頭函數時,this的綁定值等於其外層的普通函數(或全域物件本身)的this。

●系統或第三方綁定:當函數作為參數,傳入系統或第三方提供的介面時,傳入函數中的 this 是由系統或第三方綁定的。

this 的作用

this 的機制提供了一個優雅的方式,隱式地傳遞一個對象,這可以讓函數設計的更加簡潔,並且復用性更好。

考慮下面一個例子,有兩個按鈕,點擊後將其背景改為紅色。

function changeBackgroundColor(ele) {
  ele.style.backgroundColor = 'red';
}
btn1.addEventListener('click',function () {
  changeBackgroundColor(btn1);
});
btn2.addEventListener('click',function () {
  changeBackgroundColor(btn2);
});

在這裡,我們明確地將被點擊的元素傳遞給了 changeBackgroundColor 函數。但實際上,這裡可以利用  this 隱式傳遞上下文的特點,直接在函數取得目前被點擊的元素。如下:

function changeBackgroundColor() {    this.style.backgroundColor = 'red';
}
btn1.addEventListener('click',changeBackgroundColor);
btn2.addEventListener('click',changeBackgroundColor);

在第一個例子中,被點擊元素是透過 ele ,這個形式參數來取代的。而在第二個例子中,是透過一個特殊的關鍵字 this 來取代。 this 它的作用和形式參數類似,其本質上是一個物件的引用,它的特殊性在於不需要手動傳值,所以使用起來會更加簡單和方便。

六大規則

在實際使用中, this 究竟指向哪個物件是最令人困惑的。本文歸類了六類情景,總結六條 this 的綁定規則。

1.new 綁定

使用 new 建立物件的時候,類別中的 this 指的是什麼?

class Person {
  constructor(name){
    this.name = name;
  }
  getThis(){
    return this
  }
}
const xiaoMing = new Person("小明");
console.log(xiaoMing.getThis() === xiaoMing); // true
console.log(xiaoMing.getThis() === Person); // false
console.log(xiaoMing.name === "小明"); // true

在上面範例中,使用了 ES6 的語法建立了 Person 類別。在使用 new 關鍵字建立物件的過程中,this 會由系統自動綁定到已建立的物件上,也就是 xiaoMing。

規則一:在使用 new 關鍵字建立物件時,this 會綁定到已建立的物件上。

2.明確綁定


情景二,使用 call、apply 和 bind 方法,明確綁定 this 參數。

以 call 為例,call 方法的第一個傳入的參數,是 this 所引用的物件。

function foo() {  console.log( this === obj ); // true
  console.log( this.a === 2 ); // true}const obj = {
  a: 2};
foo.call( obj );

在明確傳遞的情況下,this 指向的物件很明顯,就是 call、apply 或 bind 方法的第一個參數。

規則二:使用 call、apply 或 bind 方法明確綁定時, this 為其第一個參數。

3.隱式綁定


隱式綁定和明確綁定不同的地方在於,明確綁定由開發者來指定this;而隱式綁定時,函數或方法綁定不同的地方在於,明確綁定由開發者來指定this;而隱式綁定時,函數或方法綁定時,函數或方法綁定都會有一個“擁有者”,這個“擁有者”指的是直接呼叫的函數或方法物件。

例一

先看一個最簡單的例子。

function bar() {  console.log( this === obj );
}const obj = {
  foo: function () {    console.log( this === obj );
  },
  bar: bar
};
obj.foo(); // trueobj.bar(); // true


函數 foo 是直接掛在物件 obj 裡面的,函數 bar 是在外面定義的,然後掛在物件 obj 上的。無論函數是在何處定義,但最後函數呼叫時,它的「擁有者」是 obj。所以 this 指向的是函數呼叫時的「擁有者」 obj。

例二

為了更深入的理解,再考慮函數重新賦值到新的物件上的情況,來看看下面的例子。

function bar() {  console.log( this === obj1 ); // false
  console.log( this === obj2 ); // true}const obj1 = {
  foo: function () {    console.log( this === obj1 ); // false
    console.log( this === obj2 ); // true
  },
  bar: bar
};const obj2 = {
  foo: obj1.foo,
  bar: obj1.bar
};

obj2.foo();
obj2.bar();

在這個例子中,將 obj1 中的 foo 和 bar 方法賦值給了 obj2。函數呼叫時,「擁有者」是 obj2,而不是 obj1。所以 this 指向的是 obj2。

例三

物件可以多層嵌套,在這種情況下執行函數,函數的「擁有者」是誰呢?

const obj1 = {
  obj2: {
    foo: function foo() {      console.log( this === obj1 );      // false
      console.log( this === obj1.obj2 ); // true
    }
  }
};

obj1.obj2.foo()

foo 方法/函數中的直接呼叫者是 obj2,而不是 obj1,所以函數的「擁有者」指向的是離它最近的直接呼叫者。

例四

如果一个方法/函数,在它的直接对象上调用执行,又同时执行了 call 方法,那么它是属于隐式绑定还是显式绑定呢?

const obj1 = {
  a: 1,
  foo: function () {    console.log(this === obj1); // false
    console.log(this === obj2); // true
    console.log(this.a === 2);  // true
  }
};const obj2 = {
  a: 2};

obj1.foo.call(obj2); // true

由上,可以看出,如果显式绑定存在,它就不可能属于隐式绑定。

规则三:如果函数是挂在对象上执行的,这个时候系统会隐式的将 this 绑定为函数执行时的“拥有者”。

4.默认绑定

前一小段,讨论了函数作为对象的方法执行时的情况。本小段,要讨论的是,函数独立执行的情况。

在函数直接调用的情况下,this 绑定的行为,称之为默认绑定。

例一

为了简单起见,先讨论在浏览器的非严格模式的下绑定行为。

function foo() {  console.log( this === window); // true}
foo();

在上面的例子中,系统将 window 默认地绑定到函数的 this 上。

例二

在这里,先介绍一种我们可能会在代码中见到的显式绑定 null 的写法。

function foo() {  console.log( this == window ); // true}

foo.apply(null);

将例一默认绑定的情况,改为了显式绑定 null 的情况。

在实际开发中,我们可能会用到 apply 方法,并在第一个参数传入 null 值,第二个参数传入数组的方式来传递数组类型的参数。这是一种传统的写法,当然现在可以用 ES6 的写法来代替,但是这不在本文的讨论范围内。

在本例最需要关注的是,this 竟然指向的 window 而不是 null。个人测试的结果是,在函数独立调用时,或者显式调用,传入的值为 null 和 undefined 的情况下,会将 window 默认绑定到 this 上。

在函数多次调用,形成了一个调用栈的情况下,默认绑定的规则也是成立的。

例三

接着,探讨下严格模式下,this 的默认绑定的值。

"use strict";

function foo() {
  console.log( this === undefined );
}

foo();               // true
foo.call(undefined); // true
foo.call(null);      // false

在严格模式下,this 的默认绑定的值为 undefined。

规则四:在函数独立执行的情况下,严格模式 this 的默认绑定值为 undefined,否则默认绑定的值为 window。

5.箭头函数绑定

箭头函数实际上,只是一个语法糖,实际上箭头函数中的 this 实际上是其外层函数(或者 window/global 本身)中的 this。

// ES6
function foo() {
  setTimeout(() => {
    console.log(this === obj); // true
  }, 100);
}

const obj = {
  a : 1
}

foo.call(obj);

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log(_this === obj); // true
  }, 100);
}

var obj = {
  a : 1
}

foo.call(obj);

规则五:使用箭头函数时,this 的绑定值和其外层的普通函数(或者 window/global 本身) this 绑定值相同。

6.系统或第三方绑定

在 JavaScript 中,函数是第一公民,可以将函数以值的方式,传入任何系统或者第三方提供的函数中。现在讨论,最后一种情况。当将函数作为值,传入系统函数或者第三方函数中时,this 究竟是如何绑定的。

我们在文章一开始提到的,两个按钮例子,系统自动将 this 绑定为点击的按钮。

function changeBackgroundColor() {    console.log(this === btn1); // true}

btn1.addEventListener('click',changeBackgroundColor);

接着测试系统提供的 setTimeout 接口在浏览器和 node 中绑定行为。

// 浏览器
setTimeout(function () {
  console.log(this === window); // true
},0)

// node
setTimeout(function () {
  console.log(this === global); // false
  console.log(this); // Timeout
},0)

很神奇的是,setTimeout 在 node 和浏览器中的绑定行为不一致。如果我们将 node 的中的 this 打印出来,会发现它绑定是一个 Timeout 对象。

如果是第三发提供的接口,情况会更加复杂。因为在其内部,会将什么值绑定到传入的函数的 this 上,事先是不知道的,除非查看文档或者源码。

系统或者第三方,在其内部,可能会使用前面的五种规则一种或多种规则,对传入函数的 this 进行绑定。所以,规则六,实际上一条在由前五条规则上衍生出来的规则。

规则六:调用系统或者第三方提供的接口时,传入函数中的 this 是由系统或者第三方绑定的。

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript的起源:探索其實施語言JavaScript的起源:探索其實施語言Apr 29, 2025 am 12:51 AM

JavaScript起源於1995年,由布蘭登·艾克創造,實現語言為C語言。 1.C語言為JavaScript提供了高性能和系統級編程能力。 2.JavaScript的內存管理和性能優化依賴於C語言。 3.C語言的跨平台特性幫助JavaScript在不同操作系統上高效運行。

幕後:什麼語言能力JavaScript?幕後:什麼語言能力JavaScript?Apr 28, 2025 am 12:01 AM

JavaScript在瀏覽器和Node.js環境中運行,依賴JavaScript引擎解析和執行代碼。 1)解析階段生成抽象語法樹(AST);2)編譯階段將AST轉換為字節碼或機器碼;3)執行階段執行編譯後的代碼。

Python和JavaScript的未來:趨勢和預測Python和JavaScript的未來:趨勢和預測Apr 27, 2025 am 12:21 AM

Python和JavaScript的未來趨勢包括:1.Python將鞏固在科學計算和AI領域的地位,2.JavaScript將推動Web技術發展,3.跨平台開發將成為熱門,4.性能優化將是重點。兩者都將繼續在各自領域擴展應用場景,並在性能上有更多突破。

Python vs. JavaScript:開發環境和工具Python vs. JavaScript:開發環境和工具Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

JavaScript是用C編寫的嗎?檢查證據JavaScript是用C編寫的嗎?檢查證據Apr 25, 2025 am 12:15 AM

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript的角色:使網絡交互和動態JavaScript的角色:使網絡交互和動態Apr 24, 2025 am 12:12 AM

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C和JavaScript:連接解釋C和JavaScript:連接解釋Apr 23, 2025 am 12:07 AM

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

從網站到應用程序:JavaScript的不同應用從網站到應用程序:JavaScript的不同應用Apr 22, 2025 am 12:02 AM

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)