lambda 表达式中的 this 与普通情况下的 this 指向
lambda 表達(dá)式中的 this 與普通情況下的 this 指向
- Java
- JavaScript
- this 綁定
- 總結(jié)與提醒
??很多編程語(yǔ)言都支持 lambda 表達(dá)式,不過(guò)對(duì)于不同編程語(yǔ)言,其 lambda 表達(dá)式中 this 指向差異很大,有些甚至相反。下面舉例如下。
Java
??對(duì)于 Java 語(yǔ)言,很普通情況下的 this 很好理解,這里不在詳述。值得一提的是 Java 中的內(nèi)部類(lèi)。
??Java 的內(nèi)部類(lèi)有:成員內(nèi)部類(lèi)、局部?jī)?nèi)部類(lèi)、匿名內(nèi)部類(lèi)、靜態(tài)內(nèi)部類(lèi)。這里只講述匿名內(nèi)部類(lèi),因?yàn)槠渌膬?nèi)部類(lèi)中的 this 指向都不易混淆,所以從略。
-
對(duì)于 Java 中的匿名內(nèi)部類(lèi),編譯器會(huì)自動(dòng)生成它的類(lèi)名,而自動(dòng)生成的類(lèi)名為外部類(lèi)類(lèi)名$數(shù)字。而匿名內(nèi)部類(lèi)中的 this,將指向的是這個(gè)內(nèi)部類(lèi)對(duì)象。
-
對(duì)于 Java 中的 lambda 表達(dá)式中的 this,指向的是 lambda 表達(dá)式所在類(lèi)的對(duì)象。也就是說(shuō),對(duì)一個(gè)類(lèi)來(lái)說(shuō),lambda 表達(dá)式中的 this,與普通表達(dá)式中的 this,沒(méi)有任何區(qū)別。
JavaScript
??關(guān)于 JavaSript 中的 this 使用,一般分為普通表達(dá)式中的 this、匿名函數(shù)中的 this 和箭頭函數(shù)中的 this。
??注意:JavaScript 中的匿名函數(shù)與箭頭函數(shù)不是同一個(gè)東西。JavaScript 中的匿名函數(shù)又叫 lambda 函數(shù),但從形式上,JavaScript 中的箭頭函數(shù)才像 Java 中的 lambda 表達(dá)式。例如。
/*** 常規(guī)函數(shù)*/ function showName() {console.log(this.name); }/*** 匿名函數(shù)(lambda 函數(shù))*/ let showSex = function() {console.log(this.sex); }/*** 箭頭函數(shù)*/ let showAge = () => console.log(this.age);-
對(duì)于普通表達(dá)式中的 this 所處的位置,可以分為以下情況:
-
含 this 的表達(dá)式?jīng)]有位于任何函數(shù)中。在這種情況,此 this 指向?qū)ο?window(非嚴(yán)格模式下)或?yàn)?undefined(嚴(yán)格模式下)。
-
含 this 的表達(dá)式位于一個(gè)函數(shù)中。在這種情況,此 this 指向調(diào)用該函數(shù)的對(duì)象。
特別地,當(dāng) this 直接位于一個(gè)構(gòu)造函數(shù)中(即此 this 外最近一層的函數(shù)為構(gòu)造函數(shù)),此 this 指向該構(gòu)造函數(shù)所創(chuàng)建的對(duì)象(即,視調(diào)用構(gòu)造函數(shù)的對(duì)象為該構(gòu)造函數(shù)所創(chuàng)建的對(duì)象)。
注意:不能武斷地通過(guò)判斷此含 this 的表達(dá)式所處的位置來(lái)斷定 this 的指向。即,不能認(rèn)為此含 this 的表達(dá)式位于某個(gè)對(duì)象內(nèi),就認(rèn)為該 this 指向那個(gè)對(duì)象。判斷 this 的指向還需要通過(guò)判斷含 this 的函數(shù)在哪里被調(diào)用。
例如(假設(shè)下面的代碼均位于非嚴(yán)格模式下):
window.color = 'red'; let obj = {color: 'blue' };function sayColor() {console.log(this.color); }/*** 沒(méi)有使用對(duì)象來(lái)調(diào)用 sayColor(),this 默認(rèn)指向 window。*/ sayColor(); // redobj.sayColor = sayColor; /*** 使用對(duì)象來(lái)調(diào)用 sayColor(),this 指向?qū)ο?obj。*/ obj.sayColor(); // blue -
-
對(duì)于匿名函數(shù)中的 this,它與普通表達(dá)式中的 this 的指向規(guī)則是一樣的,因此此處不再詳述。
-
對(duì)于箭頭函數(shù)中的 this,其指向直接包含此箭頭函數(shù)定義的函數(shù)所屬的對(duì)象。
【注意】
-
是包含箭頭函數(shù)的函數(shù),不是包含 this 的箭頭函數(shù)。
-
“直接”指的是包含箭頭函數(shù)的函數(shù)必須是箭頭函數(shù)外的最近一層的函數(shù)。
-
當(dāng)箭頭函數(shù)沒(méi)有位于某一個(gè)函數(shù)中時(shí),此處的“函數(shù)”理解為“上下文”。
不過(guò),由于 JavaScript 中的函數(shù)的歸屬可以改變,因此此處也不能直接通過(guò)判斷此含 this 的表達(dá)式所處的位置來(lái)斷定 this 的指向,還是要看含該箭頭函數(shù)的函數(shù)被調(diào)用的位置。
例如,對(duì)于普通情況下:
window.color = 'red'; let obj = { color: 'blue' };/*** 原箭頭函數(shù)沒(méi)有位于某一個(gè)函數(shù)中,而位于全局*/ let sayColorGlobalArrowFun = () => console.log(this.color); /*** 原箭頭函數(shù)沒(méi)有位于某一個(gè)函數(shù)中,那就更沒(méi)有該函數(shù)顯式的所屬對(duì)象了,* 因此默認(rèn)所屬對(duì)象為 window。于是 this 恒指向 window*/ sayColorGlobalArrowFun(); // redobj.sayColorGlobalArrowFun = sayColorGlobalArrowFun; /*** 原箭頭函數(shù)沒(méi)有位于某一個(gè)函數(shù)中,那就更沒(méi)有該函數(shù)顯式的所屬對(duì)象了,* 因此默認(rèn)所屬對(duì)象為 window。于是 this 恒指向 window*/ obj.sayColorGlobalArrowFun(); // redfunction sayColorNorFun() { // NorFun:Normal Function/*** 原箭頭函數(shù)代碼位于函數(shù) sayColorNorFun 中*/let sayColorLocalArrowFun = () => console.log(this.color); sayColorLocalArrowFun(); } /*** 原箭頭函數(shù)代碼位于函數(shù) sayColorNorFun 中,* 而此處函數(shù) sayColorNorFun 屬于對(duì)象 window。* 于是 this 指向 window*/ sayColorNorFun(); // redobj.sayColorNorFun = sayColorNorFun; /*** 原箭頭函數(shù)代碼位于函數(shù) sayColorNorFun 中,* 而此處函數(shù) sayColorNorFun 屬于對(duì)象 obj。* 于是 this 指向 obj*/ obj.sayColorNorFun(); // blue對(duì)于將包含箭頭函數(shù)的函數(shù)作為構(gòu)造函數(shù)時(shí):
function King() {/*** this 直接位于一個(gè)普通函數(shù)中。在本文后面的調(diào)用中,其指向 King 對(duì)象*/this.royaltyName = 'Henry';/*** this 直接位于一個(gè)箭頭函數(shù)中。在本文后面的調(diào)用中,其指向 King 對(duì)象* * 注意:不能看代碼看到這里就斷定此處的 this 恒指向 window,* 要看含函數(shù) King() 被調(diào)用處附近的代碼。* 但通常情況下,可以猜測(cè) this 恒指向 window*/setTimeout(() => console.log(this.royaltyName), 1000); }function Queen() {/*** this 直接位于一個(gè)普通函數(shù)中。在本文后面的調(diào)用中,其指向 Queen 對(duì)象*/this.royaltyName = 'Elizabeth';/*** this 直接位于一個(gè)匿名函數(shù)中*/setTimeout(function() { console.log(this.royaltyName); }, 1000); }/*** 此處將函數(shù) King() 作為構(gòu)造函數(shù),因此 this 指向此處“new”創(chuàng)建的 King 對(duì)象,* 同時(shí)還調(diào)用了函數(shù) King() */ new King(); // Henry/*** 此處將函數(shù) Queen() 作為構(gòu)造函數(shù),但由于 this 位于一個(gè)匿名函數(shù)中,* 而此匿名函數(shù)將由函數(shù) setTimeout 來(lái)調(diào)用,* 而函數(shù) setTimeout 將不會(huì)使用顯式的對(duì)象來(lái)調(diào)用此匿名函數(shù),因此視調(diào)用方為 window* * 注意:此處并不是因?yàn)椤皀ew Queen()”位于全局,所以認(rèn)為調(diào)用方為 window,* 而是因?yàn)橹苯影思^函數(shù)代碼的是一個(gè)匿名函數(shù),而此匿名函數(shù)的調(diào)用方為 window*/ new Queen(); // undefined -
this 綁定
??既然 JavaScript 中普通函數(shù)與匿名函數(shù)中的 this 如此危險(xiǎn),有什么辦法可以回避這個(gè)風(fēng)險(xiǎn)呢?一種方法是改用箭頭函數(shù),如果箭頭函數(shù)所處的上下文是確定的對(duì)象,那么它的 this 指向就不會(huì)改變。
??但有些時(shí)候,需要這個(gè) this 不事先確定,這有點(diǎn)像面向?qū)ο笳Z(yǔ)言中基類(lèi)方法的 this 一樣。在 JavaScript 中,有時(shí)為了減少代碼冗余,會(huì)將一些共同代碼置入一個(gè)模塊中,供其它模塊使用,這個(gè)時(shí)候,希望 this 指向調(diào)用模塊的上下文。不過(guò)考慮函數(shù)傳遞調(diào)用(一個(gè)函數(shù)調(diào)用另一個(gè)函數(shù),而后者再調(diào)用另一個(gè)函數(shù)),這個(gè)時(shí)候判斷 this 的指向會(huì)變得很麻煩。為此,JavaScript 提供了函數(shù) bind 來(lái)終結(jié)這個(gè)判斷難題。函數(shù) bind 可以間接強(qiáng)制規(guī)定一個(gè)函數(shù)中恒定的 this 指向。
??在 JavaScript 中,每個(gè)函數(shù)都是一個(gè)對(duì)象,每個(gè)函數(shù)對(duì)象都有一個(gè)函數(shù) bind,它接收一個(gè)對(duì)象參數(shù),然后返回一個(gè)函數(shù)。返回的這個(gè)函數(shù)與自己幾乎一樣,區(qū)別是,這個(gè)函數(shù)的 this 被強(qiáng)制綁定為傳入的這個(gè)對(duì)象參數(shù)。示例如下:
window.color = 'red';var obj = {color: 'blue' };function sayColor0() {console.log(this.color); }let sayColor = sayColor0().bind(obj);sayColor0(); // red sayColor(); // blue總結(jié)與提醒
-
當(dāng)兩個(gè) this 分別位于一個(gè)普通函數(shù)和一個(gè)箭頭函數(shù)中時(shí),它們的區(qū)別是,前者的 this 指向該普通函數(shù)(在被調(diào)用時(shí))所屬的對(duì)象(調(diào)用該普通函數(shù)的對(duì)象),而后者的 this 指向包含箭頭函數(shù)定義的上下文(在被調(diào)用時(shí))所屬的對(duì)象。
-
如果把箭頭函數(shù)放置在一個(gè)函數(shù)中,則此箭頭函數(shù)中的 this 與普通函數(shù)的 this 的效果一樣的。因此,一般來(lái)說(shuō),不要把含 this 的箭頭函數(shù)放置在一個(gè)函數(shù)中,而應(yīng)該直接暴露在最外層的上下文中。這樣,此箭頭函數(shù)就永遠(yuǎn)指向當(dāng)時(shí)的上下文,而不管之后又將此箭頭函數(shù)傳遞給了誰(shuí)。
-
之所以 this 在普通函數(shù)與箭頭函數(shù)中的行為有所不同,是因?yàn)?JavaScript 中的普通函數(shù)、匿名函數(shù)(lambda 函數(shù))都屬于函數(shù),但箭頭函數(shù)不屬于函數(shù),它只是一種特殊的表達(dá)式。而在 JavaScript 中,一個(gè)函數(shù)在被調(diào)用時(shí),會(huì)為其創(chuàng)建 this 與 arguments,因?yàn)榧^函數(shù)不屬于函數(shù),所以它自己沒(méi)有 this,它的 this 只能來(lái)源于外部的 this——也就是包含箭頭函數(shù)定義的上下文。
總結(jié)
以上是生活随笔為你收集整理的lambda 表达式中的 this 与普通情况下的 this 指向的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Bean 在 Spring 中代表什么含
- 下一篇: 计算机领域中,增量是什么意思?