ES6的class關鍵字有沒有實現真正的面向對象?

  1. 類沒有靜態屬性;
  2. 類的靜態方法,實例無法調用;
  3. 只能在方法內定義屬性;


很多「純面向對象廚」還吐槽像Java、C#的靜態方法不面向對象呢。「真正的面向對象」語言里所有操作都應該有receiver,靜態方法沒有receiver所以不面向對象。

——你們想怎麼定義哪種模型更面向對象都罷,俺只管用,怎麼樣好用都行…

回到題主的問題,每個問題都可以換個角度來爭辯:&<- 再次聲明,俺對這些爭辯不感冒,既不支持題主的論點也不是說下面爭辯的觀點就對。只要是規定得規整的設計俺都OK。

1. 類沒有靜態屬性;

也可以說有靜態屬性更不面向對象。

類自身是對象,類對象可以有欄位,這就很足夠了,非常面向對象。

2. 類的靜態方法,實例無法調用;

在「真正的面向對象」語言里,類也是一個對象,所謂「靜態方法」不過就是掛在類對象上的方法而已。要調用它們就指定該類為receiver去調用即可。ES6的class正好就可以做到這點,很面向對象。

像Java、C#的靜態方法沒有receiver,是一種比較不面向對象的設計。要從面向對象的角度看,它們可以看作是依賴靜態類型系統來去省略了作為receiver的類參數的折衷設計,而它們其實也是要通過「ClassName.methodName(...)」的方式來調用的,只不過Java和C#在名字查找規則上對靜態方法做了特殊處理,允許在實例方法里省略類名去調用本類的靜態方法。在像ES6這樣動態的語言里,這種隱式指定receiver的做法反而不現實也不直觀。

Java的語法里還有一種非常噁心的調用靜態方法的辦法——通過一個實例的引用去調用:

public class Foo {
static void bar() { }
void baz() {
this.bar(); //=&> actually compiles into Foo.bar()
}

public static void main(String[] args) {
Foo obj = null;
obj.bar(); //=&> actually compiles into Foo.bar(), no NPE thrown
}
}

這裡 Foo.bar() 是一個靜態方法,但我們可以用調用實例方法的語法(this.bar()、obj.bar())去調用它——而實際的語義跟那個引用一點關係都沒有,純粹是一個靜態方法調用而已。這就是為什麼當引用是null的時候用這種語法調用靜態方法還是可以正常編譯並運行,而不會在運行時拋出NullPointerException。這個設計非常糟糕,很容易就把讀代碼的人騙了,以為這裡調用的是實例方法。這絕對不是什麼好的面向對象設計。

3. 只能在方法內定義屬性;

這跟是否面向對象其實關係不大,而是跟語言的動態性更有關係。

看看同樣也很動態的Python和Ruby,它們也都是只能在實例方法里定義實例欄位。像Ruby的attr_accessor只是聲明了某個名字的getter / setter(合起來叫做accessor),但卻沒有定義實例欄位自身。這只不過是一種動態的設計風格,談不上面向對象與否。


完全贊同R大。

要補充的是,1和3其實都有草案,未來是可能直接支持的。


OO is not about class, it is about logical individual and message between them.

// Sorry, I broke my IME temporary.


總的來說,面向對象講的是interface的事情,跟class其實關係不大。class說白了本來就應該只是一個返回interface的實現的函數名,只是嚴格的這樣做很多人會不開心,所以後來就乾脆發明了class,然後水就被攪渾了。


謝邀。

關於類,贊同 @RednaxelaFX 的答案;關於 ES 到底能不能實現題述的功能,同意 @賀師俊 的答案;關於面向對象和類型,同意輪子哥的答案。他們的答案都看一遍是極好的。

所以關鍵並不在於 ES 到底是不是面向對象, ES 是多範式的,能做的遠遠不止 class ,何苦把自己局限在面向對象的窠臼里。現在對 ES 的主要批評在於它太靈活,又沒有類型,用在大型工程里會有一些麻煩,再加上其他一些缺陷,導致一些人決定另起爐灶,弄出了一些 compile to js 的方案。

對 ES 的批評、思考、實踐和改進,都是極好的,這對 ES 的成長是一種幫助。


有人已經回答得很好了。你說的跟沒實現面向對象沒關係。

而且JS本就是基於原型的面向對象語言,哪怕沒有class,它也是面向對象的。

每一個全局變數其實是頂層對象的屬性,每一個全局函數其實是頂層對象的方法。

ES6之前用(偽)構造函數模擬OOP,函數也可以 new 不同的實例出來的。


什麼叫」真正的面向對象「?面向對象還有假的?

題主這種,就是想得太多,做的看的太少,死命鑽牛角尖。

面向對象語言的硬指標就那麼幾種,類,對象,繼承,成員函數覆蓋,門檻很低。這些指標和語言的具體實現沒有任何關係,有就是OO,沒有就不是。早期版本的Objective C純粹就是一個C預處理器,人家照樣算是OO。Javascript 在ES3不是OO,ES6就是了,因為ES6有class關鍵字,其實你用Babel編譯一看,就是轉成了一堆噁心的ES3原型鏈代碼。語法糖層面的OO也是OO,沒有什麼規矩說一定要在什麼層面上實現OO才算是正統OO。


