摘要:有三個重要組成部分和。參考小結(jié)函數(shù)中的是由調(diào)用函數(shù)的方式?jīng)Q定的。構(gòu)造函數(shù)中的當(dāng)構(gòu)造函數(shù)通過操作符來調(diào)用時,表示正在創(chuàng)建的對象。情況沒有明確作用對象的情況下,通常為全局對象例如函數(shù)的回調(diào)函數(shù),它的就是全局對象。
一. this的來源
this是JavaScript的關(guān)鍵字,它最初應(yīng)該是從Java、C++等面向?qū)ο蟮恼Z言中借鑒來的。
比如,在Java中沒有函數(shù)只有方法,this只能用在類的成員方法或構(gòu)造方法中,表示當(dāng)前實(shí)例對象。所以在Java中this的含義很明確,在其他語言中也類似。
然而到了JavaScript中,this變得復(fù)雜了起來:不僅函數(shù)內(nèi)可以用,在所有函數(shù)外(全局上下文中)也可以用;函數(shù)中的this的含義在函數(shù)聲明時無法確定,要到運(yùn)行期才能確定,而且與調(diào)用函數(shù)的方式有關(guān);代碼是否是嚴(yán)格模式也會影響this的取值。
二. this到底是什么在ES5.1中,有一個所謂執(zhí)行上下文(Execution Context,EC)的概念,簡單的說就是JS引擎的執(zhí)行進(jìn)入到某塊代碼區(qū)域時,為該代碼區(qū)域建立的上下文對象,主要用來記錄該區(qū)域中聲明的變量、函數(shù)等。
EC有三個重要組成部分:VE、LE和ThisBinding。前兩個是詞法環(huán)境,暫且不管。第三個 ThisBinding就是指在該代碼區(qū)域的this的值。
可見,this是跟某塊代碼區(qū)域關(guān)聯(lián)的。而在JS中,代碼區(qū)域有三種:
global代碼
function代碼
eval代碼。
此文中主要討論前兩種。
三. 全局代碼區(qū)域中的this全局代碼區(qū)域是所有函數(shù)之外的區(qū)域。在此區(qū)域中的this就是指全局對象window(在Node.js中是global)。
示例:
var num = 123; console.log(this.num); // 輸出123
參考:http://es5.github.io/#x10.4.1.1
四. 函數(shù)代碼區(qū)域中的this函數(shù)代碼區(qū)域是指某個函數(shù)內(nèi)的代碼,但是不包括它所嵌套的函數(shù)內(nèi)的代碼。從我們可以看出:
this是與包裹它的且離它最近的函數(shù)相關(guān)的,this既不能穿透到外部的函數(shù),也不能穿透進(jìn)內(nèi)部的函數(shù)。
示例:
btn.addListener("click", function() { var that = this; dosth(function() { console.log(that.name); }); });
通常每個函數(shù)中的this是不同的,內(nèi)部函數(shù)可以引用外部函數(shù)的局部變量,但是不能直接引用外部函數(shù)的this。通過將外部函數(shù)的this賦值給一個局部變量可以解決這個問題。
函數(shù)內(nèi)的this的具體函數(shù)比較復(fù)雜,主要與調(diào)用這個函數(shù)的方式有關(guān)。主要包括以下情況:
1. 直接調(diào)用時示例:
var num = 123; function fn() { console.log(this.num); } function fn2() { "use strict" console.log(this.num); } fn(); // 輸出123 fn2(); // 報(bào)錯
直接調(diào)用函數(shù)時,如果是在嚴(yán)格模式下,this會被設(shè)為undefined;如果是在非嚴(yán)格模式下,this會被設(shè)為全局對象window。
2. 作為方法調(diào)用時示例:
var student = { name: "Tom", sayName: function() { console.log(this.name); }; }; student.sayName(); // 輸出Tom
作為方法調(diào)用時,this指方法所屬的對象。
參考:http://es5.github.io/#x10.4.3和 http://es5.github.io/#x11.2.3
3. call和apply方法:調(diào)用時指定this除了上述兩種固定的情況外,Javascript提供了一種可以隨心所欲地根據(jù)需要更改函數(shù)中this方法。即使用函數(shù)對象的call或apply方法來調(diào)用函數(shù),顯然這種方式給編程帶來了極大的靈活性。
示例:
function fn() { var args = Array. prototype. slice.call(arguments, 1); console.log(args); } fn(1, 2, 3); // 輸出[2, 3]
這種方法常用的場景就是:把一個對象的方法"借"給另一個具有類似結(jié)構(gòu)的對象使用。
4. bind方法:重新綁定函數(shù)的this與call和apply不同,bind方法是在調(diào)用前就把函數(shù)內(nèi)的this綁定了,而且一旦綁定就不能再改變。實(shí)際上bind方法返回了一個原函數(shù)的新版本。
示例:
function fn() { console.log(this.age); } var fn2 = fn.bind({age: 18}); fn2() // 輸出18 fn2.call({age: 25}) // 輸出18
通過bind得到的函數(shù),不論用哪種方式調(diào)用,它的this都是相同的。
參考:http://es5.github.io/#x15.3.4.5
小結(jié):函數(shù)中的this是由調(diào)用函數(shù)的方式?jīng)Q定的。同一個函數(shù),調(diào)用它的方式不同,那么它內(nèi)部的this就可能不同。換句話說,this是動態(tài)決定的。
5. 構(gòu)造函數(shù)中的this當(dāng)構(gòu)造函數(shù)通過new操作符來調(diào)用時,this表示正在創(chuàng)建的對象。
示例:
function Person(name, age) { this.name = name; this.age = age; } var jerry = new Person("Jerry", 12); console.log(jerry.age); // 輸出12
正因?yàn)檫@個原因,我們可以在構(gòu)造函數(shù)中通過this給實(shí)例添加屬性。
參考:http://es5.github.io/#x11.2.2
6. 回調(diào)函數(shù)的this回調(diào)函數(shù)也只不過是函數(shù)的一種,實(shí)際上這種情況已經(jīng)包含在了前面提到的情況中。但是由于回調(diào)函數(shù)的調(diào)用者往往不是我們自己,而是回調(diào)函數(shù)的接收者,即某個庫或框架、甚至是JS運(yùn)行時環(huán)境。這樣一來,回調(diào)函數(shù)在中的this是什么就與對方的調(diào)用方式有關(guān)了,因此變得比較復(fù)雜,所以多帶帶拿出來討論一下。
情況1:沒有明確作用對象的情況下,通常this為全局對象
例如setTimeout函數(shù)的回調(diào)函數(shù),它的this就是全局對象。你如果希望自己指定this,可以通過bind函數(shù)等方法。
情況2:某個事件的監(jiān)聽器回調(diào)函數(shù),通常this就是事件源對象
例如:
button.addEventListener("click", fn)
fn的中的this就是事件源button對象。
情況3:某些API會專門提供一個參數(shù),用來指定回調(diào)函數(shù)中的this
例如,我們可以重新設(shè)計(jì)一個可以指定this的setTimeout:
function setTimeoutExt(cb, period, thisArg) { setTimeout(function() { cb.call(thisArg); }, period); }
另外,在ExtJS中也大量使用了可以指定this的接口。
五. eval中的this(代補(bǔ)充)
六. 重新審視this,除了面向?qū)ο笳Z言中通用的那兩種情況(方法和構(gòu)造函數(shù))外,在JavaScript 中還提供了更多的使用方式,雖然這讓JS中的this變得相對難以掌握,但是它使得JS更加豐富更加靈活。我們可以把this看成函數(shù)的一個特殊的隱含的參數(shù),這個參數(shù)代表函數(shù)正在操作的主體。
注:時間比較倉促,有些地方?jīng)]有太深入,代碼實(shí)例也比較簡單。有機(jī)會繼續(xù)完善。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/78485.html
摘要:有這樣一個熱門問題其實(shí)這個問題很好理解,關(guān)鍵要弄清下面兩個知識點(diǎn)引擎對賦值表達(dá)式的處理過程賦值運(yùn)算的右結(jié)合性一賦值表達(dá)式形如的表達(dá)式稱為賦值表達(dá)式。賦值表達(dá)式是右結(jié)合的。 有這樣一個熱門問題: var a = {n: 1}; var b = a; a.x = a = {n: 2}; alert(a.x); // --> undefined alert(b.x); // --> {n: ...
摘要:在有了基礎(chǔ)之后,進(jìn)一步學(xué)習(xí)內(nèi)容包括框架。前端學(xué)習(xí)交流群禁止閑聊,非喜勿進(jìn)。代碼提交前必須做的三個事情檢查所有變更跑一邊單元測試手動運(yùn)行一遍所有 網(wǎng)站開發(fā)開發(fā)大致分為前端和后端,前端主要負(fù)責(zé)實(shí)現(xiàn)視覺和交互效果,以及與服務(wù)器通信,完成業(yè)務(wù)邏輯。其核心價(jià)值在于對用戶體驗(yàn)的追求??梢园慈缦滤悸穼W(xué)習(xí)系統(tǒng)學(xué)習(xí): 基礎(chǔ)知識: html + css 這部分建議在?w3school 在線教程上學(xué)習(xí),邊...
摘要:在有了基礎(chǔ)之后,進(jìn)一步學(xué)習(xí)內(nèi)容包括框架。前端學(xué)習(xí)交流群禁止閑聊,非喜勿進(jìn)。代碼提交前必須做的三個事情檢查所有變更跑一邊單元測試手動運(yùn)行一遍所有 網(wǎng)站開發(fā)開發(fā)大致分為前端和后端,前端主要負(fù)責(zé)實(shí)現(xiàn)視覺和交互效果,以及與服務(wù)器通信,完成業(yè)務(wù)邏輯。其核心價(jià)值在于對用戶體驗(yàn)的追求。可以按如下思路學(xué)習(xí)系統(tǒng)學(xué)習(xí): 基礎(chǔ)知識: html + css 這部分建議在?w3school 在線教程上學(xué)習(xí),邊...
摘要:為此決定自研一個富文本編輯器。本文,主要介紹如何實(shí)現(xiàn)富文本編輯器,和解決一些不同瀏覽器和設(shè)備之間的。 對ES6Generator函數(shù)的理解 Generator 函數(shù)是 ES6 提供的一種異步編程解決方案,語法行為與傳統(tǒng)函數(shù)完全不同。 JavaScript 設(shè)計(jì)模式 ② 巧用工廠模式和創(chuàng)建者模式 我為什么把他們兩個放在一起講?我覺得這兩個設(shè)計(jì)模式有相似之處,有時候會一個設(shè)計(jì)模式不能滿...
閱讀 2421·2021-10-14 09:43
閱讀 2451·2021-09-09 09:34
閱讀 1611·2019-08-30 12:57
閱讀 1212·2019-08-29 14:16
閱讀 732·2019-08-26 12:13
閱讀 3210·2019-08-26 11:45
閱讀 2297·2019-08-23 16:18
閱讀 2674·2019-08-23 15:27