問號出頭天

Mario

剛剛掃了一下 TC39 新的草案,發現和?相關的還不少,稍微來介紹一下這幾個很初期的草案吧:首先第一個是已經見過一陣子的 Optional Chaining,第一次看到這種語法是 CoffeeScript,在 CoffeeScript 現在是叫 Existential Operator,不知道是不是以前就這個名字,對付多階層的物件特別好用:

let zip = lottery.drawWinner?.()?.address?.zipcode

可以像這樣用,中間任何一層回傳 falsy value 就會直接把值給 zip 變數,而不會繼續往下找,不會造成 Script 執行錯誤,不過目前看起來對於 function 的處理比 CoffeeScript 麻煩一點,要寫成?.(),而不是?(),其實我覺得也比較醜一些。

第二個是 Nullish Coalescing,這是正港的用來設定變數 default 值用的,以前通常的作法是用||

function (option = {}) {
  let quick = option.quick || true;
}

在上面的範例中,quick預期是 boolean 值,可能是trueflase,預期的預設值是true,不過這樣寫其實,如果傳false進來會誤判,結果會變成用預設值的true,新的 Nullish Coalescing 就是要來解決這個問題,把||換成??

function (option = {}) {
  let quick = option.quick ?? true;
}

這樣傳false時就不會被當成沒傳值,只有nullundefined才會用預設值,其實判斷的方式和第一個 Optional Chaining 一樣。

第三個是 Partial Application,其實就是字面上的意思,不過是從 syntax 上就支援 partial 執行 function:

function add(x, y) { return x + y; }

const addOne = add(1, ?); // apply from the left
addOne(2); // 3

我覺得用?這招還蠻漂亮的,雖然我還不太有機會用到 就是。


Naming Cases

Camel,

整理一下各種多單字 identifier 命名慣例(規則):

CamelCase

CamelCase 應該是最有名的了,單字的首字母大寫,其它字母小寫,然後其實還分為 UpperCamelCase 和 lowerCamelCase,UpperCamelCase 是指第一個單字的首字母大寫;lowerCamelCase 則相反,其中 UpperCamelCase 又稱為 Pascal Case,因為是 Pascal 語言當中常用的命名慣例,而因為有 PascalCase 這名稱代表 UpperCamelCase,所以也很多人直接用 camelCase 代表 lowerCamelCase;此外,也有 Dromedary Case 的講法,不過現在應該只要只剩下 Pascal Case 和 Camel Case 的說法比較有人用吧,Lower Camel Case 在 JavaScript Standard 裡面是命名變數用、Upper Camel Case 則是大部分語言推薦的建構函示和 Class 的命名慣例。

CamelCase 應該也是最早有名稱的,而且其實還有很多的別名,而除了 CamelCase 外,其它命名慣例都是有用個符號分隔單字,其中最常見到的就是 snake_case 了。

snake_case

snake_case 是用底線符號_做分隔,通常是全小寫,名稱應該由其外觀而來,是 Ruby 社群那邊出來的,應該可以算是象形文字的一個分支。在 Python 的 PEP 8 和 perlstyle 是用 snake_case 來命名 function。

MACRO_CASE

snake_case 的另一種形式是全大寫字母,因為 C 語言的 MACRO 使用,所以稱為 MACRO_CASE,偶爾有人稱之為 ALL_CAPS(不過其實全部大寫就可以稱為 ALL CAPS 了),也有一種說法叫 SCREAMING_SNAKE_CASE,通常是常數使用的命名慣例,另外像是 Bash 的環境變數、C 語言的 MACRO 等也是這個形式。

以底線為分隔的,在 perlstyle 裡面還有定義一種不常見的形式,首字母大寫加上底線分隔的 Some_Caps_Snake_Case,作為模組內的 global/static 變數,另外在 wikipedia 上有看到 Ada 語言也是用這種命名慣例,這種形式目前似乎沒有慣用的稱呼方式。

