您好,登錄后才能下訂單哦!
這篇文章主要介紹“javascript是基于對象還是面對對象”,在日常操作中,相信很多人在javascript是基于對象還是面對對象問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”javascript是基于對象還是面對對象”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
javascript是基于對象的;它是一種基于對象的腳本語言,不僅可以創建對象,也能使用現有的對象。JavaScript標準對于基于對象的定義:語言和宿主的基礎設施由對象來提供,并且JavaScript程序即是一系列相互通訊的對象集合。
本教程操作環境:windows7系統、javascript1.8.5版、Dell G3電腦。
你好,我是前阿里手淘前端負責人winter,這篇文章來自于我在極客時間專欄「重學前端」中講解JavaScript的部分。
與其它的語言相比,JavaScript中的“對象”總是顯得不是那么合群。一些新人在學習JavaScript面向對象時,往往也會有疑惑:為什么JavaScript(直到ES6)有對象的概念,但是卻沒有像其他的語言那樣,有類的概念呢?為什么在JavaScript對象里可以自由添加屬性,而其他的語言卻不能呢?
甚至一些爭論中,有人強調,JavaScript并非“面向對象的語言”,而是“基于對象的語言”,這個說法一度流傳甚廣,而事實上,我至今遇到的持有這一說法的人中,無一能夠回答“如何定義面向對象和基于對象”這個問題。
實際上,基于對象和面向對象兩個形容詞都出現在了JavaScript標準的各個版本當中。我們可以先看看JavaScript標準對基于對象的定義,這個定義的具體內容是:“語言和宿主的基礎設施由對象來提供,并且ECMAScript程序即是一系列互相通訊的對象集合”。這里的意思根本不是表達弱化的面向對象的意思,反而是表達對象對于語言的重要性。
那么,在本篇文章中,我會嘗試讓你去理解面向對象和JavaScript中的面向對象究竟是什么。
我們先來說說什么是對象,因為翻譯的原因,中文語境下我們很難理解“對象”的真正含義。事實上,Object(對象)在英文中,是一切事物的總稱,這和面向對象編程的抽象思維有互通之處。中文的“對象”卻沒有這樣的普適性,我們在學習編程的過程中,更多是把它當作一個專業名詞來理解。
但不論如何,我們應該認識到,對象并不是計算機領域憑空造出來的概念,它是順著人類思維模式產生的一種抽象(于是面向對象編程也被認為是:更接近人類思維模式的一種編程范式)。
那么,我們先來看看在人類思維模式下,對象究竟是什么。
對象這一概念在人類的幼兒期形成,這遠遠早于我們編程邏輯中常用的值、過程等概念。在幼年期,我們總是先認識到某一個蘋果能吃(這里的某一個蘋果就是一個對象),繼而認識到所有的蘋果都可以吃(這里的所有蘋果,就是一個類),再到后來我們才能意識到三個蘋果和三個梨之間的聯系,進而產生數字“3”(值)的概念。
在《面向對象分析與設計》這本書中,Grady Booch替我們做了總結,他認為,從人類的認知角度來說,對象應該是下列事物之一:
一個可以觸摸或者可以看見的東西;
人的智力可以理解的東西;
可以指導思考或行動(進行想象或施加動作)的東西。
有了對象的自然定義后,我們就可以描述編程語言中的對象了。在不同的編程語言中,設計者也利用各種不同的語言特性來抽象描述對象,最為成功的流派是使用“類”的方式來描述對象,這誕生了諸如 C++、Java等流行的編程語言。而 JavaScript 早年卻選擇了一個更為冷門的方式:原型(關于原型,我在下一篇文章會重點介紹,這里你留個印象就可以了)。這是我在前面說它不合群的原因之一。
然而很不幸,因為一些公司政治原因,JavaScript推出之時受管理層之命被要求模仿Java,所以,JavaScript創始人Brendan Eich在“原型運行時”的基礎上引入了new、this等語言特性,使之“看起來更像Java”。
在 ES6 出現之前,大量 JavaScript 程序員試圖在原型體系的基礎上,把JavaScript變得更像是基于類的編程,進而產生了很多所謂的“框架”,比如PrototypeJS、Dojo。事實上,它們成為了某種JavaScript的古怪方言,甚至產生了一系列互不相容的社群,顯然這樣做的收益遠遠小于損失。
如果我們從運行時角度來談論對象,就是在討論JavaScript實際運行中的模型,這是由于任何代碼執行都必定繞不開運行時的對象模型,不過,幸運的是,從運行時的角度看,可以不必受到這些“基于類的設施”的困擾,這是因為任何語言運行時類的概念都是被弱化的。
首先我們來了解一下JavaScript是如何設計對象模型的。
在我看來,不論我們使用什么樣的編程語言,我們都先應該去理解對象的本質特征(參考Grandy Booch《面向對象分析與設計》)。總結來看,對象有如下幾個特點。
對象具有唯一標識性:即使完全相同的兩個對象,也并非同一個對象。
對象有狀態:對象具有狀態,同一對象可能處于不同狀態下。
對象具有行為:即對象的狀態可能因為它的行為產生變遷。
我們先來看第一個特征,對象具有唯一標識性。一般而言,各種語言的對象唯一標識性都是用內存地址來體現的,所以,JavaScript程序員都知道,任何不同的JavaScript對象其實是互不相等,我們可以看下面的代碼,o1和o2初看是兩個一模一樣的對象,但是打印出來的結果卻是false。
var o1 = { a: 1 };var o2 = { a: 1 };console.log(o1 == o2); // false
關于對象的第二個和第三個特征“狀態和行為”,不同語言會使用不同的術語來抽象描述它們,比如C++中稱它們為“成員變量”和“成員函數”,Java中則稱它們為“屬性”和“方法”。
在 JavaScript中,將狀態和行為統一抽象為“屬性”,考慮到 JavaScript 中將函數設計成一種特殊對象(關于這點,我會在后文中詳細講解,此處先不用細究),所以 JavaScript中的行為和狀態都能用屬性來抽象。
下面這段代碼其實就展示了普通屬性和函數作為屬性的一個例子,其中o是對象,d是一個屬性,而函數f也是一個屬性,盡管寫法不太相同,但是對JavaScript來說,d和f就是兩個普通屬性。
var o = { d: 1, f() { console.log(this.d); } };
所以,總結一句話來看,在JavaScript中,對象的狀態和行為其實都被抽象為了屬性。如果你用過Java,一定不要覺得奇怪,盡管設計思路有一定差別,但是二者都很好地表現了對象的基本特征:標識性、狀態和行為。
在實現了對象基本特征的基礎上, 我認為,JavaScript中對象獨有的特色是:對象具有高度的動態性,這是因為JavaScript賦予了使用者在運行時為對象添改狀態和行為的能力。
我來舉個例子,比如,JavaScript 允許運行時向對象添加屬性,這就跟絕大多數基于類的、靜態的對象設計完全不同。如果你用過Java或者其它別的語言,肯定會產生跟我一樣的感受。
下面這段代碼就展示了運行時如何向一個對象添加屬性,一開始我定義了一個對象o,定義完成之后,再添加它的屬性b,這樣操作,是完全沒問題的。這一點你要理解。
var o = { a: 1 };o.b = 2;console.log(o.a, o.b); //1 2
為了提高抽象能力,JavaScript的屬性被設計成比別的語言更加復雜的形式,它提供了數據屬性和訪問器屬性(getter/setter)兩類。
對JavaScript來說,屬性并非只是簡單的名稱和值,JavaScript用一組特征(attribute)來描述屬性(property)。
先來說第一類屬性,數據屬性。它比較接近于其它語言的屬性概念。數據屬性具有四個特征。
value:就是屬性的值。
writable:決定屬性能否被賦值。
enumerable:決定for in能否枚舉該屬性。
configurable:決定該屬性能否被刪除或者改變特征值。
在大多數情況下,我們只關心數據屬性的值即可。
第二類屬性是訪問器(getter/setter)屬性,它也有四個特征。
getter:函數或undefined,在取屬性值時被調用。
setter:函數或undefined,在設置屬性值時被調用。
enumerable:決定for in能否枚舉該屬性。
configurable:決定該屬性能否被刪除或者改變特征值。
訪問器屬性使得屬性在讀和寫時執行代碼,它允許使用者寫入和讀出屬性時得到完全不同的值,它可以視為一種函數的語法糖。
我們通常用于定義屬性的代碼會產生數據屬性,其中的writable、enumerable、configurable都默認為true。我們可以使用內置函數 Object.getOwnPropertyDescripter來查看,如以下代碼所示:
var o = { a: 1 };o.b = 2;//a和b皆為數據屬性 Object.getOwnPropertyDescriptor(o,\u0026quot;a\u0026quot;) // {value: 1, writable: true, enumerable: true, configurable: true} Object.getOwnPropertyDescriptor(o,\u0026quot;b\u0026quot;) // {value: 2, writable: true, enumerable: true, configurable: true}
我們在這里使用了兩種語法來定義屬性,定義完屬性后,我們用JavaScript的API來查看這個屬性,我們可以發現,這樣定義出來的屬性都是數據屬性,writeable、enumerable、configurable都是默認值為true。
如果我們要想改變屬性的特征,或者定義訪問器屬性,可以使用 Object.defineProperty,示例如下:
var o = { a: 1 }; Object.defineProperty(o, \u0026quot;b\u0026quot;, {value: 2, writable: false, enumerable: false, configurable: true});//a和b都是數據屬性,但特征值變化了 Object.getOwnPropertyDescriptor(o,\u0026quot;a\u0026quot;); // {value: 1, writable: true, enumerable: true, configurable: true} Object.getOwnPropertyDescriptor(o,\u0026quot;b\u0026quot;); // {value: 2, writable: false, enumerable: false, configurable: true} o.b = 3;console.log(o.b); // 2
這里我們使用了Object.defineProperty來定義屬性,這樣定義屬性可以改變屬性的writable和enumerable,我們同樣用Object.getOwnPropertyDescriptor來查看,發現確實改變了writable和enumerable特征。因為writable特征為false,所以我們重新對b賦值,b的值不會發生變化。
在創建對象時,也可以使用 get 和 set 關鍵字來創建訪問器屬性,代碼如下所示:
var o = { get a() { return 1 } }; console.log(o.a); // 1
訪問器屬性跟數據屬性不同,每次訪問屬性都會執行getter或者setter函數。這里我們的getter函數返回了1,所以o.a每次都得到1。
這樣,我們就理解了,實際上JavaScript 對象的運行時是一個“屬性的集合”,屬性以字符串或者Symbol為key,以數據屬性特征值或者訪問器屬性特征值為value。對象是一個屬性的索引結構(索引結構是一類常見的數據結構,我們可以把它理解為一個能夠以比較快的速度用key來查找value的字典)。我們以上面的對象o為例,你可以想象一下“a”是key。
這里{writable:true,value:1,configurable:true,enumerable:true}是value。我們在前面的類型課程中,已經介紹了Symbol類型,能夠以Symbol為屬性名,這是JavaScript對象的一個特色。
講到了這里,如果你理解了對象的特征,也就不難理解我開篇提出來的問題。
你甚至可以理解為什么會有“JavaScript不是面向對象”這樣的說法:JavaScript的對象設計跟目前主流基于類的面向對象差異非常大。而事實上,這樣的對象系統設計雖然特別,但是JavaScript提供了完全運行時的對象系統,這使得它可以模仿多數面向對象編程范式(下一節課我們會給你介紹JavaScript中兩種面向對象編程的范式:基于類和基于原型),所以它也是正統的面向對象語言。
JavaScript語言標準也已經明確說明,JavaScript是一門面向對象的語言,我想標準中能這樣說正因為JavaScript的高度動態性的對象系統。
所以,我們應該在理解其設計思想的基礎上充分挖掘它的能力,而不是機械地模仿其它語言。
要想理解JavaScript對象,必須清空我們腦子里“基于類的面向對象”相關的知識,回到人類對對象的樸素認知和面向對象的語言無關基礎理論,我們就能夠理解JavaScript面向對象設計的思路。
在這篇文章中,我從對象的基本理論出發,和你理清了關于對象的一些基本概念,分析了JavaScript對象的設計思路。接下來又從運行時的角度,介紹了JavaScript對象的具體設計:具有高度動態性的屬性集合。
很多人在思考JavaScript對象時,會帶著已有的“對象”觀來看問題,最后的結果當然就是“剪不斷理還亂”了。
到此,關于“javascript是基于對象還是面對對象”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。