官术网_书友最值得收藏!

  • 全棧開發實戰寶典
  • 優逸客科技有限公司
  • 4273字
  • 2020-06-11 16:16:37

第4章 對象

本章主要內容

● JavaScript對象

● 對象的特性

● ES6中對象的新特性

對象是整個JavaScript 中一個非常重要的概念,是JavaScript 中基本的數據類型。JavaScript 是基于對象的,一個對象就是一系列相關屬性的集合,而屬性包含對應的名字和對應的值。一個屬性的值可以是變量,也可以是函數,當為函數時也稱該屬性為方法。本章將講述對象的基本概念、創建方法、屬性等。

4.1 JavaScript對象

4.1.1 名詞解釋

JavaScript是基于對象的,那么什么是基于對象呢?

1. 基于對象

首先,一切皆對象,要以對象的概念來編程。其次,JavaScript 中有很多內置的對象,如window,所以說JavaScript是基于對象的。

2. 對象

對象就是人們要研究的任何事物,不僅能表示具體事物,還能表示抽象的規則、計劃或事件。例如,人可以看作一個對象,不同的人就是不同的對象。每個人都有自己所屬的屬性,有膚色、年齡、性別等。當然也有自己的方法,如說話、吃飯、學習等。同樣地,JavaScript 對象也有屬性來定義其特征。所以簡單地說,對象就是屬性的無序集合,每個屬性可以存一個值(原始值,對象,函數)。對象的屬性指的就是用數值描述對象的狀態,對象的方法指的就是對象具有可實施的動作。

一個水杯有自己的分類,如保溫杯還是塑料杯等,在JavaScript中,對象也有自己的類。

3. 類

具有相同或相似的性質的對象的抽象就是類。對象的抽象就是類,類的具體化(實例化)叫作對象。在JavaScript中是通過構造函數來實現類的。

4. 面向過程

面向過程是一種以過程為中心的編程思想。面向過程就是分析出解決問題所需要的步驟,然后用函數把這些步驟一步一步地實現,使用時一個一個依次調用即可。它是一種思考問題的基礎方法。

5. 面向對象

面向對象是軟件開發中的一種,是思考問題相對高級的方法。它把構成問題的事務分解成各個對象,建立對象的目的不是為了完成一個步驟,而是為了描述某個事物在整個解決問題的步驟中的行為。

這里給大家舉個示例幫助理解記憶:

汽車發動,汽車到站。汽車發動是一個事件,汽車到站是另一個事件,在面向過程中我們關心的是事件,而不是汽車本身,針對上述兩個事件,形成兩個函數,之后依次調用。

對面向對象來說,我們關心的是汽車這類對象,兩個事件只是這類對象所具有的行為,且對于這兩個行為的順序沒有強制要求。

面向過程的思維方式是分析綜合,面向對象的思維方式是構造。

4.1.2 創建對象的方法

JavaScript 擁有很多內置的對象。除此以外,也可以創建自己的對象。創建方法和其他語言大同小異。

1. 通過Object方法(JavaScript頂層構造函數)創建

語法如下:

示例:

說明:通過Object方法創建對象,實則指的是通過JavaScript的原生對象的構造方法,實例化一個新對象。

2. 通過json方式創建

此方法多用于數據的存儲,語法如下:

示例1:

說明:這也是非常簡單的一種方法,一般情況下不推薦使用,因為這種方法可讀性不夠強。請看示例2。

示例2:

說明:相比較示例 1,示例 2 中嵌套的方法可讀性很強,對象 lisi 的所有屬性和方法都包含在其自身內,一目了然。

以上兩種方法適用于只存在一個實例的對象。當需要創建多個對象實例時,就需要通過構造函數的方法來創建。

3. 通過構造函數創建

通過構造函數來創建對象類型時,最好首字母是大寫的。

語法如下:

JavaScript中沒有類這一概念,需要用函數的方式來模擬類,這個函數就是構造函數。

示例:

說明:通過使用this 將傳入函數的值賦值給對象的屬性,this 代表誰實例化它,它就指誰?,F在就可以創建多個Person對象實例了。

4.1.3 屬性與方法

1. 添加屬性與方法

當屬性的值為函數時就是對象的方法,其他都為屬性。

格式:

為對象添加屬性除了上述方法外,還可以通過prototype(原型)屬性來為對象添加屬性。

JavaScript 中為每個函數都分配了prototype 屬性,該屬性是個指針,指向一個對象,作為所有實例的基類引用。

示例:

2. 方法

格式:

示例同創建對象。

3. 訪問屬性

格式:

