javascript
前端判断session对象是否为空_谈谈JavaScript这个语言与前端是否需要面向对象?...
事實上,一個語言是否流行與它是否優秀沒有任何關系。JS綁架了整個Web前端,而我們又沒有其他的選擇。 ——題記
最近這兩年用JavaScript用的比較頻繁。一是2017年時開始制作小程序課程;二是2018年開啟了Lin-UI和Lin-CMS,無論哪個開源項目,都嚴重依賴JS;再加上5.6日上線的NodeJS&KOA新課程,JS就像個502固體膠,越黏越緊。
本篇文字,一方面講述面向對象對JS編程的重要性,另一方面也必須吐槽一下沒有ES新特性加持的JS真的有點“垃圾”。你可以將沒有ES新特性支持的JS理解成ES5。
我知道很多同學是JS語言的粉絲,也一定聽說過Atwood的名言:凡是能用JS實現的最終都將用JS實現。
但我的確不太理解這句話。
了解我的朋友應該知道,我對語言是沒什么感情的,談不上喜歡亦或是討厭。生活中有太多值得去”喜愛“的東西,一本好書、一部電影都能讓我沉醉,編程語言實在排不上號。所以,當我指出JS的一些問題時,只希望大家能夠正視這些問題。一個人成熟的標志是你是否可以客觀看待某個問題,而不是一味的袒護與自我麻醉。你大可不必一聽到語言的問題就如同坐了穿天猴般蹦的老高老高,語言而已,它欲成仙我們不能左右;它要跌落神界,我們也無能為力。
沒有語言沒有缺陷。
如果JS那么優秀,為什么現在的ES新標準瘋狂迭代,不斷借鑒其他語言,越來越面向對象化呢?
拋開作為前端開發者出于保護自己飯碗那點小心思,我們應該理智的承認,JS這個語言在ES新標準普及前,它確實不如現代流行的其他語言。甚至是對于絕大多數的開發者來說,JS引以為傲的“靈活性”和原型鏈的設計模式反而是一種負擔。
作為一個在Jquery還未普及就開始手寫原生JS的開發者,今天確實想和大家聊聊JS面向對象的一些問題。
JS是否應該支持面向對象?或者說,我們是否應該用面向對象的思維來編寫JS代碼?
必須肯定的是JS本身就不是為面向對象而生的語言,這一點同Java是有本質區別的,所以它不能很好的支持面向對象是無可厚非的。
但這里要糾正一個誤區:JS是可以支持面向對象的,只不過它和經典的面向對象實現是有差異的。JS用ES5就可以模擬面向對象,它不是用Class來組織的,而是用原型鏈來“模擬”的。
但用原型鏈來模擬Java、C#中經典的OO模型是相當丑陋的,所以才有了ES6的Class。但ES6中的Class也僅僅是語法糖,在本質上它依然是用ES5的機制來模擬的類。
在這個ES5像ES6、7、8、9新標準過度的特殊時期,對于JS生態其實是一件很尷尬的事情。
由于ES6標準雖然已經非常普及了,但大量的庫由于早期沒有Class類的支持,所以依然保持著ES5中半面向對象,半過程式的編程方式。而我們現在在編程時構建復雜的業務時,必然又需要使用Class,當用ES6的Class思維去調用這些“不倫不類”的庫時,這就造成了“割裂”。
來看一個使用Sequelize操作MySQL數據庫定義Model模型時的典型例子:
以上代碼的邏輯非常簡單,我們有三個模型對象需要實現,但是這3個模型中有大量的重復屬性,就是在ArtBase中定義image、content、pubdate等屬性。那么按照通常的思維,我們需要有一個基類,這個基類包含了以上屬性,那么子類(Movie、Music、Sentence)需要繼承這個基類,才能避免在每個子類中都定義image、content、pubdate的屬性;此外,Movie、Music、Sentence還有一個公共的like方法,這個方法也需要定義在基類上。
在Sequelize中,要定義一個模型,必須使用define這種函數調用的方式來產生一個模型。而在define的時候是不能夠在模型中直接定義方法的,所以我們需要在define返回模型的prototype上添加like方法。
而Music由于有自己獨特的url屬性,所以他在繼承ArtBase后,還需要在構造函數里用this.url 來添加屬性;而根據ES6 的Class規定,在使用this前,必須先調用super。我相信絕大多數熟悉面向對象的同學,都不喜歡這種奇葩的寫法。如果你覺得還好,可以對比下下面Python版本的實現:
4個Class,代表了基類、Music、Sentence、Movie。我相信即使你完全不了解Python,這樣的定義也能一看就明白,不要說我偏愛Python的風格,這不是語言風格的問題,而是語言機制的問題。換做Java、PHP等任何現代的OO語言,一樣是類似于Python這樣的寫法。
以上兩段代碼只是節選簡化后的示例代碼,而在真實的業務中,由于類的復雜性,兩個版本的代碼優雅性、可讀性差距越來越大。通過對比Lin CMS的KOA版和Python版本可以很明顯的看到語言特性上的差距。實現整個框架相同的功能,Python版本的代碼量只有JS的一半左右。
那為什么兩個版本的差距會這么大呢?ES6不是支持Class嗎?
仔細觀察上面兩端代碼,你會發現,最根本的原因在于Sequelize是使用define這種工廠模式來創建的Class,但Python版本不同,它是直接可以定義一個Class。
那么為什么Sequelize不能直接定義一個模型基類呢?是現在做不到嗎?不是。最本質的原因還是在于Sequelize這個庫早期由于ES6沒有普及,他本身底層就不是用面向對象的思想來構建的,而現在由于面向對象的普及,它又想要支持面向對象(define返回的就是一個ES6的Class)。這就造成了“割裂”,顯得不倫不類。
這樣的例子不只是存在于Sequelize中,大量的經典庫依然是老舊的ES5的寫法。不要小看這個問題,沒有很好面向對象支持的庫基本不具備擴展性。
當一個被封裝好(無法更改源碼)的庫,如果它的提供的功能不符合我們的需求怎么辦?有一定面向對象編程經驗的同學應該知道,如果庫均是以Class的方式提供的,那么我們可以繼承這個Class,然后通過方法重載或者方法覆蓋的方式來重寫某個關鍵的方法,從而實現自己的邏輯。
但事實上,由于大量的庫都不是以Class的方式來構建的,我們根本無法在庫的外部通過這種繼承的方式來修改庫的默認行為。這是一場災難,而且短時間無法解決。
那是否由于這些原因,我們在編寫JavaScript代碼時就不應該使用面向對象的方式來構建?肯定不是。面向對象是一個無法逃避的思維,它是解決復雜應用的必備工程手段。
反過來看,你現在能想到某種替代面向對象的其他有效手段嗎?函數式編程?有些鼓吹函數式編程(FP)的人根本沒有真實的用函數式編程開發過完整的項目或者應用。JS也根本不是一個函數式編程的語言。
Scala可以算作一個函數式編程語言,但有多少人拿Scala來構建一個大型的應用?面向對象能流行這么久自然是有它的道理的。很多人鼓吹函數式編程只不過是玩弄一些對于絕大多數人陌生的概念,從而體現自己的與眾不同。
函數式編程的思維并不是沒有用,但函數式編程更多的是用于局部的代碼塊或者解決某個方向的問題,很少被全面用于整個應用中。比如Map/Reduce就是比較經典的函數式思維。
很多前端開發者認為,面向對象只是服務器端需要使用,前端是不要的。那么,什么是服務端,什么是前端?為什么服務端需要而前端不需要呢?僅僅是服務端比前端多了一個操作數據/數據庫的能力?所以前端就不需要?還是因為前端有一部分是做UI層面的所以不需要?
恐怕給出這種結論的人也說不清楚。事實上,前端和服務器的界限已經變的很模糊了,特別是NodeJS讓JS脫離了瀏覽器后,這個界限更加的模糊,你根本無法界定哪些功能必須是前端工程師做,哪些必須是服務工程師來做。
前端的業務已經越來越復雜了,除了不能直接操作數據和數據庫,前端幾乎和服務端沒有太大的區別。面向對象經過幾十年的實踐,已經被無數經典的案例證明是最有效的代碼構建手段。TypeScript的流行一部分原因是因為JS沒有類型約束,而TS解決了這個問題;但另一方面卻是因為TS非常像C#,而C#的確是比Java還要經典的面向對象語言。使用TS天然的面向對象特性來構建復雜的應用是一個很好的選擇。
也許TS不是構建面向對象前端應用的唯一手段,但用面向對象的思維來編寫前端代碼必定是大勢所趨。
有人說JavaScript在設計之初本就只是為了在瀏覽器里做做簡單的”特效“,比如跑馬燈、動態色彩等粗糙的效果,是我們太”貪心“賦予了JavaScript太多的責任。這個論述承認了JS在沒有普及ES新特性前確實不如其他語言,但依然不承認Web前端其實被JS這個語言“劫持”了。現今的情況下,找不到替代JS的前端方案。
事實上,前端之所以選擇JS不是因為它有多優秀,而是因為JS綁架了整個Web前端。即使是NodeJS的流行也不是因為他足夠的優秀和不可替代亦或是有非常強的特點,而僅僅是因為JavaScript在前端的統治性,“反推”出來我們需要有脫離瀏覽器的JS環境,從而誕生了Node。
再拿NodeJS的一大用處——前端工程化來看:前端工程化不能用Python、Java嗎?當然能,前端工程化的基礎在于對文件的讀寫能力,哪個服務端語言不具備文件讀寫能力?糾其原因依然是因為前端最熟悉的是JS,所以需要用JS來讀寫文件實現前端工程化。
在語法層面上,JS的特性也讓很多函數的接口設計顯得及其怪異:
其實就是一段普通的函數調用,但JS的語言特性,讓它無法避免這種嵌套式的傳參形式。可閱讀性極差。如果你要昧著良心說,“好”,那我也很無奈。
那我們就不應該深入學習JS或者NodeJS了嗎?不,對于前端開發者來說,還是得學。既然JS綁架了整個Web前端,你能有什么辦法?我們畢竟是普通開發者,隨大流總不會錯。我們依然需要面試、找工作,依然需要靠JS生活。
所以,被xx了咋辦呢?躺下來享受就好。就像Lin CMS,如果按照我的意愿,我根本不想開發KOA版本,然而人多力量大,前端人就是多,那就必須搞個KOA版本,讓大家能夠用一個語言完成前端和服務端。
有時候,JS綁架了整個Web前端反而也挺好的。服務端能選擇的語言太多了,java、python、php、go、c#,有同學總是問我,我到底學什么語言,我總是說不清楚,挺費事的。
然而前端就沒這個煩惱,JavaScript,你沒得選擇。這真是件很美妙的事兒呢。
我以前總是覺得學一個語言并不是一件太費事兒的事情,所以我總是告訴前端開發者,如果你想做服務端最好的選擇是Python而不是JS。但我覺得,我犯了2個錯誤,一是我不應該拿我10年的開發經驗來對標初學編程的前端開發者。二是,我忽略了找工作這個最重要的事情。
NodeJS依然是前端進階到全棧成本最低的語言。既能加深JS語言的理解,反哺前端開發、又能給前端未來沒落后或者競爭太激烈時(我說假如),留給自己一條退路、還能增強找工作的籌碼、還能自己獨立開發一個完整的項目,關鍵是還沒有語言障礙。
一個語言要想精通還是太難了。至少編程的前五年接觸第二語言不是一件太好的事情。所以這次給《舊島》小程序做的服務端,我選擇的還是前端一體化的語言Node.js。詳細的課程內容在后續的文章中給出。
我的課依然是我的風格,業務只是個套子,真正讓人高潮的還是編程思維和JavaScript語言的本質以及異步編程模型。
最后給大家留個作業,也是在新課程中編寫校驗器的時遇到的一個問題:
如何查找一個Class實例對象以及其所有父類上指定名稱前綴的自定義屬性名和自定義方法名?
有點抽象,我們給出具體的題干代碼:
A、B、C是三個一次繼承的類。你需要編寫一個findMembers函數,傳入屬性名的前綴name,和方法的前綴名validate;查找全部的以name和validate開頭的屬性和方法名稱。函數的返回結果應該是nameA、nameB、nameC和validateA、validateB、validateC。
注意,我們尋找的是自定義方法和屬性,所以只能返回這6個名稱字符串,不能包含js對象的內置方法。
這個問題不難也不簡單,需要對原型鏈有一定的了解。這個問題放到Java、Python、C#中就是幾句代碼,因為這些語言已經內置了查找方法。但JS,我沒找到內置的方法。
同學們可以把代碼直接截圖發到公眾號后臺,我從最好的解決方法中挑選一位同學,贈送一本我很喜歡的《黑客與畫家》。有時間寫篇文章,單獨聊聊。
愛我,請關注我的公眾號:
總結
以上是生活随笔為你收集整理的前端判断session对象是否为空_谈谈JavaScript这个语言与前端是否需要面向对象?...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最长回文子串动态规划_九章算法 | 微软
- 下一篇: ssm把图片保存到项目中_项目中的图片跨