==什麼是對象?==
就是無序屬性的集合,經過屬性或者方法名與值的一一映射。
==對象的屬性類型==
對象中還定義了一些js中不能直接訪問的屬性,是爲了實現js引擎用的。有數據屬性和訪問器屬性兩種。
1.數據屬性
數據屬性包含一個數據值的位置。在這個位置能夠讀取和寫入值。數據屬性有 4 個描述其行爲的
特性。app
把新值保存在這個位置。這個特性的默認值爲 undefined。函數
要修改屬性默認的特性,必須使用 ECMAScript 5 的 Object.defineProperty()方法。this
注意:
1》 configurable 設置爲 false,表示不能從對象中刪除屬性。若是對這個屬性調用 delete,則 在非嚴格模式下什麼也不會發生,而在嚴格模式下會致使錯誤。並且,一旦把屬性定義爲不可配置的, 就不能再把它變回可配置。
2》在調用 Object.defineProperty()方法時,若是不指定,configurable、enumerable 和 writable 特性的默認值都是 false。
2.訪問器屬性
訪問器屬性不包含數據值;包含一對兒 getter 和 setter 函數(不過,這兩個函數都不是必需的)。 在讀取訪問器屬性時,會調用 getter 函數,這個函數負責返回有效的值;在寫入訪問器屬性時,會調用 setter 函數並傳入新值,這個函數負責決定如何處理數據。訪問器屬性有以下 4 個特性。spa
[[Get]]:在讀取屬性時調用的函數。默認值爲 undefined。
[[Set]]:在寫入屬性時調用的函數。默認值爲 undefined。
訪問器屬性不能直接定義,必須使用 Object.defineProperty()來定義。prototype
能夠經過Object.definePro- perties()定義多個屬性;
使用 ECMAScript 5 的 Object.getOwnPropertyDescriptor()方法,能夠取得給定屬性的描述符。code
==建立對象的方式==
經過字面量的方式能夠建立對象,可是建立有相似屬性的對象時會產生大量重複代碼。
1.工廠模式
用函數來封裝以特定接口建立對象。對象
缺點就是沒法知道一個對象的類型。
2.構造函數模式繼承
經過構造函數建立的對象能夠經過constructor標識對象類型,經過instanceof檢測對象類型。
構造函數模式與工廠模式對比:
1》沒有顯式地建立對象;
2》直接將屬性和方法賦給了 this 對象;
3》 沒有 return 語句。
經過new操做符調用構造函數會經歷4個步驟:
(1) 建立一個新對象;
(2) 將構造函數的做用域賦給新對象(所以 this 就指向了這個新對象);
(3) 執行構造函數中的代碼(爲這個新對象添加屬性);
(4) 返回新對象。接口
構造函數也可做爲普通函數調用
Person("Greg", 27, "Doctor"); // 添加到window window.sayName(); //"Greg"
也能夠在另外一個對象的做用域中調用
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse"); o.sayName(); //"Kristen"ip
構造函數模式的缺點就是每一個方法都要在每一個實例上從新建立一遍。
function Person(name, age, job){
this.name = name; this.age = age; this.job = job; this.sayName = new Function("alert(this.name)"); // 與聲明函數在邏輯上是等價的
}
alert(person1.sayName == person2.sayName); //false
3.原型模式
經過prototype爲對象添加屬性和方法。這樣實例就能共享原型的屬性和方法。
1》原型具備動態性。在實例化後定義的原型方法,實例也能調用。
2》原型的簡單寫法。
能夠將原型簡寫如上,可是這種寫法其實是從新寫了原型,新原型的constructor已經改變,指向object。因此能夠從新設置constructor。
並且若是在實例化後重寫原型,則已經實例的對象依舊訪問原來原型對象,不能訪問新原型的方法和屬性。
組合使用構造函數模式和原型模式
===繼承===
繼承:利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法。
1.原型鏈繼承
包含引用類型值的原型屬性會被全部實例共享;而 這也正是爲何要在構造函數中,而不是在原型對象中定義屬性的緣由。在經過原型來實現繼承時,原型實際上會變成另外一個類型的實例。因而,原先的實例屬性也就瓜熟蒂落地變成了如今的原型屬性了。
原型鏈的問題是:因爲原型中包含引用類型值所帶來的問題。和在建立子類型的實例時,不能向超類型的構造函數中傳遞參數。實際上,應該說是沒有辦法在不影響全部對象實例的狀況下,給超類型的構造函數傳遞參數。實踐中不多會單獨使用原型鏈。
2.構造函數繼承
借用構造函數:別忘了,函數只不過是在特定環境中執行代碼的對象, 所以經過使用 apply()和 call()方法也能夠在(未來)新建立的對象上執行構造函數。
借用構造函數的問題
若是僅僅是借用構造函數,那麼也將沒法避免構造函數模式存在的問題——方法都在構造函數中定 義,所以函數複用就無從談起了。並且,在超類型的原型中定義的方法,對子類型而言也是不可見的,結 果全部類型都只能使用構造函數模式。考慮到這些問題,借用構造函數的技術也是不多單獨使用的。
組合繼承
組合繼承避免了原型鏈和借用構造函數的缺陷,融合了它們的優勢,成爲 JavaScript 中最經常使用的繼 承模式。