Day08 JavaScript Scope & Context

更新 發佈閱讀 9 分鐘


Scope(作用域

不只是JavaScript,scope的概念在每個程式語言裡面都有,但每個語言scope運作邏輯多少有差異。

我們先來舉個例來了解scope:

vocus|新世代的創作平台
vocus|新世代的創作平台

隨著myFunction()執行,這段程式毫無疑問的console.log()出了myName這個變數的值’my name’

但如果我們稍微調整console.log()以及變數定義的位置,情況會變得有所不同。

vocus|新世代的創作平台
這樣寫就會出現錯誤。

這樣寫就會出現錯誤。

如果我們將myName的宣告寫在function內部,則在外面的console.log()就無法取得myName這個變數,所以會出現錯誤顯示myName沒有被定義。


我們明明在function內定義了myName在外部卻不能使用,這就是因為它所在的scope和外部的scope不同,而且外部的scope不能存取內部的scope。它們的關係就像這樣:

vocus|新世代的創作平台

比較小的scope就像一個小包廂,不能隨意進入。但包廂內的人隨時可以走出來看看外面。這就是為什麼在外面的console.log()存取不到myName,它不能隨意闖入別人的包廂。

以這個例子來說,function內{}包起來的範圍就自己成為一個scope了,被稱為一個block scope


不只是function可以形成scope,在大多數情況下,使用{}包起來的範圍都會自成一個scope。我們刻意用if結構來創造第二層的scope。

vocus|新世代的創作平台

目前我們有兩個內部的scope,一個在function內,另一個在if內。目前這樣寫也都是正常運作的,因為內部的scope可以存取外部的scope內容。另外,最外層被稱為global scope


我們再稍微改寫一下這個例子:

vocus|新世代的創作平台

我們多宣告了兩次myName,並且在不同的scope裡都用console.log()印出來。JavaScript會尋找同一個scope裡面有沒有myName,沒有的話才會繼續往更外層(更大的scope)尋找。

vocus|新世代的創作平台

在現在的情況裡,if那一層scope有myName會印出”my name 2”、function那一層scope也有myName會印出”my name 1”,而global scope則會印出”my name”


請注意,這並不是內部的myName覆蓋掉了外部的。用let關鍵字表示要新增一個變數,就算新變數的名稱和先前定義過的一樣,在JS裡也是可行的。換句話說,在上面例子裡看到的3個myName,就只是3個名字剛好一樣,毫無關係的變數。這是JavaScript scope跟變數的運作方式,在其他語言可能不適用。


如果想要複寫掉原本定義過的myName的話,可以這樣寫:

前面沒有新的let,JS尋找之前定義過的myName並且覆蓋掉它。

前面沒有新的let,JS尋找之前定義過的myName並且覆蓋掉它。

可以注意到在if那層的scope裡,少了let這個關鍵字。這時候JS會做的就不是產生新的變數,而是尋找之前有沒有myName,在同一個scope找不到,就會接著往上層scope找,然後更新它。

這種情況下,所有的myName都被更新成"my name 2"。

這種情況下,所有的myName都被更新成"my name 2"。

在這個例子中,我們保留了所有的console.log(),由於myName被更新了,就只會印出”my name 2”這個值。這和上個例子其實就只差了let,但結果完全不一樣!


letvar

常見的JavaScript宣告關鍵字除了let還有var,在比較早期的JavaScript裡面,開發者幾乎只能用var來宣告變數,但後來推出了let這個關鍵字。這兩個關鍵字有一些些微的差異,最重要而且最大的差別就是它們適用的scope不同。


let如剛才提到的,是block scope,只要有新的{}就會產生新的scope,
var是function scope,只有function內的{}才會產生新的scope。


讓我們舉例說明。

vocus|新世代的創作平台

我們同樣用剛剛製作一個function裡面在「用if製作另一個scope」的情境為例。對insideIfLet來說if裡面是一個新的scope,新的包廂,所以在外面的console.log()會失敗,它不能存取內部的變數

但詭異的是,使用var在這種情況下console.log()卻可以正常的運作。原因是var 來說,只有function的{}才會開闢新scope,if內的{}不是。

用let時,if{}被視為新的scope,而外部不能存取內部scope,所以出錯。

用let時,if{}被視為新的scope,而外部不能存取內部scope,所以出錯。


好的我知道非常奇怪,不知道為什麼JS的設計師要這樣設計。其實簡單的建議就是不要用var,很多情況下工程師很難直接判斷怎樣的{}是來自function,判斷這件事也會花費很多不必要的時間。使用var會造成scope變得更複雜,還幾乎沒有必要。相較之下,使用let時只要看見{},就能判斷那是一個新的scope,對於自行回顧程式或溝通協作都非常有幫助。

Context

在JavaScript中,還有一個容易讓人混淆的關鍵字叫this,它的代表的值會隨著程式碼執行的環境(context)而改變。不同的context下,this可能指向不同的對象,搞清楚這件事就是我們這個今天的目標。


我們先考慮這個userobject:

vocus|新世代的創作平台

這個object叫做me,裡面包含firstNamelastName兩個property,還有一個method叫做eat(),它的功能單純就是印出一串string。

vocus|新世代的創作平台


目前eat()是寫死的,不能根據名稱動態的調整。我們現在希望可以讓eat()存取到firstName以及lastName,這時候就可以用this這個關鍵字。

vocus|新世代的創作平台
vocus|新世代的創作平台

而這正是this被設計的目的 — 存取同一個object內的property或是method。滿好理解的,看起來沒什麼問題對吧?但問題就是這個this的運作模式很多時候真的讓人混淆。


我們看看下面的例子。

vocus|新世代的創作平台

我們在eat()裡面再多定義一個functionhungry(),定義完之後馬上使用它。

vocus|新世代的創作平台

這時候卻會出現這個結果,this.firstNameundefined,我非常確定沒有打錯字。


這是因為this指向的是「呼叫這個function的object」。以上面的例子來說me.eat()就是me在呼叫eat()eat()內用到的this就是me。但你可以看見hungry()前面並沒有誰在乎叫它,它不是me.hungry()或類似的寫法。這時候hungry()this指的就是程式碼最外層的context(我們會稱作global context,在瀏覽器裡面是Window這個object),反正不是me


關於Window的資訊現在先聽聽就好,總而言之,在一個function前面,呼叫它的角色,就代表this的值。現在你大概知道這個關鍵字有多擾人了。


順帶一提,如果我們是可以調整剛才那個hungry()內的this指向的。

我們指定讓me來callhungry(),它裡面的this就會是me了。

我們指定讓me來callhungry(),它裡面的this就會是me了。

vocus|新世代的創作平台

用每個function內建的methodcall()bind()apply()也可以),就可以指定this的指向。


