欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript中this機(jī)制是如何真正工作的

 更新時間:2023年11月04日 14:24:15   投稿:yin  
JavaScript中this機(jī)制提供了更優(yōu)雅的方式來隱含地“傳遞”一個對象引用,導(dǎo)致更加干凈的API設(shè)計(jì)和更容易的復(fù)用,this既不是函數(shù)自身的引用,也不是函數(shù)詞法作用域的引用,this實(shí)際上是在函數(shù)被調(diào)用時建立的一個綁定,它指向什么是完全由函數(shù)被調(diào)用的調(diào)用點(diǎn)來決定的

this 不是編寫時綁定,而是運(yùn)行時綁定。它依賴于函數(shù)調(diào)用的上下文條件。this 綁定與函數(shù)聲明的位置沒有任何關(guān)系,而與函數(shù)被調(diào)用的方式緊密相連。this 既不是函數(shù)自身的引用,也不是函數(shù) 詞法 作用域的引用。this 實(shí)際上是在函數(shù)被調(diào)用時建立的一個綁定,它指向 什么 是完全由函數(shù)被調(diào)用的調(diào)用點(diǎn)來決定的。

當(dāng)一個函數(shù)被調(diào)用時,會建立一個稱為執(zhí)行環(huán)境的活動記錄。這個記錄包含函數(shù)是從何處(調(diào)用棧 —— call-stack)被調(diào)用的,函數(shù)是 如何 被調(diào)用的,被傳遞了什么參數(shù)等信息。這個記錄的屬性之一,就是在函數(shù)執(zhí)行期間將被使用的 this 引用。

為什么要用 this?

如果對于那些老練的 JavaScript 開發(fā)者來說 this 機(jī)制都是如此的令人費(fèi)解,那么有人會問為什么這種機(jī)制會有用?它帶來的麻煩不是比好處多嗎?在講解 如何 有用之前,我們應(yīng)當(dāng)先來看看 為什么 有用。

讓我們試著展示一下 this 的動機(jī)和用途:

function identify() {
	return this.name.toUpperCase();
}

function speak() {
	var greeting = "Hello, I'm " + identify.call( this );
	console.log( greeting );
}

var me = {
	name: "Kyle"
};

var you = {
	name: "Reader"
};

identify.call( me ); // KYLE
identify.call( you ); // READER

speak.call( me ); // Hello, I'm KYLE
speak.call( you ); // Hello, I'm READER

如果這個代碼段 如何 工作讓你困惑,不要擔(dān)心!我們很快就會講解它。只是簡要地將這些問題放在旁邊,以便于我們可以更清晰的探究 為什么。

這個代碼片段允許 identify() 和 speak() 函數(shù)對多個 環(huán)境 對象(me 和 you)進(jìn)行復(fù)用,而不是針對每個對象定義函數(shù)的分離版本。

與使用 this 相反地,你可以明確地將環(huán)境對象傳遞給 identify() 和 speak()。

function identify(context) {
	return context.name.toUpperCase();
}

function speak(context) {
	var greeting = "Hello, I'm " + identify( context );
	console.log( greeting );
}

identify( you ); // READER
speak( me ); // Hello, I'm KYLE

然而,this 機(jī)制提供了更優(yōu)雅的方式來隱含地“傳遞”一個對象引用,導(dǎo)致更加干凈的API設(shè)計(jì)和更容易的復(fù)用。

你的使用模式越復(fù)雜,你就會越清晰地看到:將執(zhí)行環(huán)境作為一個明確參數(shù)傳遞,通常比傳遞 this 執(zhí)行環(huán)境要亂。當(dāng)我們探索對象和原型時,你將會看到一組可以自動引用恰當(dāng)執(zhí)行環(huán)境對象的函數(shù)是多么有用。

this的困惑

我們很快就要開始講解 this 是如何 實(shí)際 工作的,但我們首先要摒棄一些誤解——它實(shí)際上 不是 如何工作的。

在開發(fā)者們用太過于字面的方式考慮“this”這個名字時就會產(chǎn)生困惑。這通常會產(chǎn)生兩種臆測,但都是不對的。

第一種常見的傾向是認(rèn)為 this 指向函數(shù)自己。至少,這是一種語法上的合理推測。

為什么你想要在函數(shù)內(nèi)部引用它自己?最常見的理由是遞歸(在函數(shù)內(nèi)部調(diào)用它自己)這樣的情形,或者是一個在第一次被調(diào)用時會解除自己綁定的事件處理器。

初次接觸 JS 機(jī)制的開發(fā)者們通常認(rèn)為,將函數(shù)作為一個對象(JavaScript 中所有的函數(shù)都是對象?。?,可以讓你在方法調(diào)用之間儲存 狀態(tài)(屬性中的值)。這當(dāng)然是可能的,而且有一些有限的用處,但這本書的其余部分將會闡述許多其他的模式,提供比函數(shù)對象 更好 的地方來存儲狀態(tài)。

this的作用域

對 this 的含義第二常見的誤解,是它不知怎的指向了函數(shù)的作用域。這是一個刁鉆的問題,因?yàn)樵谀骋环N意義上它有正確的部分,而在另外一種意義上,它是嚴(yán)重的誤導(dǎo)。

