1. 程式人生 > >用函數語言程式設計對JavaScript進行斷舍離

用函數語言程式設計對JavaScript進行斷舍離

譯者按: 當從業20的JavaScript老司機學會函數語言程式設計時,他扔掉了90%的特性,也不用面向物件了,最後發現了真愛啊!!!

為了保證可讀性,本文采用意譯而非直譯,並且對原始碼進行了大量修改。另外,本文版權歸原作者所有,翻譯僅用於學習。

我和JavaScript

從1997年網景的Navigator 3瀏覽器開始就開始使用JavaScript。當時,JavaScript還只能做一些很簡單的事情。我記得最酷的就是用JavaScript實現mouseover特性,在那個時候已經算得上是高科技了!當滑鼠移過去之後,文字內容就神奇的改變了。因為當時都是pre-DHTML,你根本不需要隱藏或則顯示DOM元素。

關於DHTML(以前的 DHTML 如今是不是也算前端?):

DHTML是Dynamic HTML的簡稱,就是動態的html(標準通用標記語言下的一個應用),是相對傳統的靜態的html而言的一種製作網頁的概念。所謂動態HTML(Dynamic HTML,簡稱DHTML),其實並不是一門新的語言,它只是HTML、CSS和客戶端指令碼的一種整合,即一個頁面中包括html+css+javascript(或其它客戶端指令碼),其中css和客戶端指令碼是直接在頁面上寫而不是連結上相關檔案。

在那個時候,JavaScript的演化很慢,主要應用在表單驗證。因此,不像今天這麼火爆,並沒有引起太多的關注。可以說只是一個錦上添花的附加物,你需要確保在瀏覽器禁用JavaScript之後,你的應用依然可以正常使用。再往後,框架一個接著一個出現:jQuery,Knockout, Angular, React, Vue, 等等。

同樣,JavaScript也在加速演化。我們才使用ES6不久,現在人們幾乎已經跳過ES7,開始討論ES8了。

並且,我們有很多替代品,比如TypeScript,CoffeScript,ClojureScript, ELM,等等。

我們已經被太多的框架和語言所淹沒,很難去跟蹤和掌握所有的語言和框架。

錯誤路線

當JavaScript逐漸成熟,面向物件程式設計(OOP)的概念也滲入進來,而且我曾經很喜歡。

我開始嘗試所有不同的方法來建立類,我最終也可以正確的使用繼承。我對自己說:JavaScript開始真的像一個語言了!

但是,直到多年以後我發現OOP是JavaScript引入的最糟糕的一個設計!

我嘗試將我對C#的理解帶入到JavaScript中去。一開始充滿期待,但是後來發現真的太複雜,太燒腦了。

這主要是因為JavaScript的原型繼承和C#不一樣,我已經習慣於每天編寫類似於console.log(this)這樣飄逸的程式碼。但是現在呢?如果我一不小心沒按照規則來,那將會給我帶來噩夢。私有方法和私有值必須要在名字前面加上下劃線,甚至必須用閉包來保證私有性。

因此,不僅OOP導致了很多問題,同時也由於新增OOP帶來了很多新的問題。

函數語言程式設計

一開始我並不理解。我可以閱讀並理解這些用函式式編寫的程式碼,但是不知道為什麼!最終,我強迫我自己去學習它。我在線上教育網站EDX免費學習了函式式語言的入門課程,然後嘗試把這些技術運用到JavaScript中去。

函式式語言給了我一個全新的視角,讓我從一個完全不同的方式去看待程式設計。

一開始會感到不自然,需要時間去適應。所有的定義都是基於函式,值不可更改,無狀態。我用函式式的思維去解決問題。因為不熟悉,我花了更長的時間去學習。漸漸地,我熟練掌握了使用函式式的方法去程式設計。並且,我也知道所有程式碼這樣編寫的內在含義。

