iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 15
0
Modern Web

【這些年我似是非懂的 Javascript】系列 第 15

【這些年我似是非懂的 Javascript】Day 15 - 語彙範疇

範疇的運作方式主要有兩種模型,
第一種就是今天的主題語彙範疇
是大多數的程式語言所用的,
第二種叫做動態範疇
它則是少數語言(Bash, Perl 的某些模式)使用的。
接著我們就來好好的跟他交朋友吧

語彙分析時期

昨天那篇有提到傳統編譯式語言通常的三步驟的第一步就是 lexing 也就是語彙分析
而語彙範疇就是在這個時期所定義的範疇(聽起來有點繞口),而這範疇其實就是你在寫 code 時所編寫的"變數"和"區塊",

範疇泡泡

我自己在高中的時候,計概老師都叫他 Block ,那年夏天老師溫柔的握著我的手把 Block 畫出來的那種感覺。
(做夢中)


如圖所示
Bubble 1 最外圈就是全域範疇
Bubble 2 包含 foo 的範疇
Bubble 3 包含 boo 的範疇

Bubble 1 包含 Bubble 2 + Bubble 3
Bubble 2 包含 Bubble 3
這樣應該就知道了吧!

查找

由上面的範疇泡泡可以知道結構與相對位置,而最內層的 console.log,就會一路從最內層開始找,找到最外層直到只要找到"第一個符合",就會停止查找,
不管該函式在哪邊""用,語彙範疇只會管你在哪被宣告的。

欺騙語彙範疇

JS 有兩個機制是會影響到語彙範疇的,而且在社群上已經被唾棄,幾乎是完全不建議使用。

  1. with
  2. eval (這大家應該都熟悉)

那我們就先從 with 來看看吧

with

我自己之前沒看過和用過,並且已經棄用了,他主要是讓我們可以對一個物件進行多次參考,而不用每次都一直參考該物件本身。

範例
正常情況下

obj.name = 'robin';
obj.age = '18';
obj.phone = '0912345678';

使用 with

with(obj){
    name = 'robin';
    age = '18';
    phone = '0912345678';
}

看起來不錯啊!?
真放便而且清楚明瞭。
但是他被唾棄且棄用...
why!?
因為...
他的霸氣會外漏

來看看下面的範例

function foo(){
    with(obj){
        a = 3;
    }
}

var obj1 = {
    a = 4;
}

var obj2 = {
    b = 4;
}

foo(obj1);
console.log(obj1.a); // 3

foo(obj2);
console.log(obj2.a); // undefined
console.log(a); // 3 shit 變成全域變數了

看到這你一定會想說...

原因是這樣~
第一個 obj1 本身就有 a 這個特性,
而第二個 obj2 沒有 a 這個特性...
然後...
它就直接略過 witha 做正常語彙參考一樣直接往外找,
找不到 a 直接幫他建了一個 a 並且塞 3 這個值給他。

不過這樣講起來,經過昨天的 LHSRHS 的講解後,其實你就已經有一個底直接開啟嚴格模式,其實就不會發生這類型的 side effect 了。

eval

我以前用過 Orz... 而且被糾正過。
但是其實我當初也不太知道為何不能用,那我們就一起來看看他有些什麼問題吧。

eval 的主要用途是在於他可以把一段 String 轉為程式碼,並且可以正常執行。

eval('console.log('hi')') // hi

那他為何被唾棄?
因為他在一開始的時候 Engine 不會知道他的內容造成他欺騙語彙範疇,就有點類似半路殺出程咬金的感覺xD
來看看範例吧

function foo(str, a){
    eval(str);
    console.log(a,b); // 8,6
}

var b = 7;

foo('var b = 6',7);

原本你以為的結果會是 8,7,結果突然因為 eval 導致結果變 8,6,與你預期的不符合。

效能

不管事 eval 還是 with,他們都是在執行的時候才修改或建立新的語彙範疇,
之前提過 JS 在編譯階段會做各種最佳化,那當他們遇到上述兩個的時候,他們會直接略過不管,不會去解析裡面的內容,導致最佳化的時候沒有被最佳化所以效能會變比較差...

以上是今天的內容
感謝您的收看
如果喜歡請按讚訂閱加分享
明天見~


參考來源:

你所不知道的 JS|範疇與 Closures,this 與物件原型 (You Don't Know JS: this & Object Prototypes))


上一篇
【這些年我似是非懂的 Javascript】Day 14 - 範疇
下一篇
【這些年我似是非懂的 Javascript】Day 16 - 函式的範疇
系列文
【這些年我似是非懂的 Javascript】34

尚未有邦友留言

立即登入留言