如果ECMAScript 2015+完全普及,原型鏈這種知識是否還有了解的必要?

不管是不是,都請大家來說說原因吧。

補充問題,如果原型鏈這種知識被面向對象的繼承、組裝完全代替而不需要再去理解的話,ECMAScript是否存在其他的知識點,在接下來的發展中可以不需要去了解的呢?

=========分割線========

我是題主。這個問題是我最近在思考而不得其解的問題,所以邀請了十幾個我知道的前端大大來討論這個事情。

現在我來談談我的理解。

其實我的想法跟 @汪志成 有些許類似。

我對原型鏈的理解就是一個實現面向對象的工具。儘管這種理解如果錯誤了那麼後面的想法都不成立,但是對我來說原型鏈是我在業務中需要實現某些設計模式的時候我才會去使用的一種工具。

在新的ES中包含有OOP的語法糖,這種class和interface的語法糖所帶來的好處就是更直觀的面向對象編程方式,作為一個面向對象特性來說,比原型鏈直觀太多。那麼我在現階段條件允許下基本就不會再去使用原型鏈。另外我給同事做培訓或者分享的時候,也會捨棄掉原型鏈實現的示例。

以上就是我自己對這個問題的看法。

如果哪裡有錯,還望各位朋友不吝賜教!

========討論的分割線========

其實我的提問中並不包含「原型鏈很難,我不想學」「這種東西肯定學了也用不到」這種想法,因為很多朋友回答了「題主你學個原型鏈很難嗎」「題主一定也不會XX」這種毫無幫助的回答。

另外我想解釋一下為什麼我想討論的是原型鏈是否可以被替代,因為從代碼可讀性和可維護性來說,OOP的語法糖比原型鏈要強。如果可以代替,我們應該用語法糖,如果不可代替,原因有哪些。我想討論的是這個,如果提問並不清楚,我在這裡做一個補充。

現在至少我覺得有一點很確信,就是你想知道ECMAScript的面向對象實現原理,你要了解原型鏈。

下面是一些牢騷大家可以不用往下看了。

==========牢騷分割線==========

那幾個懷疑我會不會原型鏈的朋友,我問的問題就是我想知道的東西,跟設計模式這種東西比起來,原型鏈難個屁……


等瀏覽器全面支持 es201x 之後,不了解原型鏈可以幹活,這是必然的。es201x 的目的不就是這個嗎?

但是呢,這說到底不僅僅是個技術問題,還是個江湖問題。

首先說技術。c++使用者大都知道一本書叫做《深度探索c++對象模型》,這本書講的,就是你在c++里寫的class和new的對象,在內存里到底是個什麼樣子。要說沒必要,這本書講的內容,比原型鏈更沒必要掌握,畢竟是編譯器背後的事情,如果你做應用,你在代碼里永遠也不用接觸這玩意兒。

但是,很多c++使用者都看過這本書,並且會向新手推薦這本書。為什麼呢?

其實是個底氣問題,你知道你寫的代碼在內存里是怎麼運行的,你就有了一份底氣。這不是虛幻的東西,調試代碼的時候,這份底氣很重要。有些程序員看到this指針指向0,就迷惑了,連數組越界把後面的內存數據踢了這種可能性都想不到,這就是典型的沒有底氣。

原型鏈也是一樣的道理。

然後我們再說說江湖。其實程序員之間,不管是面試還是平時的交流,有些技術話題是用來對暗號的——不一定真有用,但是你不懂,別人可能就會因此看低你。

比如說v8引擎是怎麼做數組排序的,這事兒重要嗎?800年也遇不到一次應用場景。但是你還是會經常聽到前端在談論這個事情,這其實就是在對暗號,確認誰在圈兒里誰在圈兒外。就好像文青聊張愛玲,不一定是真愛看,只是一個辨認同類,排斥異類的手段。

我記得郭德綱說過一個事兒,說解放前的老相聲演員都要會唱太平歌詞,不然就要少拿錢,人家說學逗唱四門,你缺一門,人家拿100,你拿75。

咱們理性的琢磨一下,先不說這事兒真的假的,就算是真的,有道理嗎?完全沒有。相聲吸不吸引人,和會不會唱太平歌詞有什麼關係?別說不會唱太平歌詞,就算什麼都不會就會灑狗血,觀眾愛看你管的著?

