iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 12
1
Modern Web

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

【這些年我似是非懂的 Javascript】Day 12 - 文法 # 趴萬

今天要來分享一下 Javascript 的文法~
什麼是文法?
對於 Javascript 來說文法就是描述他的語法,包括運算子、關鍵字等等的,如何讓他們結合在一起成為一個正確並且有效的程式的一個結構化方式。

我個人認為不用在這塊太糾結字面上的文法或是語法的詞彙爭奪戰xDD 我們一起來看看作者想傳遞的是什麼吧!


述句與運算式

以我們日常學的英語來說,述句就像是句子,運算式就像是片語,而運算子就像是連接詞或是標點符號。
直接來看一下範例

const a = 8*7
const b = a;
b;

對於 JS 來說這三個其實都是含有運算式的述句,
一二行叫做宣告述句,假使一二行把 const拿掉他們就叫做指定運算式。
那...第三行呢!?
第三行雖然只有一個運算式 b ,但他本身也可以當作一個述句被稱之為運算式述句。

述句都有完成值

你有發現...當你在使用 JS 的 REPL 時,你不管打了些什麼,當他完成該述句時他"x都會"回傳最近一次的完成值 ( 就算他是 undefined 也會)。

我自己其實有發現... 但是我不曾去查過為什麼會這樣 xDD

來看看範例就知道我在說些什麼了xDD

上面兩行的"宣告述句是回傳 undefined
而下面兩行的運算述句則是直接回傳該值,
那...如果去掉 const 的指定運算式呢?
答案跟運算述句一樣是回傳該值。

那有區塊 (block) 的完成值是什麼?
他會回傳該區塊最後一個述句或是運算式的值。

我有一個大膽的想法是將該區塊的完成值放進變數行不行!?
譬如說下面這個範例

const a = 123;
b = if(true){
        a + 123;
    }

這當你想著夢想很美好時,
然後你就會拿到一個...
Uncaught SyntaxError: Unexpected token 'if'

頓時感到現實很殘酷xDDD

不過這也不是唯一的方式去實現你想要的夢想,
你可以使用... 用了就會被撻罰和鄙視的 eval(..)

const a = 123;
b = eval("if(true){a + 123;}");
b; // 246

除了這個又醜又臭的方式沒了嗎?
還有!
ES7 提出了一個叫做 do expression 的運算式,大概長以下這樣。

const a = 123;
b = do{
        if(true){
            a + 123;
        };
    };
b; // 246

目的就是為了減少使用 eval 這東西的機會。

運算式的副作用

你知道嗎?運算式本身就有副作用!
像是下面的範例...

var a = 12;
var b = a + 5;

...你看出來了嗎?
我是看不出來啦
如果你現在憤怒,就代表你的觀念是正確的xD
運算式本身沒有副作用,主要會產生副作用的情況是在於說函式呼叫時產生的副作用,可以參考以下範例。

function foo(){
    a = a+1;
};

var a = 1; 
foo(); // 結果是 `undefined`,但是他卻直接改變了 a 這個值

除此之外還有下面這種情況可能會產生副作用

var a = 17;
var b = a++;

a; // 18
b; // 17

你可能預期原本 a 和 b 都是拿到 18 這個值,但是你忘了 ++ 他放在後綴使用會變成在該值會傳之後才會發生,反之如果放在前綴就會是你要的了~
a++ 後綴 -> 先回傳在運算
++a 前綴 -> 先運算在回傳
這樣應該會比較好理解

那...
如果我用 () 封住他行不行!?
答案是不行!
因為他沒辦法定義一個新的包裹運算式,
除了上面那個使用前綴的方式外,還有另一種方式叫做述句序列逗號運算子(聽起來真不好記xD),用法如下

var a = 18, b;
b = ( a++, a );
a; // 19
b; // 19

其實 else if 不存在

在 JS 中其實沒有 else..if 這樣的子句,像是以下範例。

if (x){
    // ...
}
else if(y){
    // ...
}
else if(z){
    // ...
}

這次沒有騙!
是說真的XD
用過 JS 的你一定知道...

if (a) {
    doSomething(a)
};

可以寫成下面這樣

if (a) doSomething(a);

or

if (a) {doSomething(a)};

那...回到剛剛的問題
所以剛剛的 else if 其實最後他是會這樣剖析...

if (x){
    // ...
}
else {
    if(y){
        // ...
    }
    else{
        if(z){
            // ...
        }
    } 
}

嗯... 我看到我也是為之驚嘆xDD

運算子的優先順序

之前提過其實 JS 的 &&|| 並不是產生 truefalse 的 boolean 值,而是選擇其中一個運算元對吧!?
沒看過回去看! (兇屁

var a = 18;
var b = 'foo';

a && b; // "foo"
a || b; // 18

兩個運算元沒爭議...
那...三個呢!?

var a = 18;
var b = 'foo';
var c = [1,2,3];

a && b || c; // ???
a || b && c; // ???

我們這一 part 就是要來了解一下運算子的優先序~
()> && > || > ?:(三元運算子)
然後 &&|| 是左結合的(也就是從左到右)
但是 ?: 這三元運算子是右結合的(也就是從右到左)
所以上面的會變成

(a && b) || c;  // 'foo';
a || (b && c); // 18;

why ?
第一個
a && b 得到 'foo',接著 'foo' || c 得到 'foo', 所以答案就是 'foo'
第二個
b && c 得到 [1,2,3],接著 a || [1,2,3] 得到 18,所以答案就是 18

這樣看起來是不是很簡單!?
來點簡單的小測驗吧
(先不要往下來看答案,自己試試看)

const a = 18;
const b = "foo";
const c = false;

const d = a && b || c ? c || b ? a : c && b : a ;

...

...

...

...

要公佈答案囉~
答案是...

18

基本上就是 && 全部先做完接著做 ||,慢慢做就海闊天空了xD
你答對了嗎?
歡迎底下留言 "我答對了",
就可以獲得我一個你好棒棒的回應。

短路

發生短路常見原因之一是電池的正極與負極被低電阻的導線連接在一起。 這時,較大的電流使得電源在短時間內提供大量的能量。 強大電流使熱量迅速的產生並大量積累,進而導致電池的爆炸或釋放氫氣和電解質。 ... 電弧是一種氣體放電現象,電流通過某些絕緣介質(例如空氣)所產生的瞬間火花。
-維基百科

開玩笑的xD
不是這種短路!
這邊的短路是對 &&|| 來說假使左手邊的運算元就可以決定結果時,右手邊的運算元其實就不會被估算或是執行,也就是走已經走捷徑出去了那後面再多也不會執行。


好!
今天分享到此結束~
下一篇還是文法~
這本書的最後一篇了!!!
啊啊啊啊!!!
寫到忘記丟垃圾 (超崩潰)

前幾天分享過我的時間規劃,
黃金讀書時間是把手機電腦相關,
會影響到你的都關靜音並且關閉,
但是我設定要倒垃圾的鬧種也隨之靜音了...
我們明天見 Orz


參考來源:

你所不知道的 JS|導讀,型別與文法 (You Don't Know JS: Up & Going)


上一篇
【這些年我似是非懂的 Javascript】Day 11 - 魔幻邪惡的強制轉型 #最終章 #隱含的強制轉型
下一篇
【這些年我似是非懂的 Javascript】Day 13 - 文法 # 趴兔
系列文
【這些年我似是非懂的 Javascript】34

尚未有邦友留言

立即登入留言