明確地說,this 不會以任何方式指向函數(shù)的 詞法作用域。作用域好像是一個將所有可用標(biāo)識符作為屬性的對象,這從內(nèi)部來說是對的。但是 JavasScript 代碼不能訪問作用域“對象”。它是 引擎 的內(nèi)部實(shí)現(xiàn)。

考慮下面代碼,它(失敗的)企圖跨越這個邊界,用 this 來隱含地引用函數(shù)的詞法作用域:

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

function bar() {
	console.log( this.a );
}

foo(); //undefined

這個代碼段里不只有一個錯誤。雖然它看起來是在故意瞎搞,但你看到的這段代碼,提取自在公共社區(qū)的幫助論壇中被交換的真實(shí)代碼。真是難以想象對 this 的臆想是多么的誤導(dǎo)人。

首先,試圖通過 this.bar() 來引用 bar() 函數(shù)。它幾乎可以說是 碰巧 能夠工作,我們過一會兒再解釋它是 如何 工作的。調(diào)用 bar() 最自然的方式是省略開頭的 this.,而僅使用標(biāo)識符進(jìn)行詞法引用。

然而,寫下這段代碼的開發(fā)者試圖用 this 在 foo() 和 bar() 的詞法作用域間建立一座橋,使得bar() 可以訪問 foo()內(nèi)部作用域的變量 a。這樣的橋是不可能的。 你不能使用 this 引用在詞法作用域中查找東西。這是不可能的。

每當(dāng)你感覺自己正在試圖使用 this 來進(jìn)行詞法作用域的查詢時,提醒你自己:這里沒有橋。

this調(diào)用點(diǎn)(Call-site)

為了理解 this 綁定,我們不得不理解調(diào)用點(diǎn):函數(shù)在代碼中被調(diào)用的位置(不是被聲明的位置)。我們必須考察調(diào)用點(diǎn)來回答這個問題:這個 this 指向什么?

一般來說尋找調(diào)用點(diǎn)就是:“找到一個函數(shù)是在哪里被調(diào)用的”,但它不總是那么簡單,比如某些特定的編碼模式會使 真正的 調(diào)用點(diǎn)變得不那么明確。

考慮 調(diào)用棧(call-stack) (使我們到達(dá)當(dāng)前執(zhí)行位置而被調(diào)用的所有方法的堆棧)是十分重要的。我們關(guān)心的調(diào)用點(diǎn)就位于當(dāng)前執(zhí)行中的函數(shù) 之前 的調(diào)用。

我們來展示一下調(diào)用棧和調(diào)用點(diǎn):

function baz() {
    // 調(diào)用棧是: `baz`
    // 我們的調(diào)用點(diǎn)是 global scope(全局作用域)

    console.log( "baz" );
    bar(); // <-- `bar` 的調(diào)用點(diǎn)
}

function bar() {
    // 調(diào)用棧是: `baz` -> `bar`
    // 我們的調(diào)用點(diǎn)位于 `baz`

    console.log( "bar" );
    foo(); // <-- `foo` 的 call-site
}

function foo() {
    // 調(diào)用棧是: `baz` -> `bar` -> `foo`
    // 我們的調(diào)用點(diǎn)位于 `bar`

    console.log( "foo" );
}

baz(); // <-- `baz` 的調(diào)用點(diǎn)

在分析代碼來尋找(從調(diào)用棧中)真正的調(diào)用點(diǎn)時要小心,因?yàn)樗怯绊?nbsp;this 綁定的唯一因素。

注意: 你可以通過按順序觀察函數(shù)的調(diào)用鏈在你的大腦中建立調(diào)用棧的視圖,就像我們在上面代碼段中的注釋那樣。但是這很痛苦而且易錯。另一種觀察調(diào)用棧的方式是使用你的瀏覽器的調(diào)試工具。大多數(shù)現(xiàn)代的桌面瀏覽器都內(nèi)建開發(fā)者工具,其中就包含 JS 調(diào)試器。在上面的代碼段中,你可以在調(diào)試工具中為 foo() 函數(shù)的第一行設(shè)置一個斷點(diǎn),或者簡單的在這第一行上插入一個 debugger 語句。當(dāng)你運(yùn)行這個網(wǎng)頁時,調(diào)試工具將會停止在這個位置,并且向你展示一個到達(dá)這一行之前所有被調(diào)用過的函數(shù)的列表,這就是你的調(diào)用棧。所以,如果你想調(diào)查this 綁定,可以使用開發(fā)者工具取得調(diào)用棧,之后從上向下找到第二個記錄,那就是你真正的調(diào)用點(diǎn)。

到此這篇關(guān)于JavaScript中this機(jī)制是如何真正工作的的文章就介紹到這了,更多相關(guān)JavaScript中this關(guān)鍵字內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論