lisp-case

lisp-case 則是用連字號(hyphens)-做分隔,也一樣通常是全小寫,和 PascalCase 一樣因為程式語言 lisp 而得名,其實大部分語言都不支援 lisp-case,因為-同時是運算符號, parse 起來會蠻有問題的,除了 lisp 外我看過支援的還有 livescript,好像都還蠻偏 functional language 的,除了程式語言外,其實 URL 的路徑很常用,雖然主要是為了 SEO 效果,另外就是 HTML、XML 裡面的 attribute、id、class 也蠻容易見到用 lisp-case 的,而除了 lisp-case 這個名字外外,還有一個也很知名的稱呼是 kebab-case,和 snake_case 一樣是外觀而來的名稱。

COBOL-CASE

用連字號做分隔,但是全大寫的則是叫 COBOL-CASE,一樣是從 COBOL 語言而來。

Train-Case

以 hyphens 為分隔的,在 wikipedia 上還有看到首字母大寫的形式叫 Train-Case,不過沒有標註名稱出處,不多人用這個名稱,不過也沒其它名稱,以後應該也只有這個名稱吧,不常在程式語言內見到,Windows Power Shell 的指令是用這種規則命名的,另外一個比較常見的地方就是 HTTP Header 的 field name 了。

我自己其實是最喜歡 lisp-case,編寫 HTML 的時候 id、class 我都是用 lisp-case,次之是 snake_case,偏偏 JavaScript Standard 是用 camelCase 的,其實掙扎了一陣子,不過現在已經比較習慣一點了。

這些不同命名規則間的轉換其實有不少工具可以協助,Ian Storm Taylor 在 NPM 上有一整個系列的工具,支援很多種規則的轉換,還包括了書寫用的 Title Case,講到這個就要提一下 CSS 裡面的 text-transform 的 capitalize,其實這個屬性只處理每個單字的第一個字母,也就是說,如果你本來是全大寫的 TITLE,用 capitalize 轉換後,還是 TITLE,如果要純 CSS 方案的,其它字母轉小寫,一個單字的話勉強可以配合::first-letter來辦到,不然就是輸出到 HTML 之前要先處理過,而且,capitalize 不是 Title Case,精確的 Title Case 是不會把一些介係詞、冠詞轉大寫的,例如「I Have an Apple」裡面的 an,這問題目前就是沒有 CSS 解法,有搜尋過一下發現,沒做的主因應該是因為 Title Case 幾乎只有英語用的上。

在 Vim 上如果要轉換一個變數名稱的命名規則,我是用 switch.vim 然後加上一組自訂的轉換設定:

let g:switch_custom_definitions =
    \ [
    \   {
    \     '\<\(\l\)\(\l\+\(\u\l\+\)\+\)\>': '\=toupper(submatch(1)) . submatch(2)',
    \     '\<\(\u\l\+\)\(\u\l\+\)\+\>': "\\=tolower(substitute(submatch(0), '\\(\\l\\)\\(\\u\\)', '\\1_\\2', 'g'))",
    \     '\<\(\l\+\)\(_\l\+\)\+\>': '\U\0',
    \     '\<\(\u\+\)\(_\u\+\)\+\>': "\\=tolower(substitute(submatch(0), '_', '-', 'g'))",
    \     '\<\(\l\+\)\(-\l\+\)\+\>': "\\=substitute(submatch(0), '-\\(\\l\\)', '\\u\\1', 'g')",
    \   }
    \ ]

這組設定是MACRO_CASElisp-casecamelCasePascalCasesnake_case這樣的順序循環切換,還蠻方便的,不用花大腦思考要轉成哪種規則然後下不同指令,就一直連打-就好。

其實一開始只是在想有多少種組合才開始查的,結果幾乎一般組合都有地方使用,只差符號分隔單字加 camelCase 的兩種形式吧,最後放一些參考連結:


更之前的文章