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