JavaScript 中的面向對象編程
介紹
JavaScript 是一個強大的面向對象編程語言,但是,並不像傳統的編程語言,它採用一個以原型為基礎的OOP模型,致使它的語法讓大多數開發人員看不懂。另外,JavaScript 也把函數作為首要的對象,這可能會給不夠熟悉這門語言的開發人員造成更大的困惑。那就是我們決定放在前面作為一個簡短前言進行介紹的原因,並且在 JavaScript 里也可以用作面向對象編程的一個參考。
這個文檔沒有提供一個面向對象編程的規則預覽,但有它們的介面概述。
命名空間
隨著越來越多的第三方庫,框架和web依賴的出現,JavaScript發展中的命名空間是勢在必行的,我們得盡量避免在全局命名空間的對象和變數的衝突。
不幸的是,JavaScript沒有提供支持命名空間的編譯,但是我們可以使用對象來得到同樣結果。在JavaScript中我們有許多種模式來實現命名空間介面,但是我們覆蓋嵌套的命名空間,它在該領域是最常用的模式。
嵌套命名空間
嵌套的命名空間模式使用對象字面量來捆綁一個特定應用的特定名字的功能。
我們最初創建一個全局對象,並且賦值給一個稱為MyApp的變數。
上述的語法會檢查MyApp是否已經被定義過。假如它已經被定義過,我們簡單地把它賦值給自己,但是,我們創建一個空的容器來裝載我們的函數和變數。
我們也可以使用相同技術來創建子命名空間。例如:
我們一旦啟動我們的容器,我們可以在(容器)內部定義我們的函數和變數,並且在全局命名空間調用它們,不需要冒著與現有定義衝突的風險。
在JavaScript命名模式的一個內部概述是由Goggle的Addy Osmani在Essential JavaScript Namespacing Patterns的文章中介紹的。假如你想探索不同的模式,這裡將是一個美好的起點。
對象
如果你寫過 JavaScript 代碼,那你已經使用過對象了。JavaScript 有三種類型的對象:
原生對象
原生對象是語言規範的一部分,不管在什麼樣的運行環境下運行,原生對象都可用。原生對象包括:Array、Date、Math 和 parseInt 等。想了解所有原生對象,請參閱 JavaScript 內建對象參考
宿主對象
與原生對象不同,宿主對象是由 JavaScript 代碼運行的環境創建。不同的環境環境創建有不同的宿主對象。這些宿主對象在多數情況下都允許我們與之交互。如果我們寫的是在瀏覽器(這是其中一種運行環境)上運行的代碼,會有 window、document、location 和 history 等宿主對象。
用戶對象
用戶對象(或植入對象)是在我們的代碼中定義的對象,在運行的過程中創建。JavaScript 中有兩種方式創建自己的對象,下面詳述。
對象字面量
在前面演示創建命名空間的時候,我們已經接觸到了對象字面量。現在來搞清楚對象字面量的定義:對象字面量是置於一對花括弧中的,由逗號分隔的名-值對列表。對象字面量可擁有變數(屬性)和函數(方法)。像 JavaScript 中的其它對象一樣,它也可以作為函數的參數,或者返回值。
現在定義一個對象字面量並賦予一個變數:
向這個對象字面量添加屬性和方法,然後在全局作用域訪問:
這看起來和前面的命名空間很像,但這並不是巧合。字面量對象最典型的用法就是把代碼封裝起來,使之在一個封裝的包中,以避免與全局作用域中的變數或對象發生衝突。由於類似的原因,它也常常用於向插件或對象傳遞配置參數。
如果你熟悉設計模式的話,對象字面量在某種程度上來說就是單例,就是那種只有一個實例的模式。對象字面量先天不具備實例化和繼承的能力,我們接下來還得了解 JavaScript 中另一種創建自定義對象的方法。
構造函數
定義構造函數
函數是 JavaScript 一等公民,就是說其它實體支持的操作函數都支持。在 JavaScript 的世界,函數可以在運行時進行動態構造,可以作為參數,也可以作為其它函數的返回值,也可被賦予變數。而且,函數也可以擁有自己的屬性和方法。JavaScript 中函數的特性使之成為可以實體化和繼承的東西。
來看看怎麼用構造函數創建一個自定義的對象:
創建構造函數類似於創建普通函數,只有一點例外:用 this 關鍵字定義自發性和方法。一旦函數被創建,就可以用 new 關鍵字來生成實例並賦予變數。每次使用 new 關鍵字,this 都指向一個新的實例。
構建函數實例化和傳統面向對象編程語言中的通過類實例化並非完全不同,但是,這裡存在一個可能不易被察覺的問題。
當使用 new 關鍵字創建新對象的時候,函數塊會被反覆執行,這使得每次運行都會產生新的匿名函數來定義方法。這就像創建新的對象一樣,會導致程序消耗更多內存。這個問題在現代瀏覽器上運行的程序中並不顯眼。但隨著應用規則地擴大,在舊一點的瀏覽器、計算機或者低電耗設備中就會出現性能問題。不過不用擔心,有更好的辦法將方法附加給構造函數(是不會污染全局環境的哦)。
方法和原型
前面介紹中提到 JavaScript 是一種基於原型的編程語言。在 JavaScript 中,可以把原型當作對象模板一樣來使用。原型能避免在實例化對象時創建多餘的匿名函數和變數。
在 JavaScript 中,prototype 是一個非常特別的屬性,可以讓我們為對象添加新的屬性和方法。現在用原型重寫上面的示例看看:
這個示例中,不再為每個 Person 實例定義 sayHey 方法,而是通過原型模板在各實例中共享這個方法。
繼承性
通過原型鏈,原型可以用來實例繼承。JavaScript 的每一個對象都有原型,而原型是另外一個對象,也有它自己的原型,周而復始…直到某個原型對象的原型是 null——原型鏈到此為止。
在訪問一個方法或屬性的時候,JavaScript 首先檢查它們是否在對象中定義,如果不,則檢查是否定義在原型中。如果在原型中也沒找到,則會延著原型鏈一直找下去,直到找到,或者到達原型鏈的終端。
現在來看看代碼是怎麼實現的。可以從上一個示例中的 Person 對象開始,另外再創建一個叫 Employee 的對象。
現在 Employee 只有一個屬性。不過既然員工也屬於人,我們希望它能從 Person 繼承其它屬性。要達到這個目的,我們可以在 Employee 對象中調用 Person 的構造函數,並配置原型鏈。
要適應原型繼承還需要一些時間,但是這一個必須熟悉的重要概念。雖然原型繼承模型常常被認為是 JavaScript 的弱點,但實際上它比傳統模型更強大。比如說,在掌握了原型模型之後創建傳統模型簡直就太容易了。
ECMAScript 6 引入了一組新的關鍵字用於實現 類。雖然新的設計看起來與傳統基於類的開發語言非常接近,但它們並不相同。JavaScript 仍然基於原型。
結論
JavaScript已經經過了長時間的發展,在此期間,按今天的標準來看,一些本不應該使用的方法,卻被大量開發者使用著。根據 ES2015 的介紹,這種狀況正開始慢慢改變,然而,許多開發人員仍然堅持使用一些舊的編程方式,這損害了他們的代碼的關聯性。理解面向對象編程方法,並將它應用在你的JavaScript項目中,對於編寫可持續的代碼非常有意義。
我希望這個簡短的介紹將有助於你達到這個目標。
譯者:邊城, xufuji456, 昌偉兄, 混元歸一
譯文:http://www.oschina.net/translate/object-oriented-programming-javascript
原文:http://1bytebeta.com/object-oriented-programming-javascript/
點擊展開全文
※如何學習Javascript
※當一個程序員寫不出代碼了,該怎麼辦?
※誰說 JavaScript 簡單的?
※菊花綻放:微信是如何識別小程序碼的?
※4種JavaScript的內存泄露及避免方法
TAG:JavaScript |
※AppleCare+ for Mac正式面向中國市場推出
※蘋果AppleCare+for Mac正式面向中國市場推出
※思科聯合Pure Storage發布面向AI的FlashStack融合系統
※TensorFlow官方最新tf.keras指南:面向對象構建深度網路
※Google發布面向Linux和Mac的VR180 Creator
※Dell宣布與Google合作:面向商務領域推出Chromebook
※Facebook Reality Labs正式成立面向VR/AR開發
※Google只發布面向Linux和Mac的VR180 Creator
※Bantam Tools 桌面 PCB 銑床通過 Digi-Key 面向全球即時供貨
※微軟Chromium版Edge瀏覽器Dev版面向Windows 7/8.1推出
※Silicon Labs Giant Gecko系列1 MCU在貿澤開售 面向性能密集型物聯網應用
※Fitbit面向合作夥伴推出Inspire健身追蹤器 概不零
※三星或正在研發第二款Bixby智能音箱,對標Google Home Mini面向低端市場
※面向未來的工作?——《Unnatural death》告訴你
※微軟面向醫療機構推出Healthcare Bot服務
※華為面向全球發布AI-Native資料庫GaussDB
※GitHub Education現正面向所有學校開放
※谷歌 I/O 開發者大會上的 Smart Compose 功能開始面向 Gmail 桌面用戶公測
※面向 JS 開發者的機器學習框架 TensorFlow.js 以及相關示例
※Matterport公司面向開發者推出3D SDK