當然,我們還有其他辦法可以解決這個this難題,之後會提到。

小結

說了這麼多關於scope和context的內容有點讓人混亂,不過今天只是希望給大家一點概念,不是真的要熟悉每一個細節。重點是在JavaScript裡面,scope和context非常容易讓人混淆(特別是this),在某些比較複雜的情境,資深人員也需要一點時間來搞清楚scope和context的問題。現在的目的是讓大家認識,並且在日後遇到找不出原因的bug的時,可以想到是scope和context的可能性。隨時都可以用console.log()來確認得到的值是不是如預期。


明天我們會討論更多JavaScript裡常見的寫法與其特殊規則,正是因為有這些內容的存在,第一次看到JavaScript才容易不理解,在明天的內容之後,至少能夠看懂那些簡寫是發生了什麼事。


Resource

今日Codepen

連結

Credits

關於我

我是Erkin, 一個網站開發者。
有任何疑問或是想勘誤的話歡迎聯繫。

留言
avatar-img
HCY 71的沙龍
0會員
11內容數
HCY 71的沙龍的其他內容
2024/11/04
這個單元裡我們會繼續用Codepen來製作簡單的To-Do List app。裡面會使用到基本的HTML和CSS來製作UI,別擔心會非常簡單。示範的Codpen同樣會附在今天的內容裡面,如果想看成果的話可以直接點前往。 基礎架構 為了完成這個web app,我們必須先理解HTML、CSS之間
Thumbnail
2024/11/04
這個單元裡我們會繼續用Codepen來製作簡單的To-Do List app。裡面會使用到基本的HTML和CSS來製作UI,別擔心會非常簡單。示範的Codpen同樣會附在今天的內容裡面,如果想看成果的話可以直接點前往。 基礎架構 為了完成這個web app,我們必須先理解HTML、CSS之間
Thumbnail
2024/11/04
在JavaScript裡面,Async和Await應該是搜尋熱度最高的關鍵字了,因為他們相對複雜。我們一步步討論這件事的歷史 — 它們為什麼出現,解決了什麼問題。 JavaScript的Synchronous(同步) 首先我們必須了解JavaScript執行的基本原則 — synchrono
Thumbnail
2024/11/04
在JavaScript裡面,Async和Await應該是搜尋熱度最高的關鍵字了,因為他們相對複雜。我們一步步討論這件事的歷史 — 它們為什麼出現,解決了什麼問題。 JavaScript的Synchronous(同步) 首先我們必須了解JavaScript執行的基本原則 — synchrono
Thumbnail
2024/11/04
今天要談的內容也是JavaScript很核心的部分,即使學完了先前的章節,馬上去看別人寫的JavaScript程式碼還是會看不懂,主要是因為JS開發者會採用各種簡化和替代的寫法,我們一一討論。 Anonymous(匿名) Function 首先我們要討論的是Anonymous(匿名) Fun
Thumbnail
2024/11/04
今天要談的內容也是JavaScript很核心的部分,即使學完了先前的章節,馬上去看別人寫的JavaScript程式碼還是會看不懂,主要是因為JS開發者會採用各種簡化和替代的寫法,我們一一討論。 Anonymous(匿名) Function 首先我們要討論的是Anonymous(匿名) Fun
Thumbnail
看更多
你可能也想看
Thumbnail
本章節旨在介紹TypeScript中的函數,包括其基本結構、如何呼叫函數、函數的參數以及函數的返回值等相關概念。通過本章節,讀者可以學習到如何在TypeScript中使用不同的方式來定義函數,如函數聲明、函數表達式、箭頭函數和匿名函數等。
Thumbnail
本章節旨在介紹TypeScript中的函數,包括其基本結構、如何呼叫函數、函數的參數以及函數的返回值等相關概念。通過本章節,讀者可以學習到如何在TypeScript中使用不同的方式來定義函數,如函數聲明、函數表達式、箭頭函數和匿名函數等。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
JSDoc 全名是 JavaScript Documentation,顧名思義是為 JavaScript 所使用的 API 文件,在程式碼內透過註解的方式撰寫,運行後 JSDoc 會自動掃描註解內容,並生成一份網頁版的文件,對於沒有使用 Typescript 開發的專案,也
Thumbnail
JSDoc 全名是 JavaScript Documentation,顧名思義是為 JavaScript 所使用的 API 文件,在程式碼內透過註解的方式撰寫,運行後 JSDoc 會自動掃描註解內容,並生成一份網頁版的文件,對於沒有使用 Typescript 開發的專案,也
Thumbnail
本章節旨在介紹TypeScript的基本語法,包括一般結構、程式進入點、註解以及變數的定義和賦值。這些知識將幫助讀者瞭解TypeScript的基本架構,並且可以開始使用TypeScript進行開發。
Thumbnail
本章節旨在介紹TypeScript的基本語法,包括一般結構、程式進入點、註解以及變數的定義和賦值。這些知識將幫助讀者瞭解TypeScript的基本架構,並且可以開始使用TypeScript進行開發。
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News