4. 訪問方法

格式:

4.1.4 銷毀對象

銷毀對象的格式如下:

JavaScript的垃圾回收機制在對象不被引用時釋放內存。

刪除對象上的屬性:可以用delete 來刪除對象上一個不是通過集成而來的屬性,示例如下。

4.1.5 對象的遍歷

對象的遍歷使用for...in方法。

示例:

4.1.6 對象的存儲方式

1)變量保存的僅僅是對象的引用地址。

2)對象保存在堆中,每創建一個對象,就開辟一塊內存。

3)當JavaScript引擎檢測到對象沒有引用時,將把它當作垃圾,等待回收。

4)在某一時刻回收垃圾對象。

對象的存儲方式如圖4-1所示。

圖4-1

4.1.7 instanceof

instanceof運算符用來檢測某個對象是否是某個構造函數的實例。

示例:

任何對象對Object構造函數進行判斷,結果都是true,因為Object()是JavaScript中的頂層構造函數。

4.2 對象的特性

4.2.1 對象的特性——封裝

封裝是將對象的所有組成部分組合起來,盡可能地隱藏對象的部分細節,使其受到保護,只提供有限的接口與外部發生聯系。

下面介紹封裝方法。

(1)工廠函數(不推薦使用)

示例:

(2)構造函數(每創建一個對象,會把相同的代碼存儲到內存中,會造成對內存的浪費)

示例:

(3)prototype方法(會把共享的方法或屬性放到代碼段中來存儲,它不能共享對象)

示例1:

示例2:

(4)混合函數

這是一種最佳的方法,構造函數與prototype的結合,應根據實際情況考慮。

示例:

4.2.2 對象的特性——繼承

繼承是一個對象擁有另一個對象的屬性與方法。所有的JavaScript 對象繼承于至少一個對象,并且繼承的屬性可通過構造函數的prototype 對象找到。

對象的一個類可以從現有的類中派生出來,并且它擁有現有的類的方法與屬性,這個過程就是繼承。

父類(基類/原型)是被繼承的對象,子類是繼承的對象。

1. 繼承優點

通過繼承可以提高代碼的重用性、邏輯性與可維護性。

2. 繼承的方式

(1)通過原型來繼承

示例:

說明:這種方式實現繼承最為簡單,只需讓子類的prototype 屬性賦值為被繼承的一個實例化對象即可,之后就可以直接使用被繼承類的方法和屬性了。

(2)call方法

格式:

從本質上來說,call方法實際上就是要改變fun函數內的this指向。

示例:

(3)apply方法

用法基本與call方法相同,格式如下:

示例:

3. 繼承的順序

優先級:對象本身>構造函數>原型鏈。

示例:

4.2.3 this指針

本章很多內容中都提到了this,本節專門針對this為讀者進行詳細講解。

大家肯定會困惑,為什么要在編程中用this?this到底代表什么呢?

JavaScript 是一門基于對象的語言,也就是說,一切皆對象,函數也是一個普通的對象。JS可以通過一定的設計模式來實現面向對象的編程,其中this指針就是實現面向對象的一個很重要的特性。

示例:

說明:上述示例是一個普通的函數,通過調用say函數,彈出全局變量name。

下面把上面的示例稍作修改:

說明:定義一個全局對象say并執行這個函數,函數內部使用this關鍵字,執行this對象時執行代碼的對象是say,say 被定義在全局作用域中。JS 中所謂的全局對象,無非就是定義在window 這個對象下的一個屬性而已。因此say 的所有者是window 對象。也就是說,在全局作用域下,可以通過直接使用name 去引用這個對象,也可以通過window.name去引用同一個對象。因此,this.name就可以翻譯為window.name了。

兩個示例最終運行結果一樣,說明this.name引用的還是全局的name對象。

JavaScript 是一門動態語言,某一個函數中的this 最終代表誰取決于調用模式。接下來通過示例幫助讀者更好地理解this指向問題。

1)在普通函數中,this總是指向window全局對象,代碼如下:

2)當函數作為對象的方法使用時,this指向的是當前對象,代碼如下:

3)在構造函數中,this指向的是該構造函數實例化出來的對象,代碼如下:

4)在call和apply中,this指的是方法中傳入的對象,如果apply中沒有傳入對象,則this指向window,代碼如下:

4.2.4 對象的分類

1)內置對象:直接使用即可,不需要實例化。

內置頂層對象(global):Math();

2)本地對象:需要實例化后才能使用,如String();、Boolean();、Number();、Function();、Array();。

3)宿主對象:BOM和DOM,詳細內容參考第6章。