像 javascript 這種動態弱類型語言,天生就是面向對象的,這跟它有沒有 class、class 怎麼設計完全沒關係。

所謂面向對象無非是說了兩件事兒:

  1. 對象里能存儲狀態;
  2. 對象和對象之間能發消息互操作;

具體到代碼里,面向對象就是 interface。而 js 這種語言根本不需要 interface 關鍵字就能表達出 interface 的語義,反正不管什麼東西都是 var,發消息也無非就是 foo.bar(),如果 foo 沒定義對 bar 消息的處理函數,大不了就是拋異常嘛。

其實 js 也好,python 也好,vbs 也好,你可以認為裡面所有的對象都實現了一個叫做 obj.emit(message) 的介面,只要有這東西,自然就面向對象了。


一個本來面向過程的語言 非得加個oo草案,肉疼


「面向對象」只是一種風格,別太執著。就如R大所說,只要規整,怎樣都行。

至於ES6 的class,姑且理解成包裝了prototype機制的語法糖吧。

至於2,我一直認為「實例可以調用類的靜態方法」或者說「類可以擁有靜態方法」是一個錯誤的設計,既然是靜態方法,那就應該是全局的,而類在這種語境下更像是「包」或者「命名空間」,在推廣一下你就會發現其實這兩者的概念幾乎是一樣的。

最後再深入一點,面向對象的目標是復用代碼,手段是利用類型系統來管理繁複的數據結構,在有大量結構重複的問題領域(如GUI),成效卓著,現有的class-object模型也是那個時候的最佳實踐。既然整個「面向對象」就是為了解決諸如「兩個數據結構太像了,我可不想寫兩遍」產生的,那事實上最流行語言javascript最後會怎樣利用這些特性其實真的沒必要去深究,應用場景不一樣,設計目標不一樣,時代不一樣。

畢竟,我們最終要的還是生產力,沒有完美語言也沒有完美產品,永遠不會。


構造函數內部不是全功能的javascript

原型繼承 類繼承都是面向對象啊

題主應該跳出類繼承


沒有。JS是多範式的語言,連完全面向對象(無其它範式)都做不到,更別提「真正」的面向對象了。

就你提到的三點。(1)和(2)以JS的靈活性可以分分鐘繞過。(3)是糖不糖的問題,跟面向對象沒有關係。


面向對象就是一套建模方法,管它是不是「真正的」,好用就行,原教旨容易boom……


js 在出現 class 以前已經支持面向對象了


oo是程序設計的一種思想,用c也可以寫出具有OO思想的代碼


就連學校課本裡面都會寫著,面向對象的三大特徵:封裝、繼承、多態。

也就是說,實現了這三個特性就是面向對象。題主提到的各種功能最多只能說是某些語言在滿足基本的面向對象原則後添加的feature。

大家寫C/C++/Java之類的習慣了,就很可能拿這些語言的一些特性當作是面向對象的特性。

事實上其它很多語言只不過是用更簡約的方式實現了面向對象罷了,例如Lua或ES6之前的JS,對於它們來說,實現一個class關鍵字都可以說是一個語法糖。


靜態屬性,靜態方法 相當於實例化了一個類,然後把這個類隱藏了.


真正的面向對象里怎麼會有類這個東西


其實這可以看作一種trade off。js現在足夠面向對象啦。也贊同R大的,從另一種角度來說靜態更不面向對象。

如果js要實現得完全面相對象,還會有這麼好用嗎?

前兩點依靠js的靈活性就可以實現了。更好的方法也在草案階段。

對於第三點那就是糖的問題。


js的面向對象屬性比java什麼的不知道高到哪去了 對象需要什麼靜態方法和屬性?

當然ruby就更絕了 萬物皆對象

以 Java 為例:如果你想取一個數字取絕對值,java 的做法是:

int num = Math.abs(-99);

也就是將一個數值傳遞給 Math 類的一個靜態函數 abs 處理。為什麼這麼做?因為在 java 中,數值是基本類型不是類。

而在 Ruby 中,任何事物都是對象,也就是說,數字–99就是對象,取絕對值這樣的操作應該屬於數字本身,所以Ruby的做法就是:

num = -99.abs


但是沒有用啊沒有用啊沒有用啊…………作為一個動態類型語言……

編輯器裡面寫成員變數都沒有靠譜的補全啊

你打一個點後面該寫什麼不敢下手啊!心虛啊

開兩個頁面左右一邊一個對著看啊

一邊是介面定義一邊是正在寫的函數啊

感覺還是輪子哥說得好,oop最大的作用是啥,就是一個interface啊

帶自動補全的interface啊

帶編譯期類型檢查的interface啊

沒有undefined啊

//typescript大法好然而要編譯


你說那些都是 class oriented language

js只有object 所以是 object only oriented language


推薦閱讀:

關於JS中this作為方法調用?
如何評價 TypeScript 1.7?
npm、bower、jamjs 等包管理器,哪個比較好用?
js 數組賦值問題 :值傳遞還是引用?
在自學前端,但是沒有什麼實踐的資源,大家來推薦一下論壇或者別的可供練習的資源吧?

TAG:JavaScript | 面向對象編程 | ECMAScript2015 |