當前位置:
首頁 > 知識 > 如何讓你的 JS 寫得更漂亮

如何讓你的 JS 寫得更漂亮

網上有不少關於JS編寫優化建議,這裡我根據自己的經驗提出一些比較有用的意見。

1. 按強類型風格寫代碼

JS是弱類型的,但是寫代碼的時候不能太隨意,寫得太隨意也體現了編碼風格不好。下面分點說明:

(1)定義變數的時候要指明類型,告訴JS解釋器這個變數是什麼數據類型的,而不要讓解釋器去猜,例如不好的寫法:

聲明了三個變數,但其實沒什麼用,因為解釋器不知道它們是什麼類型的,好的寫法應該是這樣的:

定義變數的時候就給他一個默認值,這樣不僅方便了解釋器,也方便了閱讀代碼的人,他會在心裡有數——知道這些變數可能會當作什麼用。

(2)不要隨意地改變變數的類型,例如下面代碼:

第1行它是一個整型,第2行它變成了一個字元串。因為JS最終都會被解釋成彙編的語言,彙編語言變數的類型肯定是要確定的,你把一個整型的改成了字元串,那解釋器就得做一些額外的處理。並且這種編碼風格是不提倡的,有一個變數第1行是一個整型,第10行變成了一個字元串,第20行又變成了一個object,這樣就讓閱讀代碼的人比較困惑,上面明明是一個整數,怎麼突然又變成一個字元串了。好的寫法應該是再定義一個字元串的變數:

(3)函數的返回類型應該是要確定的,例如下面不確定的寫法:

getPrice這個函數有可能返回一個整數,也有可能返回一個空的字元串。這樣寫也不太好,雖然它是符合JS語法的,但這種編碼風格是不好的。使用你這個函數的人會有點無所適從,不敢直接進行加減乘除,因為如果返回字元串進行運算的話值就是NaN了。函數的返回類型應該是要確定的,如下面是返回整型:

然後告訴使用者,如果返回-1就表示不合法。如果類型確定,解釋器也不用去做一些額外的工作,可以加快運行速度。

2. 減少作用域查找

(1)不要讓代碼暴露在全局作用域下

例如以下運行在全局作用域的代碼:

有時候你需要在頁面直接寫一個script,要注意在一個script標籤裡面,代碼的上下文都是全局作用域的,由於全局作用域比較複雜,查找比較慢。例如上面的map變數,第二行在使用的時候,需要在全局作用域查找一下這個變數,假設map是在一個循環裡面使用,那可能就會有效率問題了。所以應該要把它搞成一個局部的作用域:

上面用了一個function製造一個局部作用域,也可以用ES6的塊級作用域。由於map這個變數直接在當前的局部作用域命中了,所以就不用再往上一級的作用域(這裡是全局作用域)查找了,而局部作用域的查找是很快的。同時直接在全局作用域定義變數,會污染window對象。

(2)不要濫用閉包

閉包的作用在於可以讓子級作用域使用它父級作用域的變數,同時這些變數在不同的閉包是不可見的。這樣就導致了在查找某個變數的時候,如果當前作用域找不到,就得往它的父級作用域查找,一級一級地往上直到找到了,或者到了全局作用域還沒找到。因此如果閉包嵌套得越深,那麼變數查找的時間就越長。如下:

上面的代碼定義了一個process函數,在這個函數裡面count變數的查找時間要高於局部的factor變數。其實這裡不太適合用閉包,可以直接把count傳給process:

這樣count的查找時間就和factor一樣,都是在當前作用域直接命中。這個就啟示我們如果某個全局變數需要頻繁地被使用的時候,可以用一個局部變數緩存一下,如下:

頻繁地使用了window.location對象,所以可以先把它緩存一下:

搞成了一個局變變數,這樣查找就會明顯快於全局的查找,代碼也可以寫少一點。

3. 避免==的使用

這裡你可能會有疑問了,有些人喜歡用==,有些人喜歡用===,大家的風格不一樣,你為什麼要強制別人用===呢?習慣用==的人,不能僅僅是因為==比===少敲了一次鍵盤。為什麼不提倡用==呢?

(1)如果你確定了變數的類型,那麼就沒必要使用==了,如下:

上面的兩個例子都是確定類型的,一個是字元串,一個是整數。就沒必要使用==了,直接用===就可以了。

(2)如果類型不確定,那麼應該手動做一下類型轉換,而不是讓別人或者以後的你去猜這裡面有類型轉換,如下:

(3)使用==在JSLint檢查的時候是不通過的:

如下JSLint的輸出:

Expected 『===』 and instead saw 『==』.

