寫在最前
人生苦短,我用 JavaScript。 然鵝,其他圈子裡還流行這樣一句話:人生苦短,我用 Python。 當然還有什麼完美秀髮程式設計,這就不提了。當你在前端學到一定地步的時候,你會有種想出去看一看的衝動,翻過這座山,去山的外面,看看外面的風景。雖然外面的風景也就那樣,但是還是忍不住去看一看(%E8%B4%B1%E5%91%97%0A)。
多說一句
作為一個不安分的 FEE,我表示就算學了忘,我還是會學的。學了忘,和從來沒有學過,是完全不同的概念。我記得有一個成語是這樣的,叫 觸類旁通。
通常我們會這樣理解,我舉個例子,比如我學習 JavaScript,我通過學習 JavaScript 來慢慢通曉其他類似的語言。但是我覺得我們還可以換種角度理解,比如我 JavaScript 學習的很好了,我想去學習 Python ,通過學習 Python 來反補我的 JavaScript ,通過 Python 的學習,使我對 JavaScript 的思考變得更深了。比如,import
等關鍵詞在 Python 中早就有了。其實我想說的是,當你學習的內容越廣泛的時候,涉獵的知識越多的時候,看待事情的格局越高的時候,你會發現,很多問題,都可以用 萬變不離其宗 來解決。嗯….這哪是多說一句,明明就是一段。。。。
恩恩,,開始探索了啦!!
出自一家門
我喜歡把其他所學的知識和前端的知識進行比較。在整個較為系統(看慕課視訊和閱讀好書)的學習了 Python 後。其實收穫還是挺多的。
其實 PY 和 JS 有很多相同的地方,一個最重要的相同點就是: JS 和 PY 都是解釋型語言。解釋型語言俗稱指令碼語言,翻開程式語言的歷史,會發現 Perl 語言的誕生是指令碼語言走向成熟的標誌,有興趣可以自行查閱資料去了解,如果想深入瞭解程式語言原理,可以看《程式語言原理》第10版,作者是賽巴斯塔。寫的非常棒!別問我為什麼,因為我以前看過了,嘻嘻。
其實解釋型語言和 Java 這種編譯型語言本質的區別就是如下一段話:
解釋型語言是不需要開發者進行編譯的,是在執行程式時才被翻譯成機器語言。而Java
這種語言是需要開發者去手動編譯的,究竟哪個好呢,其實沒法去比較,要是說效能,肯定是Java
的效能更好,因為一次編譯後,後面多次執行就可以直接執行位元組碼檔案,不需要再次編譯了。而JavaScript
、Python
這種語言,雖然效能差了點,每次執行都需要進行編譯,但是開發效率高啊,可移植性也非常好。給它一個rumtime,它送你一個快樂的人生。 而且,我是指令碼語言,我慢咋了?沒聽過電腦科學領域有一句非常 NB 的名言麼:
電腦科學領域的任何問題都可以通過增加一個間接的中間層來解決。
根據這個理論,完全可以找到一個解決解釋型語言執行慢的方法,那就是JIT compilation,翻譯一下就是即時編譯,用一箇中間層,把翻譯的機器碼儲存下來,等下次再次呼叫的時候,就直接從快取中執行之前就已經編譯好的機器碼。
JS一直在吸收PY的優點
作為指令碼行業的翹楚,PY
一直扮演著高貴的角色,PY
的設計哲學是優雅、明確、簡單。而回頭望一眼當初用了10天就發明出來的JS
,我發現JS
就好像一個白手起家的屌絲(人窮志不窮)。通過農村包圍城市的方法,一步一個腳印,最終殺出一片屬於自己的天空。
為什麼要這樣說呢,是因為我個人理解的,JS
在被創造出來的時候,並沒有給與太大期望,這也導致了很多東西在創造出來的時候沒有考慮到,比如JS
是基於面對物件進行設計的,但是卻沒有類、繼承等面對物件的語言所必須擁有的特性。而PY
從被設計之初就已經是一門面對物件的語言了。我舉個例子,JS
中的this
,有多種指向,對於剛入門前端的同學,是一個很難理解的知識點。縱觀整個OOP
(面對物件程式設計)語言,this
的指向都很明確,指向由類建立出來的物件。而在JS
中,正是因為設計之初的定位模稜兩可,說是OOP
,缺沒有實現類等特性,但又是基於面對物件進行設計的。
既然沒有在語言設計層面給出相應的關鍵字,例如class
關鍵字,如果沒有類,那JS還有什麼,那就都是函式了丫?,OOP
的不明顯,那剩下的只能OPP
(程式導向)了呀?。那這樣一來,this
的指向就會變得有多種情況,具體情況就不說了,自行查閱資料。但是呢,是時候拿出名言了:
電腦科學領域的任何問題都可以通過增加一個間接的中間層來解決。
你說沒有class
關鍵字 ? 無法實現繼承? 無法實現多型性?不存在的,我就算餓死,我也會把這個實現了。嗯….真香~~ 然後就出現了一開始的使用原型鏈來實現繼承,同時為了減少記憶體消耗,可以優化成組合繼承。其實這一切的一切,都是為了填當初設計時沒有規劃好的坑,前同事挖坑,我來填。再後面,等ES6
出來的時候,終於可以使用class
來寫OOP
了。但是這個class
也只是語法糖,說白了同事留下的坑,已經深入地心了!全世界都在用,我能怎麼辦?我內心謊的一筆,不能直接從根本上進行修改,那隻能採取靠上面那句名言了,我造一個間接的中間層來實現class
功能,其他的底層我都不動,向下相容,畢竟使用者是全世界。所以日子久了,你造一箇中間層,我造一箇中間層,然後JS
變成的越來越優雅、明確、簡潔。日子就越來越好了。
在全世界的FEE的努力下,JS一直向優雅、明確、簡潔的方向上努力前進。
JS是如何吸收PY的
吸星大法也是分等級的,吸的不好,可能會炸。
第一個關於分號這個事情:
編寫
PY
程式碼時不加分號是一個標準,使用換行符作為行程式碼結束標誌。目前JS
主流的框架都提倡不加分號。目的很簡單:簡單高效。JS
日後的標準。
第二個關於關鍵字
PY
和JS
都使用import
作為模組匯入關鍵詞
第三個關於函式
都有閉包、匿名函式,都可以使用
lamada
表示式。
這裡說一下,其實有些其他語言也有,我學習PY
的目的是為了反補JS
,讓我換個角度去看我的小可愛JS
。其實在前端,很多人搞不清楚閉包。知其然,不能知其所以然。為什麼會出現這種情況呢?
我個人認為,最主要的原因是因為閉包在JS
語言中扮演著很重要的角色,說開點就是用到閉包的地方和場景太多了,很多場景必須使用閉包才能完成,然後呢閉包在很多場景的作用也不一樣。很多剛入貴圈沒多久的寶寶,還只停留在很淺的理解上。比如防止全域性變數汙染、模組化等。並不能深入的理解到閉包在JS
中的重要作用。想透徹掌握閉包,那編譯語言原理是肯定要掌握或者瞭解的。
閉包在JS
中有多重要,我個人認為:閉包在很多語言中都存在,但JS
對閉包的依賴,超過其他任何語言對閉包的依賴。為什麼這麼說呢?我們把格局放的大一點:從程式語言原理的角度來看來閉包,閉包其實就是:
一個子程式和定義它的引用環境。也就是如果子程式可以從程式的任意位置呼叫,就需要引用環境。
中斷一下,先不看閉包,你會發現有個詞很陌生,叫引用環境。其實這裡的引用環境也叫作用域。不同叫法而已,那麼問題來了,引用環境(作用域)是什麼東東?
引用環境(作用域)是指這條語句中所有可見變數的集合。
怎麼理解這句話,其實這句話對你理解前端經常提的作用域非常非常重要,請看一個非常簡單的程式碼:
const g = 'haha'const a = 'i am godkun'function fun() {
let b = 'hello world' console.log(b + a)
}fun()複製程式碼
OK,看上面程式碼,fun()
語句的作用域是什麼?按照靜態作用域語言的特性,你要去fun
函式的程式碼執行處去看,通過fun
函式可以知道,fun
函式的作用域(引用環境)就是fun
函式體內的區域性作用域中宣告的的變數b
和全域性作用域下的變數a
的集合,這裡強調一點,就算全域性變數g
沒有被fun
函式使用。那也是算在fun
函式的引用環境裡的。
總結一下就是: 在靜態作用域語言中,語句的引用環境是在它的區域性作用域中宣告的變數,和在它的祖先作用域中宣告的所有可見變數的集合。
好了,繼續開始閉包吧,也就是如果作用域為靜態的程式語言不允許巢狀子程式,那閉包就沒有什麼用。如果允許巢狀子程式,那就支援閉包。這種允許巢狀子程式的語言中,子程式引用環境中的所有變數(其本地變數和全域性變數)都是可訪問的,無論子程式在程式的什麼地方呼叫。 這句話不好理解,我們可以以JS
為例子進行通俗闡述:
JS
是一個靜態作用域語言,同時允許巢狀子程式,如果JS
不允許巢狀子程式,那一首涼涼送給小可愛JS
啊。什麼是靜態作用域語言,官方解答就不說了,我通俗點說,就是你的JS
程式在宣告時,就已經確定好作用域了。學習過程式語言原理的應該知道 靜態作用域又叫做詞法作用域,使用詞法作用域的變數叫詞法(lexical)變數。
function say() {
let str = 'hello world' console.log(str)
} 複製程式碼
從上面可以知道,變數str
就是詞法變數。那麼最核心的本質要出來了。
詞法變數都有一個確定的作用域和不確定的生存期。
詞法變數的作用域可以是一個函式或block
,使得其在這段程式碼區域內都有效。自從JS
支援了塊級作用域(let
宣告的也不能算真正意義上的塊級作用域,不說這個了),這個block
也就成為了現實。不過為什麼說詞法變數的生存期不確定呢,是因為詞法變數的生存期取決於該變數需要引用多久。而引用多久,這是我們可以人為控制的。而人為控制總是會不靠譜的。所以就誕生了 GC 這種神器。
你會發現,從上面的靜態作用域可以知道,應該還存在動態作用域。動態作用域是什麼呢,不說了!,畢竟和JS
無關。我只說我反補的!說到這,我是不是應該寫個閉包文章,算了吧,以後再說吧。
發現說不完了
一本來想一篇搞定的,發現寫著寫著收不住了,一想到我今天9點(寫到這時間已1542994654097)還要參加VueConf
,明天還要參加上海的谷歌開發者大會。然後刺激的是今天我要5點起床做高鐵,嗯,默默的在文章標題最後加了 ——上篇, 我還是收手睡覺吧。
其實我學習PY
的目的是為了反補JS
,通過PY
來看清楚JS
。其實學習服務端語言,對前端有一個很重要的幫助,就是可以深入理解Web
程式設計中的關於網路方面的很多知識,TCP/IP 、 Socket 、HTTP等等,以及在web
安全方面,服務端是如何做的。等等吧,下篇再說吧,當然還有我學習PY
後的一次小實戰,也算是學有所用吧。雖然用途不大,但是有趣就好。
可能有人會說,Node.js
不也是服務端語言麼,為什麼不學習Node.js
,這個我要說一下,Node.js
我也學丫。比如Node.js
原始碼中就大量用到了閉包,非同步IO
操作就用到了閉包。但是Node.js
也是用JS
寫的?,我是獵奇系列,所以Node.js
不考慮在內。
PY
有裝飾器,JS
沒有,但是偉大的轉譯器Babel
可以解決這個問題,我覺得可以腦補一下,Babel
這種神器以後甚至可以統一指令碼語言。按照Babel
規定的語法規範寫,然後Babel
通過對現有的程式碼進行分析,解析成AST
,然後轉換,生成新的AST
,然後再讓直譯器去解釋新的程式碼結構。
然後你懂的,根據命令來編譯出你想要的指令碼語言。PY
和JS
結合為一體,最終變成了:
人生苦短,我愛 PS。 卒
兄得,如果你也愛 PS ,就點個贊吧,嘻嘻。歡迎關注,後續系列將更加精彩?!