4.3 ES6中對象的新特性

4.3.1 類的支持

前文已經提到JavaScript 中沒有類,但是在ES6 中添加了對類的支持,引入了class 關鍵字(class在JavaScript中是保留字,在ES6新版本中,派上了用場)。

下面通過一個示例來展示類的用法:

4.3.2 變量的解構賦值

在ES6中,允許按照一定的模式,從數組和對象中提取值,對變量進行賦值,這就稱為解構。下面通過一些示例來介紹解構賦值的應用。

1. 數組的解構賦值

示例:

說明:從數組中提取值時,會按照對應的位置對變量進行賦值。如果解構不成功,則變量的值就等于undefined。

2. 對象的解構賦值

解構賦值不僅可以用于數組,還可以用于對象。對象的解構賦值和數組有一個重要的不同:數組的元素是按照內容的順序依次進行對應位置的賦值,而對象的屬性是沒有順序的,變量必須與屬性同名才能進行正確的賦值。

示例:

說明:上述示例中,a 是匹配的模式,c 才是變量。真正被賦值的是變量c,而不是模式a。

3. 字符串的解構賦值

字符串也可以解構賦值。這是因為此時,字符串被轉換成了一個類似數組的對象。

示例:

4. 函數參數的解構賦值

函數的參數也可以使用解構賦值。

示例:

說明:上述示例中,add 函數的參數表面上是一個數組,但在傳入參數的那一刻,數組參數就被解構成變量x和y。對于函數內部的代碼來說,它們能接收到的參數就是x和y。

更多有關ES6中函數的相關內容可參考3.3節。

4.3.3 擴展運算符(spread)和rest參數

1. 擴展運算符

擴展語法:擴展運算符是3 個點(...),允許在需要多個參數(用于函數回調)或多個元素(用于數組文本)或多個變量(用于解構分配)的位置擴展表達式。

(1)數組中

擴展運算符的作用是將一個數組轉為用逗號分隔的參數序列。

示例:

說明:從上述示例可以看出,擴展運算符可以用來替換數組中的concat函數,實現數組合并。

示例:

(2)對象中

ES6對對象也做了擴展,方法與數組類似。

示例:

說明:對對象進行擴展運算,實現的是對象的淺復制,并且是復制對象的可枚舉的屬性。

(3)函數中

如果一個函數的最后一個形參是以“…”為前綴的,則在函數被調用時,該形參會成為一個數組,數組中的元素都是傳遞給該函數的多出來的實參的值。

示例:

說明:在上述示例中,theArgs 會包含傳遞給函數的從第3 個實參開始到最后所有的實參(第1個實參映射到a,第2個實參映射到b)。

2.rest參數

ES6 中引入了rest 參數(…變量名)。通常,需要創建一個可變參數的函數,之前都是借助arguments對象?,F在使用rest參數就可以創建可變參數的函數。

3.1.3節中有關傳入參數個數不同,故進行不同操作的示例,這里就不做過多介紹了。

下面是個有關rest參數的示例:

似乎看上去使用rest 參數和arguments 對象的運行結果一樣,但是它們之間還是有本質區別的。

rest參數和arguments對象的區別如下:

1)剩余參數只包含那些沒有對應形參的實參。

2)arguments對象包含了傳給函數的所有實參。

3)arguments 對象不是一個真實的數組,而剩余參數是真實的數組實例,即能夠在其上直接使用所有的數組方法,如sort、map、forEach、pop。

4.3.4 屬性的簡潔表示

ES6允許在對象之中直接寫變量。這時,屬性名為變量名,屬性值為變量的值。

示例:

屬性的簡潔表示用于函數的返回值非常方便,示例如下:

取值器和賦值器中的用法如下:

4.3.5 屬性名表達式

ES6中,在使用字面量定義對象時,可以把表達式放到方括號中作為屬性名。

示例:

4.3.6 方法的name屬性

方法也是函數,所以方法也有name屬性,示例如下:

主站蜘蛛池模板: 崇州市| 海南省| 涟水县| 普格县| 营山县| 金川县| 南郑县| 安泽县| 通州市| 太保市| 都兰县| 林周县| 香格里拉县| 永仁县| 兰州市| 大方县| 新安县| 卢湾区| 台东县| 沂源县| 和田县| 宜昌市| 怀柔区| 孝感市| 上蔡县| 合水县| 敖汉旗| 铅山县| 镇康县| 东台市| 桐柏县| 廉江市| 荥经县| 台中市| 乡宁县| 广平县| 兴和县| 通河县| 修武县| 玉门市| 易门县|