if(a == b){

(4)並且使用==可能會出現一些奇怪的現象,這些奇怪的現象可能會給代碼埋入隱患:

上面的比較在用===的時候都是false,這樣才是比較合理的。例如第一點null居然會等於undefined,就特別地奇怪,因為null和undefined是兩個毫無關係的值,null應該是作為初始化空值使用,而undefined是用於檢驗某個變數是否未定義。

這和第1點介紹強類型的思想是相通的。

4. 合併表達式

如果用1句代碼就可以實現5句代碼的功能,那往往1句代碼的執行效率會比較高,並且可讀性可能會更好

(1)用三目運算符取代簡單的if-else

如上面的getPrice函數:

可以改成:

這個比寫一個if-else看起來清爽多了。當然,如果你寫了if-else,壓縮工具也會幫你把它改三目運算符的形式:

(2)連等

連等是利用賦值運算表達式會返回所賦的值,並且執行順序是從右到左的,如下:

有時候你會看到有人這樣寫:

也是利用了賦值表達式會返回一個值,在if裡面賦值的同時用它的返回值做判斷,然後else裡面就已經有值了。上面的+號把字元串轉成了整數。

(3)自增

利用自增也可以簡化代碼。如下,每發出一條消息,localMsgId就自增1:

5. 減少魔數

例如,在某個文件的第800行,冒出來了一句:

就會讓人很困惑了,上面的四個常量分別代表什麼呢,如果我不去查一個那個函數的變數說明就不能夠很快地意會到這些常量分別有什麼用。這些意義不明的常量就叫「魔數」。

所以最好還是給這些常量取一個名字,特別是在一些比較關鍵的地方。例如上面的代碼可改成:

這樣意義就很明顯了。

6. 使用ES6簡化代碼

ES6已經發展很多年了,兼容性也已經很好了。恰當地使用,可以讓代碼更加地簡潔優雅。

(1)使用箭頭函數取代小函數

有很多使用小函數的場景,如果寫個function,代碼起碼得寫3行,但是用箭頭函數一行就搞定了,例如實現數組從大到小排序:

如果用箭頭函數,排序只要一行就搞定了:

代碼看起來簡潔多了,還有setTimeout裡面經常會遇到只要執行一行代碼就好了,寫個function總感覺有點麻煩,用字元串的方式又不太好,所以這種情況用箭頭函數也很方便:

箭頭函數在C++/Java等其它語言裡面叫做Lambda表達式,Ruby比較早就有這種語法形式了,後來C++/Java也實現了這種語法。

當然箭頭函數或者Lambda表達式不僅適用於這種一行的,多行代碼也可以,不過在一行的時候它的優點才比較明顯。

(2)使用ES6的class

雖然ES6的class和使用function的prototype本質上是一樣的,都是用的原型。但是用class可以減少代碼量,同時讓代碼看起來更加地高大上,使用function要寫這麼多:

使用class代碼看加地簡潔易懂:

並且class還可以很方便地實現繼承、靜態的成員函數,就不需要自己再去通過一些技巧去實現了。

(3)字元串拼接

以前要用+號拼接:

現在只要用兩個反引號「`」就可以了:

另外反引號還支持佔位替換,原本你需要:

現在只需要:

就不用使用+號把字元串拆散了。

(4)塊級作用域變數

塊級作用域變數也是ES6的一個特色,下面的代碼是一個任務隊列的模型抽象:

但是上面代碼的執行輸出是4,4,4,4,並且不是想要輸出:0,1,2,3,所以每個task就不能取到它的index了,這是因為閉包都是用的同一個i變數,i已經變成4了,所以執行閉包的時候就都是4了。那怎麼辦呢?可以這樣解決:

把i賦值給了k,由於k它是一個function的一個參數,每次執行函數的時候,肯定會實例化新的k,所以每次的k都是不同的變數,這樣就輸出就正常了。

但是代碼看起來有點彆扭,如果用ES6,只要把var改成let就可以了:

只改動了3個字元就達到了目的。因為for循環裡面有個大括弧,大括弧就是一個獨立的作用域,let定義的變數在獨立的作用域裡面它的值也是獨立的。當然即使沒寫大括弧for循環執行也是獨立的。

除了以上幾點,ES6還有其它一些比較好用的功能,如Object的assign,Promise等,也是可以幫助寫出簡潔高效的代碼。

以上列了我自己在實際寫代碼過程中遇到的一些問題和一些個人認為比較重要的方面,其它的還有變數命名、縮進、注釋等,這裡就不提及了。寫代碼的風格也體現了編程的素養,有些人的代碼看起來非常地乾淨利落,而有些人的代碼看起來讓人比較痛苦。這種編程素質的提升需要有意識地去做一些改進,有些人雖然代碼寫得很爛,但是他自己並不覺得有什麼問題。這就需要多去學下別人的代碼,甚至學一下其它語言的書寫,兩者一比較就能發現差異,或者看下這方面的書,像什麼代碼大全之類的。

作者:會編程的銀豬

原文:http://www.renfed.com/2017/04/29/effective-js-optimize/

讀前端乾貨就上前端日報

點擊展開全文

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 JavaScript 的精彩文章:

程序員和產品經理之間的默契
Adobe宣判Flash死刑:2020年停止開發和發行
千萬不要跟程序員說你的程序有BUG
用空格縮進的程序員掙得更多?
前端開發中最常用的8個npm技巧

TAG:JavaScript |

您可能感興趣

自己寫的Js,自己不認識了?
8 個問題看你是否真的懂 JS
GJSAY光晶說:噹噹網賣身!曾經的大佬走錯了哪一步?
想成為JS大牛,作用域是你必須知道的
我所不知的JS
讀者搭配 | 裸穿JSK,這些少女有心得!
小米公司突發「SJS」,雷軍沒明說,最後卻肯定是它沒錯
背著雙肩書包的可愛女孩簡直是天使!盤點JS的動漫壁紙
Sorry,會JS真的了不起
為什麼說JSON不適合做配置語言?
僅僅是小米8發布?SJS透漏的遠比你想像的多
關於 Vue.js:那些好的,不怎麼樣的和糟糕的
你為什麼不應該在JS文件中保存敏感信息?
《舉杯呵呵喝》大左說的js是誰?楊迪剛說出名字就被否認
小白都能看懂的JSON反序列化遠程命令執行
nw.js作者Roger:找到正確方向比怎麼做更重要
小鄭搞碼事:為什麼建議大家在JS代碼中,永遠不要使用with語句
關於Google發布的JS代碼規範,你需要了解什麼?
JS重做後BAN率第一,ADC變成一群孤兒,誰都可以隨便殺
小米又留懸念,「SJS」到底是啥?網友神回復