我的程式碼更加簡潔了,而且容易複用。漸漸的,我以前使用的那些語言特性從程式碼中消失了,我的程式碼看上去完像是用另一個語言編寫。我還在用JavaScript嗎?

1. 不再使用var

我用const替代了var。通過函式式的設計,我的函式都是純(pure)的。不會再去對一個變數進行值的變更操作,同樣也是為了確保不會對其操作。

我會檢查程式碼確保每一個var,甚至let,所有宣告都使用const

2. 沒有for迴圈

在學習程式語言的時候,我們一開始就會學到for迴圈。但是自從學習了函數語言程式設計,我將for迴圈都改成了使用filter, map和reduce來實現。對於那些需要一些額外計算的需求,我會使用遞迴或則第三方庫比如lazy.js

在此,推薦我的另外一篇專門介紹for迴圈部落格:[Rethinking JavaScript: Death of the For Loop](Rethinking JavaScript: Death of the For Loop)

如今我的程式碼裡面完全沒有for迴圈了,如果你看到了,告訴我我會把它消除。

3. if也可以被簡化

我開始停止在if裡面編寫大塊大塊的程式碼。我將裡面的邏輯抽取出來單獨放在一個函式中。這樣,我們就可以將if用三元運算元(a?b:c)來簡化。

在此,推薦我的另外一篇專門介紹if部落格:Rethinking JavaScript: The if statement

如今我的程式碼裡面幾乎沒有if語句。為了方便其他開發者理解我的程式碼,我很少使用它。

4. 和switch說拜拜

同樣,我也不喜歡用switch,而是尋找一個函式式的寫法。

推薦我的部落格: Rethinking JavaScript: Eliminate the switch statement for better code

我也很喜歡用Ramda的cond運算元來替代swtich。

5. 不在擔心this

對的,你沒有聽錯!我們也可以完全消除this

函式式的JavaScript可以讓你完全拋棄使用煩人的this

現在只有資料和函式,甚至資料不過是函式的一種特殊表達形式,你再也不需要this了。我開始將物件理解為函式式語言中狀態(state)和函式。我甚至不需要把狀態或則函式和物件繫結到一起,就像OOP中那樣。

我寫了一篇部落格專門介紹如何解耦: Functional JavaScript: Decoupling methods from their objects

面向物件的設計不是必須的

現在往回看,我發現面型物件程式設計帶來的複雜度真的是不必要的。我可以使用函式式語言實現同樣的功能,完成相同的任務。而且,程式碼更加輕簡,因為不在需要將這些複雜的物件傳來傳去。只有資料和函式,而且因為函式沒有和物件繫結,更加容易複用。我不在需要擔心傳統的原型繼承帶來的所有的問題,JavaScript設計的並不好。

JavaScript缺乏私有、公有、內部或則被保護這類訪問控制器也不再是一個問題。訪問控制器是用來解決由於引入面向物件程式設計而設計的。在函式式的JavaScript中,這些問題不復存在。

總結

我的程式碼現在看上去完全不同。它包含了很多純函式,我將它們做成不同的ES6模組。這些函式可以被使用來構建更加複雜的函式。很大一部分函式都是很簡單的一行lambda表示式。

現在我看待軟體的思維也變了:輸入是一個數據流,然後程式作用到該資料流上對資料進行各種操作,然後返回新的資料。

函式式設計對程式語言的影響以及無處不在,C#中的LINQ就是一個最佳的例子。同樣Java 8也引入了函式式語言的特性。

關於Fundebug

Fundebug專注於JavaScript、微信小程式、微信小遊戲、支付寶小程式、React Native、Node.js和Java實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了7億+錯誤事件,得到了Google、360、金山軟體、百姓網等眾多知名使用者的認可。歡迎免費試用!

用函數語言程式設計對JavaScript進行斷舍離

版權宣告

轉載時請註明作者Fundebug以及本文地址:

https://blog.fundebug.com/2017/09/13/how-i-rediscovered-my-love-for-js/