但是,你攔不住郭德綱拿這個說事兒,這就是江湖。


看你想做什麼級別的工程師了。

以我看,中級及以上是必須掌握的吧……


很不幸,就算大多數時候用不到但還是要了解一下的。面向對象時的代碼復用問題在 JavaScript 還缺乏一個優雅的解決方案,所以所有人都被迫去接觸現在這種複雜的實現方式。現在的 class 關鍵字並沒有把背後的複雜度降低下來或完全封裝起來,所以所有的複雜度還是被暴露出來了,只是特定寫法可以被簡化而已。希望有一天有一個新的設計能夠解決這個問題。(或許面向對象在 JavaScript 裡面就是個錯誤的方向,但因為 DOM 已經設計成這樣子了,又難以完全拋棄掉對象體系。)


class只是原型鏈的一種語法糖啊。就算是我大部分時間都在寫後端的開發者,看到ES6中對於class關鍵字這樣的描述,也明白。ES或者JS的核心是原型鏈啊。

原生class設計和class語法糖,差別可大了。

public,private,protected,static,class method,繼承,overload,override,interface,多態,多繼承,Mixin等都是完全不一樣的實現方式。

敢忽略這個?


謝邀。

這個問題其實取決於 ES 6+ 的類究竟能不能完全代替原型鏈 —— 至少在最佳實踐下。

作為類比,大多數中高級程序員都不會手寫彙編甚至讀彙編,就是因為高級語言在絕大多數場景下已經完全替代了彙編,甚至做得更好。同樣的,大多數高級前端也都是不會寫 C++ 的,雖然瀏覽器大多數都是 C/C++寫的,包括 JS 引擎。對於自認高級的前端,有多少敢說了解 V8 工作原理的?至少我最多也就了解其表層。

而原型鏈至少在兼容老代碼的問題上恐怕是無法在短期內被完全替代的,在心理層面更是如此。你沒看到很多高級前端還極其排斥 TypeScript 嗎?我相信排斥 ES 6+ 的也會有不少,有人甚至認為類的存在損害了 FP。所以,我對此不是很樂觀,很多人可能相當長時間內都不得不跟原型鏈打交道。

至於不需要了解的知識點嘛……我覺得空值表應該算一個。至少在正規團隊中都會通過 jslint 等方式避免讓代碼受到空值表的影響,如果有面試官讓你寫出完整的空值表,那就直接摔門走人吧。


當然還是需要了解。

就像其他答主提到的,class只是一個語法糖,本質上還是原型鏈繼承。

但是正是因為是原型鏈繼承,所以才需要理解,因為跟其他的語言不一樣,這裡不是類繼承。

如果你不了解原型繼承,貿然的使用es6的class關鍵字,會有很多問題跟麻煩。

本質上這是兩種不同的面向對象的設計思想,類繼承思想是「按類歸納」,原型繼承思想是「照葫蘆畫瓢」,這是思想上的不同,class 語法糖只是在強行的讓他們很像罷了,因為有類繼承編程經驗的人很多,通過class來讓他們快速類比掌握原型繼承是一種降低語言學習門檻的辦法。

看問題如果不看本質,那麼你永遠只能看到表象。為什麼有的人按網上抄來的套路追妹子一追就到手,為什麼有的人就不行?還不是因為他不了解看上去性格相同的兩個妹子其實一個是老司機,一個是傻白甜,只不過老司機因為種種原因裝作像傻白甜的樣子。不懂得撥開現象看本質,最後肯定是要被老司機玩的。

因此不要本末倒置,es6里的class並不是真正的類,它只是看上去像類罷了。不求甚解只會被這甜蜜的語法糖毒害,永遠也搞不明白一些騷操作是什麼意思。


在我心中不懂原型的前端是傻逼,除非你認為自己不是前端就是一玩票的。

態度夠明確吧……

就是一個簡單的鏈表,到底哪裡難了?

如果一個前端不懂原型,那他怎麼理解 class的類型是 function? 這個 function 還有個 prototype 屬性?

難道要視而不見嗎?

別整天問能不能不學原型。


想要邀請不了解原型鏈的同學回答這些問題:

  1. 當需求是創建一個安全的無枚舉副作用的對象,你會怎麼做?
  2. 當有 SuperHero 和 Bat 兩個類的時候,想要再得到一個 Batman 類,你會怎麼做?
  3. 當需求是創建一個 Transformer 類,具有實例方法 .transformTo,它可以讓實例變身成其它生物,你會怎麼做?
  4. 當想要為類的方法做代理,如果類是第三方提供的,顯然此時你無法使用裝飾器,你會怎麼做?

