javascript
range作用于对象global失败_彻底弄懂JavaScript作用域问题
這幾次都是些的基礎文章,可能好多人會說基礎不太重要,做前端這么久,也沒用到多少基礎 (首先恭喜你,已經進提前進入了被優化名單)。
下面我們來詳細解答一下基礎是什么。
let 知識, 基礎 if (知識 === '房子') {基礎 = '地基' } if (知識 === '大樹') {基礎 = '樹根' } if (知識 === '天空') {基礎 = '階梯'console.log('基礎 makes you up, up, up…… 直到你碰頭') } ………………怎么樣?認識到基礎的重要性了吧,如果沒有了基礎,代碼就好像無根之木,空中樓閣,雖然賞心悅目,但總是短暫的。
直到你真正領悟了底層是怎么運作的,你才能夠真正做到 他強任他強,清風拂山崗;他橫自他橫,明月照大江。
扯遠了,收~
回到我們的正題。今天帶大家了解以下 JavaScript 中的作用域問題。請拭拭拭拭拭拭目以待。(自己 get 重點)。
先從最基礎的開始講起。
1.什么是作用域
作用域是什么這個問題,好多人都回答不好。請注意:通常來說,作用域就是限制一個變量在程序中的使用范圍。
搜嘎,突然有一種 “同行十二年,不知木蘭是女郎” 的趕腳。
1.1 全局和局部
了解了作用域的名字來由之后。我們來認識一下它。
在 JavaScript 中作用域的邊界是以函數劃分。有 全局 和 局部 作用域之分。
- 全局作用域:聲明在全局的變量或者不使用var聲明的變量在整個程序中都是可用的,所以叫全局作用域。
- 局部作用域:聲明在函數體內的變量,在整個函數執行環境和其子函數內都是可用的,但是在函數外訪問不到,所以叫局部作用域
小栗子 同學上場:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> </body> </html> <script>var global = "我是全局變量,全局都能看到我";global2 = "我也是全局變量,全局都能看到我";function getName() {var name = "我是局部變量,只能在getName函數內才能找到我"} </script>1.2 預解析和變量提升
看到標題的同學是不是會稍有一愣。預解析是什么玩意兒?變量提升又是啥?(知道答案的同學請配合這個無聊的作者一下,假裝一愣神。)
咳咳~不忙,等本大神(經)來解釋一下。
預解析是在程序執行之前,會進行一遍預檢。查找當前作用域內由 function 和 var 。并且每次更換作用域都會在此作用域中執行預解析
變量提升是指,在查找到由 function 和 var 后,首先在當前作用域的頂端定義好并賦給默認值。var的默認值為 undefined, function的默認值為函數本身。
注:
? 像 var getName = function() {} 這種代碼會被當做變量定義,而不會當做函數定義。
“讓一下,讓一下……” 遠處小栗子攜大量代碼滾滾而來~~
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> </body> </html> <script>console.log(global) // undefinedconsole.log(getName) // function getName(){}var global = 1;function getName () {} </script>誒?怎么這樣?我不是定義了global嗎?怎么會輸出 undefined 難道是javascript出現了bug?
不要多想,預解析和變量提升的過程中,并不會將變量賦值,而只是定義,等真正執行的時候才會賦值。修改一下代碼,在global變量下方再次打印。
var global = 1; console.log(global); // 1解釋:當執行到打印函數的時候,global已經被賦值為 1。此時已經在執行代碼的階段,而不是在預解析階段。
先練練手:
猜想一下,下方程序如何輸出。
console.log(a) // 1 var a = 1; console.log(a) // 2 getName() function getName () {console.log(a) // 3console.log(b) // 4a = 2;console.log(a) // 5var b = 3;console.log(b) // 6function b(){} }此時你的答案是什么呢?
針對上方代碼,通過圖解的方式看下預解析的執行過程。
ps:(上圖畫的太復雜,看完需要耐心)
1.3 var和function的優先級
細心地同學可能會發現一個問題,上面的代碼,在getName函數中,我既定義了 b變量,也定義了 b函數。為什么在 console.log(b) // 4 的時候會輸出 undefined?
因為在預解析的過程中,會先查找 function 然后再查找 var 所以,function 會被 var 覆蓋。這里我們會理解為 在預解析過程中,function的優先級高于var。高優先級的會被低優先級的覆蓋 (是不是很繞?沒關系,多想想,加深下理解)
2.作用域鏈
作用域鏈的執行我們在之前就講過了,有沒有人注意到?有沒有?
好吧,沒有人回答我,看來是沒人注意到了。
就在練手代碼中,getName()函數內,向上查找 a 變量的過程,那個就是作用域鏈的查找過程。
閑言少敘,上高清大圖:
特別注意:作用域只能從下向上查找,不可逆向。(從函數外不能訪問函數內的變量)
3. 從全局獲取函數內部的變量
上面講到,在函數外訪問函數內的變量是訪問不到的,如果我堅持要訪問呢?(一般情況下,這種鉆牛角尖的人都容易挨打)。
好吧,既然你要訪問,那也是有方法的,我們可以在函數內將變量返回出來,這樣就可以訪問到函數內的變量了。
多說無益,還是代碼最實在:
console.log(getA()); // 通過這種方式,我們就可以訪問到 a 變量。function getA() {var a = 1;return a; }發散一下思維,你還知道其他方式嗎?
4. 塊級作用域
在ES6到來的時候,javascript迎來一個全新的概念,-- 塊級作用域。顧名思義,塊級作用域可以讓變量只在一塊代碼內生效。
舉個栗子:
{var a = 1 } console.log(a)上述栗子中的代碼會正常輸出,但是下方的代碼會拋出 a 變量未定義的錯誤a is not defined。
{let a = 1; } console.log(a)也就是說a變量只在花括號內生效,在花括號外是訪問不到的。
可以聲明塊級作用域的方式有兩種。let 和 const 。
目前為止,我們看到了三個定義變量的方式,接下來,讓我們瞅瞅他們之間的不同。
4.1 var、let、const的異同
同: 都可以聲明變量。
異:
var 存在局部作用域,可變量提升,聲明的值可更改。
console.log(a) var a = 1; a = 2; // 上述操作都可以let 存在塊級作用域,不可變量提升,聲明的值可修改。(只可以先聲明變量,然后再使用)
console.log(a) // 會報錯, a is not defined let a = 1; a = 2;const 存在塊級作用域,不可變量提升,聲明的值本身不可修改(只可以先聲明變量,然后再使用)
const a = 1; a = 2; // 會報錯,a不可修改// 下述情況可運行 const a = [] a[0] = 1;注意:
- const聲明的叫做常量,不可以修改其本身,但如果聲明的是復雜類型的對象,對象里的值是可修改的。
這里你會發現一個問題,三者的功能是逐步增強的。
4.2 TDZ介紹(暫時性死區)為什么let和const不能變量提升。
使用let和const聲明的變量,在預解析的時候會將變量放入到一個暫時不可訪問的區間中,此時訪問變量會提示未定義錯誤,在給變量賦值后,將變量放入到正常的執行環境中。使變量可以正常訪問。
console.log(a) // 此時的a在TDZ中 let a = 1; // 將a從TDZ中移出來 console.log(a) // 此時可以正常訪問a變量相信你現在已經充滿能量,打開你的代碼,學會分析每一步的執行順序吧。
總結
以上是生活随笔為你收集整理的range作用于对象global失败_彻底弄懂JavaScript作用域问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 罗马音平假名片假名转换器_记不住五十音的
- 下一篇: 我的新书终于写完了。