介紹
在本篇文章,我們考慮在ECMAScript中的面向對象編程的各個方面(雖然以前在許多文章中已經討論過這個話題)。我們將更多地從理論方面看這些問題。 特別是,我們會考慮對象的創建算法,對象(包括基本關系 - 繼承)之間的關系是如何,也可以在討論中使用(我希望將消除之前對于JavaScript中OOP的一些概念歧義)。
英文原文:http://dmitrysoshnikov.com/ecmascript/chapter-7-1-oop-general-theory/
概論、范式與思想
在進行ECMAScript中的OOP技術分析之前,我們有必要掌握一些OOP基本的特征,并澄清概論中的主要概念。
ECMAScript支持包括結構化、面向對象、函數式、命令式等多種編程方式,某些情況下還支持面向方面編程;但本文是討論面向對象編程,所以來給出ECMAScript中面向對象編程的定義:
ECMAScript是基于原型實現的面向對象編程語言。
基于原型的OOP和基于靜態類的方式直接有很多差異。 讓我們一起來看看他們直接詳細的差異。
基于類特性和基于原型
注意,在前面一句很重要的一點已經指出的那樣-完全基于靜態類。 隨著“靜態”一詞,我們了解靜態對象和靜態類,強類型(雖然不是必需的)。
關于這種情況,很多論壇上的文檔都有強調這是他們反對將在JavaScript里將“類與原型”進行比較的主要原因,盡管他們在實現上的有所不同(例如基于動態類的Python和Ruby)不是太反對的重點(某些條件寫,盡管思想上有一定不同,但JavaScript沒有變得那么另類),但他們反對的重點是靜態類和動態原型(statics + classes vs. dynamics + prototypes),確切地說,一個靜態類(例如:C + +,JAVA)和他的屬下及方法定義的機制可以讓我們看到它和基于原型實現的準確區別。
但是,讓我們來一個一個列舉一下。 讓我們考慮總則和這些范式的主要概念。
基于靜態類
在基于類的模型中,有個關于類和實例的概念。 類的實例也常常被命名為對象或范例 。
類與對象
類代表了一個實例(也就是對象)的抽象。在這方面有點像數學,但我們一把稱之為類型(type)或分類(classification)。
例如(這里和下面的例子都是偽代碼):
層次繼承
為了提高代碼重用,類可以從一個擴展為另一個,在加上額外的信息。 這種機制被稱為(分層)繼承 。
在類的實例上調用方的時候,通常會現在原生類本書就查找該方法,如果沒找到就到直接父類去查找,如果還沒找到,就到父類的父類去查找(例如嚴格的繼承鏈上),如果查到繼承的頂部還沒查到,那結果就是:該對象沒有類似的行為,也沒辦法獲取結果。
基于類的關鍵概念
因此,我們有如下關鍵概念:
1.創建一個對象之前,必須聲明類,首先有必要界定其類
2.因此,該對象將由抽象成自身“象形和相似性”(結構和行為)的類里創建
3.方法是通過了嚴格的,直接的,一成不變的繼承鏈來處理
4.子類包含了繼承鏈中所有的屬性(即使其中的某些屬性是子類不需要的);
5.創建類實例,類不能(因為靜態模型)來改變其實例的特征(屬性或方法);
6.實例(因為嚴格的靜態模型)除了有該實例所對應類里聲明的行為和屬性以外,是不能額外的行為或屬性的。
讓我們看看在JavaScript里如何替代OOP模型,也就是我們所建議的基于原型的OOP。
基于原型
這里的基本概念是動態可變對象。轉換(完整轉換,不僅包括值,還包括特性)和動態語言有直接關系。下面這樣的對象可以獨立存儲他們所有的特性(屬性,方法)而不需要的類。
此外,由于動態的,他們可以很容易地改變(添加,刪除,修改)自己的特性:
也就是說,在賦值的時候,如果某些特性不存在,則創建它并且將賦值與它進行初始化,如果它存在,就只是更新。
在這種情況下,代碼重用不是通過擴展類來實現的,(請注意,我們沒有說類沒辦法改變,因為這里根本沒有類的概念),而是通過原型來實現的。
原型是一個對象,它是用來作為其他對象的原始copy,或者如果一些對象沒有自己的必要特性,原型可以作為這些對象的一個委托而當成輔助對象。
基于委托
任何對象都可以被用來作為另一個對象的原型對象,因為對象可以很容易地在運行時改變它的原型動態。
注意,目前我們正在考慮的是概論而不是具體實現,當我們在ECMAScript中討論具體實現時,我們將看到他們自身的一些特點。
例(偽代碼):