如果對原型鏈的了解指的是這張圖:

那確實沒多少人了解,這個不死背還是有相當難度的。但是,了解 JS 對象具有上溯原型鏈的能力,new 和 constructor 的關係,函數原型、對象原型和實例的關係,還是很有必要的(並且也沒有難度,這些原理是具體可解釋的),當你想不通 ES6 的 class 為什麼不能多繼承,用原型鏈就很好解釋。

原型鏈只是提供了繼承,能力上是傳統的 OO 子集,因此在 JS 中要模擬 Class 的其它特性確實麻煩,尤其是 super 與 extends 比較難寫,很多人(通過很多教程)在嘗試用 prototype 模擬 class 並測試 OO 特性 -&> 嘗試改進實現完美模擬的循環中栽了跟頭。

可實際上:你可能不需 OO Class 的全部能力,prototype 提供的上溯原型鏈能力已經滿足你的需求。很多庫就是只用 prototype 於方法復用,並不會先模擬 class 再使用(其中甚者反感 new + prototype 的用法,一定要用自身的函數調用、createXXX、XXXFactory、extend、compose 這些工廠規避掉 new 操作符調用 &<- 其中一個原因是函數通過 new 和直接調用的結果不同,這不可接受)。

如果你只是需要為你的代碼庫 / 工具函數提供一個簡單的方法復用,prototype 已經足夠好用,你的代碼掌握在你自己的封閉空間內,不會被其他人「繼承」 -&> 也就無須使用 instanceof 從而擔心 constructor 指向問題;同樣的,庫及工具的開發中,用 prototype 可以充分發揮 JS 的元編程能力,發揮想像力它就是用來實現黑科技的利器。

最後說句大家不愛聽的,ES6 的 class 在純前端領域用處還不大,主要是當契約用(React, Web component)。但它當契約卻沒有抽象類和介面(未來會有 protocol )、訪問許可權、實現的時候沒有類屬性(不用 babel)、沒有 final 方法與final 類,還有令人遺憾的是 ES6 class 的類實例生命周期只有 constructor 這一個,沒有遵循開閉原則 -&> 回收的時候沒法自動析構。React 做為組件類的調度器還無所謂,如果最後自己還是不得不鼓搗一個工廠去構造、析構,有何感想?目前(乃至可以預見的未來)的 class 用起來束手束腳,它勉強可用的感覺讓人覺得好像只是在原來的 protoype 的上方便了類繼承而已。這點,在另一問題里回答過:「為什麼 React 推崇 HOC 和組合的方式,而不是繼承的方式來擴展組件?」;裡面詳細地講了下繼承的作用有限,它除了看上去好看(高 big?),只要你不需要 super 和 extends,class 的場景都可以是 prototype 的。


【定義】

JavaScript 是一種原生支持函數式編程範式、基於原型的面向對象語言!

【敲黑板】

class 關鍵詞只是為了照顧其它語言用戶的語法糖!

沒它 ECMAScript 5 照寫不誤!!

前端後生別少寫幾個字母就忘了本!!!

【科普】

「基於原型的面向對象」是 Self 語言發明人一番思考後的成果,他認為:「類」不是 OOP 很必要的概念,用「對象」為原型去構造新的對象即可。它與 Erlang 語言倡導的「基於消息的面向對象」一樣,都是 OOP 的經典實現模式。


不管是不是,都請大家來說說原因吧。

補充問題,如果原型鏈這種知識被面向對象的繼承、組裝完全代替而不需要再去理解的話,ECMAScript是否存在其他的知識點,在接下來的發展中可以不需要去了解的呢?

=========分割線========

我是題主。這個問題是我最近在思考而不得其解的問題,所以邀請了十幾個我知道的前端大大來討論這個事情。

現在我來談談我的理解。

其實我的想法跟 @汪志成 有些許類似。

我對原型鏈的理解就是一個實現面向對象的工具。儘管這種理解如果錯誤了那麼後面的想法都不成立,但是對我來說原型鏈是我在業務中需要實現某些設計模式的時候我才會去使用的一種工具。

