## 對象
JavaScript是面向對象編程(Object Oriented Programming,OOP)語言。
面對對象編程的核心思想就是是將真實世界中各種復雜的關系,抽象成一個個對象,然后由對象之間分工合作,完成對真實世界的模擬。
**何為對象?**
對象是單個實物的抽象。
一本書、一輛汽車、一個人都可以是“對象”,一個數據庫、一張網頁也可以是“對象”。世界上所有的對象都可以是“對象”。
對象是一個容器,封裝了“**屬性**”(property)和“**方法**”(method)。
屬性,就是對象的狀態,而方法,就是對象的行為。比如:我們可以把一輛汽車抽象成一個對象,它的屬性就是它的顏色、重量等,而方法就是它可以啟動、停止等。
**1、對象**
在Javascript中,對象是一個基本數據類型。
對象是一種復合值:它將很多值聚合子啊一起,可通過名字訪問這些值。對象也可看做一種無序的數據集合,由若干個“鍵值對”(key-value)構成。
```
var o={
name:'a'
}
```
上面代碼中,大括號定義了一個對象,它被賦值給變量o。這個對象內部包含一個鍵值對(又稱為“成員”),name是“鍵名”(成員的名稱),字符串a是“鍵值”(成員的值)。
鍵名與鍵值之間用冒號分隔。如果對象內部包含多個鍵值對,每個鍵值對之間用逗號分隔。
**鍵名**:對象的所有鍵名都是字符串,所以加不加引號都可以。如果鍵名是數值,會被自動轉為字符串。
對象的每一個“鍵名”又稱為“屬性”(property),它的“鍵值”可以是任何數據類型。如果一個屬性的值為函數,通常把這個屬性稱為“方法”,它可以像函數那樣調用。
```
var o = {
go: function(x){
return x+1;
}
};
o.go(2) // 3
```
如果鍵名不符合標識名的條件(比如第一個字符為數字,或者含有空格或運算符),也不是數字,則必須加上引號,否則會報錯。
```
var o = {
'1a' : 'a'
}
```
上面的代碼中,如果鍵名'1a'不用引號引起來,就會報錯。
注意:為了避免這種歧義,JavaScript規定,如果行首是大括號,一律解釋為語句(即代碼塊)。如果要解釋為表達式(即對象),必須在大括號前加上圓括號。
**2、創建對象**
在JavaScript中,有三種方法創建對象
- 對象直接量: var o={};
- 關鍵字new: var o=new Object();
- Object.create()函數: var o=Object.create(null)
**2.1對象直接量**
對象直接量是由若干名/值對組成的映射表。鍵名與鍵值之間用冒號分隔。如果對象內部包含多個鍵值對,每個鍵值對之間用逗號分隔。整個映射表用花括號括起來。
在ECMAScript 5中,保留字可以用做不帶引號的屬性名。
注意:對象直接量中的最后一個屬性后的逗號可有可無,但是在ie中,如果多了一個逗號,會報錯。 2.2通過new創建對象
new運算符創建并初始化一個新對象。關鍵字new后跟隨一個函數調用,這個函數稱做構造函數(constructor)。
例子:
```
var o1 = {};
var o2 = new Object();
var o3 = Object.create(null);
```
上面三行語句是等價的。
對象最常見的用法是創建(create)、設置(set)、查找(query)、刪除(delete)、檢測(test)和枚舉(enumerate)它的屬性。 屬性包括名字(鍵名)和值(鍵值)。
屬性名可以是包含空字符串在內的任意字符串,但對象中不能存在兩個同名的屬性。
**提取方法**
如果對對象中的方法進行提取,則會失去與對象的連接。
```
var obj = {
name: 'a',
get: function() {
console.log(this.name);
}
};
console.log(obj.get()); // "a"
var func = obj.get;
console.log(func()); // undefined
```
在上面的例子中,object對象中有一個方法get(),用來獲取obj對象中的name,而當get()方法賦值給一個變量func,再調用func()函數時,此時的this是指向window的,而非obj的。
注意:如果在嚴格模式下,this會是undefined。
**3、屬性特性**
- 可寫(writable attribute):可設置該屬性的值。
- 可枚舉(enumerable attribute):可通過for/in循環返回該屬性。
- 可配置(configurable attribute):可刪除或修改屬性。
**4、讀取屬性**
讀取對象的屬性,有兩種方法,一種是使用點運算符,還有一種是使用方括號運算符。
```
var o = {
name : 'a'
}
o.name // "a"
o['name'] //"a"
```
注意:數值鍵名不能使用點運算符(因為會被當成小數點),只能使用方括號運算符。
JavaScript對象是動態的,可新增屬性也可刪除屬性。但注意,我們是通過引用而非值來操作對象。
**5、屬性的查詢和設置**
在JavaScript中,我們可以通過點(.)或方括號([])運算符來獲取屬性的值。運算符左側應當是一個表達式,它返回一個對象。
**(1)for...in**
for...in循環用來遍歷一個對象的全部屬性。
```
var o = {
name : 'a',
age : 12
}
for(var i in o){
console.log(o[i]
}
// "a"
// 12
```
**(2)查看所有屬性**
查看一個對象本身的所有屬性,可以使用Object.keys方法,返回一個數組。
```
var o = {
name : 'a',
age : 12
}
Object.keys(o) //['name','age']
```
**(3)刪除屬性**
delete運算符可以刪除對象的屬性。
```
var o={
name : 'a'
}
delete o.name //true
o.name //undefined
```
注意:delete運算符只能刪除自有屬性,不能刪除繼承屬性。
刪除一個不存在的屬性,delete不報錯,而且返回true。
只有一種情況,delete命令會返回false,那就是該屬性存在,且不得刪除。
**(4)檢測屬性**
在JavaScript中,有多種方法檢測某個屬性是否存在于某個對象中。
用“!==”來判斷一個屬性是否是undefined
**(5)hasOwnPreperty()方法**
用于判斷一個對象自身(不包括原型鏈)是否具有指定名稱的屬性。如果有,返回true,否則返回false。
**(6)propertyIsEnumerable()方法**
只有檢測到是自有屬性且這個屬性的可枚舉性為true時才返回true。
**(7)in運算符**
in運算符左側是屬性名(字符串),右側是對象。如果對象的自有屬性或繼承屬性中包含這個屬性就返回true。
```
var o = {
name : 'a'
}
'name' in o //true
```
**6、對象的三個屬性**
每一個對象都有與之相關的原型(prototype)、類(class)和可擴展性(extensible attribute)
將對象作為參數傳入Object.getPrototypeOf()可以查詢它的原型。
檢測一個對象是否是另一個對象的原型,可以使用isPrototypeOf()方法。
**7、序列化對象**
對象序列化是指將對象的狀態轉換為字符串,也可將字符串還原為對象。
在JavaScript中,提供了內置函數**JSON.stringify()**和**JSON.parse()**用來序列化和還原JavaScript對象。
NaN、Infinity和-Infinity序列化的結果是null
```
var o = {
name : 'a',
age : 12,
intro : [false,null,'']
}
s= JSON.stringify(o) // s {"name":"a","age":12,"intro":[false,null,""]}
p=JSON.parse(s) // p是o的深拷貝
```
注意:JSON.stringify()只能序列化對象可枚舉的自有屬性。對于一個不能序列化的屬性來說,在序列化后的輸出字符串中會將這個屬性省略掉。
**8、構造函數**
構造函數,是用來生成“對象”的函數。一個構造函數可生成多個對象,這些對象都有相同的結構。
構造函數的特點:
- 函數體內使用了this關鍵字,代表了所要生成的對象實例
- 生成對象時,必需用new命令
- 構造函數名字的第一個字母通常大寫。
例子:
```
function Car(){
this.color = 'black';
}
var c = new Car();
```
上面的代碼生成了Car的實例對象,保存在變量c中。
構造函數也可以傳入參數:
```
function Car(color){
this.color = color;
}
var c = new Car('red');
```
new命令本身就可以執行構造函數,所以后面的構造函數可以帶括號,也可以不帶括號。下面兩行代碼是等價的。
```
var c = new Car();
var c = new Car;
```
每一個構造函數都有一個prototype屬性。
**8.1 this關鍵字**
this總是返回一個對象,簡單說,就是返回屬性或方法“當前”所在的對象。
this.property
上面的代碼中,this就代表property屬性當前所在的對象。
由于對象的屬性可以賦給另一個對象,所以屬性所在的當前對象是可變的,即this的指向是可變的。
```
var A = {
name: '張三',
describe: function(){
return this.name;
}
};
var B = {
name: '李四'
};
B.describe = A.describe;
B.describe();
// "李四"
```
注意:如果一個函數在全局環境中運行,那么this就是指頂層對象(瀏覽器中為window對象)。
**8.1.1 改變this指向**
在JavaScript中,提供了call、apply、bind三種方法改變this的指向。
**(1)funciton.prototype.call()**
```
call(obj, arg1, arg2, ...)
```
第一個參數obj是this要指向的對象,也就是想指定的上下文;arg1,arg2..都是要傳入的參數。
注意:如果參數為空、null和undefined,則默認傳入全局對象。
**(2)funciton.prototype.apply()**
```
apply(obj,[arg1,arg2....])
```
apply()和call()方法原理類似,只不過,它第二個參數一個數組,里面的值就是要傳入的參數。
**(3)function.prototype.bind()**
bind方法用于將函數體內的this綁定到某個對象,然后返回一個新函數。
```
bind(obj)
```
更多:[JS中的call、apply、bind方法](http://ghmagical.com/article/page/id/UPLfoGI9vJ91)
**9、原型**
**9.1 原型**
每一個JavaScript對象(null除外)都和另一個對象相關聯,也可以說,繼承另一個對象。另一個對象就是我們熟知的“原型”(prototype),每一個對象都從原型繼承屬性。只有null除外,它沒有自己的原型對象。
所有通過對象直接量創建的對象都具有同一個原型對象,并可以通過JavaScript代碼Object.prototype獲得對原型對象的引用。
通過關鍵字new和構造函數調用創建的對象的原型就是構造函數的prototype屬性的值。比如:通過new Object()創建的對象繼承自Object.prototype;通過new Array()創建的對象的原型就是Array.prototype。
沒有原型的對象為數不多,Object.prototype就是其中之一,它不繼承任何屬性。
所有的內置構造函數都具有一個繼承自Object.prototype的原型。
**9.2 原型鏈**
對象的屬性和方法,有可能是定義在自身,也有可能是定義在它的原型對象。由于原型本身也是對象,又有自己的原型,所以形成了一條原型鏈(prototype chain)。比如,a對象是b對象的原型,b對象是c對象的原型,以此類推。
如果一層層地上溯,所有對象的原型最終都可以上溯到Object.prototype,即Object構造函數的prototype屬性指向的那個對象。那么,Object.prototype對象有沒有它的原型呢?回答可以是有的,就是沒有任何屬性和方法的null對象,而null對象沒有自己的原型。
**“原型鏈”的作用**:
當讀取對象的某個屬性時,JavaScript引擎先尋找對象本身的屬性,如果找不到,就到它的原型去找,如果還是找不到,就到原型的原型去找。如果直到最頂層的Object.prototype還是找不到,則返回undefined。
**繼承**
JavaScript對象具有“自有屬性”,也有一些屬性是從原型對象繼承而來的。
當查詢一個不存在的屬性時,JavaScript不會報錯,返回undefined。
如果對象自身和它的原型,都定義了一個同名屬性,那么優先讀取對象自身的屬性,這叫做“覆蓋”(overiding)。
**9.2.1 contructor屬性**
prototype對象有一個constructor屬性,默認指向prototype對象所在的構造函數。
**9.3 操作符**
**(1)instanceof運算符**
instanceof運算符返回一個布爾值,表示指定對象是否為某個構造函數的實例。
```
var c = new Car();
c instanceof Car //true
```
instanceof運算符的左邊是實例對象,右邊是構造函數。它的運算實質是檢查右邊構建函數的原型對象,是否在左邊對象的原型鏈上。
**(2)Object.getPrototypeOf()**
Object.getPrototypeOf方法返回一個對象的原型。這是獲取原型對象的標準方法
```
Object.getPrototypeOf(c) === Car.prototype //true
```
**(3)Object.setPrototypeOf()**
Object.setPrototypeOf方法可以為現有對象設置原型,返回一個新對象。Object.setPrototypeOf方法接受兩個參數,第一個是現有對象,第二個是原型對象。
**(4)Object.create()**
Object.create方法用于從原型對象生成新的實例對象,可以替代new命令。
它接受一個對象作為參數,返回一個新對象,后者完全繼承前者的屬性,即原有對象成為新對象的原型。
**(5)Object.prototype.isPrototypeOf()**
對象實例的isPrototypeOf方法,用來判斷一個對象是否是另一個對象的原型。
```
Object.prototype.isPrototypeOf({}) //true
```
**(6)Object.prototype.__proto__**
`__proto__`屬性(前后各兩個下劃線)可以改寫某個對象的原型對象。
**(7)Object.getOwnPropertyNames()**
Object.getOwnPropertyNames方法返回一個數組,成員是對象本身的所有屬性的鍵名,不包含繼承的屬性鍵名。
**(8)Object.prototype.hasOwnProperty()**
對象實例的hasOwnProperty方法返回一個布爾值,用于判斷某個屬性定義在對象自身,還是定義在原型鏈上。
- 前言
- JavaScript簡介
- 基本概念
- 語法
- 數據類型
- 運算符
- 表達式
- 語句
- 對象
- 數組
- 函數
- 引用類型(對象)
- Object對象
- Array對象
- Date對象
- RegExp對象
- 基本包裝類型(Boolean、Number、String)
- 單體內置對象(Global、Math)
- console對象
- DOM
- DOM-屬性和CSS
- BOM
- Event 事件
- 正則表達式
- JSON
- AJAX
- 表單和富文本編輯器
- 表單
- 富文本編輯器
- canvas
- 離線應用
- 客戶端存儲(Cookie、Storage、IndexedDB)
- HTML5 API
- Video/Audio
- Geolocation API
- requestAnimationFrame
- File API
- FullScreen API
- IndexedDB
- 檢測設備方向
- Blob
- vibrate
- Luminosity API
- WebRTC
- Page Visibility API
- Performance API
- Web Speech
- Notification
- 面向對象的程序設計
- 概述
- this關鍵字
- 原型鏈
- 作用域
- 常用API合集
- SVG
- 錯誤處理機制
- JavaScript開發技巧合集
- 編程風格
- 垃圾回收機制