在新的ES中包含有OOP的語法糖,這種class和interface的語法糖所帶來的好處就是更直觀的面向對象編程方式,作為一個面向對象特性來說,比原型鏈直觀太多。那麼我在現階段條件允許下基本就不會再去使用原型鏈。另外我給同事做培訓或者分享的時候,也會捨棄掉原型鏈實現的示例。

以上就是我自己對這個問題的看法。

如果哪裡有錯,還望各位朋友不吝賜教!

========討論的分割線========

其實我的提問中並不包含「原型鏈很難,我不想學」「這種東西肯定學了也用不到」這種想法,因為很多朋友回答了「題主你學個原型鏈很難嗎」「題主一定也不會XX」這種毫無幫助的回答。

另外我想解釋一下為什麼我想討論的是原型鏈是否可以被替代,因為從代碼可讀性和可維護性來說,OOP的語法糖比原型鏈要強。如果可以代替,我們應該用語法糖,如果不可代替,原因有哪些。我想討論的是這個,如果提問並不清楚,我在這裡做一個補充。

現在至少我覺得有一點很確信,就是你想知道ECMAScript的面向對象實現原理,你要了解原型鏈。

下面是一些牢騷大家可以不用往下看了。

==========牢騷分割線==========

那幾個懷疑我會不會原型鏈的朋友,我問的問題就是我想知道的東西,跟設計模式這種東西比起來,原型鏈難個屁……


# 老司機的手動擋

時至今天,依舊有一些老司機都看不起不會開手動擋的新司機,在老司機眼裡,開自動擋費油,缺少操控精度,也沒有駕駛樂趣,提速不夠快,一點也不專業,只會開自動擋的人根本談不上"會開車",手動擋也並不難學呀.

# 讀書人的情懷

很多知識分子大多瞧不上"羅輯思維"之類的所謂知識付費平台,這種平台把知識快餐化了,一本好書閱讀起來多有樂趣啊,刨去了這裡面的思辨,論證只剩下所謂的"二手乾貨",這 TM 還能叫讀書嗎?吸收這樣快餐化的知識的人也太膚淺了罷.

# 專業的相機

用 iphone 照相也 TM 叫照相,懂什麼叫焦距,什麼叫光圈嗎?機器自動調焦調的那都是什麼玩意啊,照出來的都失真了好罷,還好意思曬到朋友圈?

# 千元以內的耳機

千元以內的耳機也能叫耳機?那出來的聲音還TM能聽?高中重低音完全不分,居然還有人買?

# 一年速成的全棧工程師

一年也能出全棧工程師?搞什麼笑,最後這幫所謂的全棧工程師連一些基本的技術常識都不清楚,那我們這些年辛辛苦苦都在做什麼?

其實我覺得技術是為了目標服務,專註於技術細節的掌握提升沒有錯誤,但是當外部產業環境發生了變革的時候,依然執著於細節意義就不大了.

這個意思不是說原型鏈等知識對於前端不重要,要看是否你的工作中是否用得到,如果你做的只是相對傳統的 web 頁面實現,還要連帶搞跟多後端的東西, 大多數 js 效果用的都是框架默認配置,js 的一些細節對於你來講只是工作的一小部分而已,那麼研究清楚細節原理就沒那麼重要;

而如果你本身就是大前端,要專註於各種移動端適配,需要自己做各種各樣的輪子,搞各種炫酷的效果與魔幻的前端交互實現,這些細節原理東西你就得知道,不然你幹不了活.

倒退十年,你如果連彙編都不會,你根本算不上程序員!


原型鏈是JS的基礎知識,基礎知識都不掌握的怎麼繼續深入啊。

當然前提條件是你想做一個好的前端。

如果是渾渾噩噩過日子沒有想過提升自我的話,那就另當別論吧... :)

總的來說,原型鏈是基礎知識。


我不看文檔寫不出es6的class,

所以我依然在用原型鏈那一套


這一個搬磚的活兒,就一個手推車,你說你用不用吧。我也知道蘭博基尼快,沒有啊!

拉磚的過程中,你熟練的掌握了各種路面應該如何控制車身的技巧,從不踩坑;知道什麼時候車胎要打氣了;知道怎樣分配體力來幹活;知道哪裡出問題了要換什麼零件。你比其他人效率都高,每天多賺了幾塊錢,你心裡美不美?當然美啊!

後來公司下了血本,給手推車升級了:橡膠的握把冬天不冷;德國的軸承更順滑;更寬大的輪胎過小坑也不怕了。大家的效率都高了不少。有那麼一瞬間,你可能覺得自己被新來的小年輕兒給淘汰了。

但是!但是!手推車畢竟還是手推車。你總結出的走線技巧依然是老鄉中的最佳實踐;別人車有什麼問題只有你能修。雖然你現在拉的可能不如別人多。但是包工頭總是對你說:你可別走,有你在,放心!

扯一堆沒用的。看看現在市面上的這些語言都是什麼時候出來的;看看常用的這些演算法都應用了多久了;工作中有多少九幾年的代碼還在每天兢兢業業地跑著。不用怕學了浪費,不用怕被淘汰,學了就不吃虧!

不止對題主,也跟所有的開發人員共勉。


我記得class只是語法糖而已,想了解原理和深層次的知識,原型鏈還是有必要學習的,而且也不難啊,多花幾天看看又不會怎樣。


沒有必要的呀~

學會class就好了。

但是,想學會class,那麼你一定需要了解extend的機制的吧,還得了解class上的prototype是幹啥用的吧,了解兩種方式掛到對象上去的函數有什麼區別,了解super關鍵字是啥,了解構造函數的工作原理……

咦,好像哪裡不對勁…(抖抖抖

但是總而言之,如果面試時有人要我說出JavaScript實現繼承的三四五六七種方式,我大概也是會崩潰的。甚至會懷疑人生,這到底是一個技術題還是一個心理素質題……(咦


一個層次,背語法。另一個層次,知道語法背後的機制。

寫C++的,只背背語法就完事了嗎?至少得知道背後是如何實現OOP的吧……class怎麼實例化的,函數虛表是啥,總得了解吧?

寫JavaScript,只背背語法就完事了?至少得知道背後是如何實現OOP的吧……function怎麼創建的,prototype,constructor啥的什麼關係?對象的內部屬性proto和scope是啥?原型鏈和作用域鏈,總得要了解吧?

在設計一個程序的時候,腦子裡呈現的是一條條的語法規則?還是邏輯上的對象、指針等本質的結構?

這個差異就是:

第一種,從語法規則到邏輯設計。背過的只是套路,依附於語法的一些設計規則而已。熟悉每種語法的功能特性,常見的使用效果等等。說到底還是背的一個套路,一套經驗規則。

第二種,由邏輯設計到語法表達。腦子裡先組織好了一些設計的結構,然後去用合適的語法表達出來就行了。注意,這和前面一個並不衝突,不是二選一。這個仍然需要熟悉掌握語法。

類似地,設計模式重要嗎?重要,也不重要。設計模式可以說是從經驗總結出來的模板,可以認為像語法一樣形式化的東西。在提出設計模式的概念之前,很多人不需要知道設計模式,自身卻已經無意識在使用它們了。這些人不需要那個模板,只是從本質的邏輯關係去設計,然後用語法表達出來就可以了。這個過程是由設計到語法實現。

總結:ES2015的class語法和原型鏈並不衝突。因為就不是一個層面的東西。學了C++的class,還是要去看內部的機制,比如看看《Inside the C++ Object Model》,反彙編看看內部到底怎麼運行的。學了JS的class,依然要看看內部如何工作的,比如看看原型鏈機制。


舉個例子吧.async await,用起來很爽,babel也實現了,可以直接用.但是如果你不去琢磨generator函數,你總會覺得async就像魔法一樣,讓人不踏實.ES6的Class也一樣.


需要。

之前寫 React 組件的時候,同事間對於 handle 形式的函數寫法有一系列的討論,關於要不要 bind,要不要用 proposal-class-fields 寫法等等。(tc39/proposal-class-fields)

但是其實它不是一個 React 問題,而是一個原型鏈問題,而一旦想清楚這是一個原型鏈問題,在怎樣的場景使用怎樣的寫法就不再是一個問題了,所以,you see。


我今天分析fb網站,就是用prototype的方式做的劫持非同步請求的。


推薦閱讀:

webpack 只適合SPA嗎?
能否用通俗語言講一下web前端講的「切圖」到底是什麼意思?
js等語言的undefined值存在的意義是什麼?
npm install的實現原理?
移動端前端開發與PC端比有哪些不同?

TAG:前端開發 | JavaScript | ECMAScript |