Javascript高級程序設計--讀書筆記之面向對象(一)
哈哈哈萬物皆對象,終於到了js的面向對象篇。
一、屬性類型
(1)數據屬性
數據屬性包含一個數據值的位置,在這個位置可以寫入和讀取數值,數據屬性有四個描述器行為的特性
- [[Configurable]]:表示能否通過 delete 刪除屬性而重新定義屬性,默認值是ture
- [[Enumerable]]:表示能否通過 for-in 循環返回該屬性,默認值true
- [[Writable]]:表示能否通過修改屬性的值,默認值true
- [[Value]]:包含這個屬性的數據值,默認值true
要修改默認屬性的特性,必須使用ECMAScript的Objedt.defineProperty()方法,這個方法接受三個參數:函數所在對象、屬性名字和一個描述對象。例
1 var person = {}; 2 Object.defineProperty(person,"name".{ 3 writable:false, 4 value:"Nicholas" 5 }); 6 alert(person.name); //Nicholas 7 person.name = "Greg"; 8 alert(person.name); //Nicholas
(2)訪問器屬性
訪問器屬性包括一對getter和setter函數,在讀取訪問器屬性時,會調用getter函數,這個函數負責返回有效值,寫入訪問器屬性的時候,會調用setter函數並傳入新值,這個函數決定如何處理數值,訪問器屬性有如下4個特性
- [[Configurable]]:能否通過delete刪除屬性並進行重新定義,默認值時true
- [[Enumerable]]:表示能否通過for-in循環返回屬性,默認值時true
- [[Get]]:在讀取屬性時調用的函數,默認值true
- [[Set]]:在寫入屬性時調用的函數,默認值true
訪問器屬性不能直接定義必須使用Obiect.defineProperty()來定義,例
var book = { _year: 2004, edition: 1 }; Object.defineProperty(book,"year", { get: function(){return: this._year; }, set: function(newValue){ if(newValue > 2004){ this._year = newValue; this.edition += newValue - 2004 } } }); var year = 2005; alert(book.edition);
二 創建對象
(1)工廠模式
function createPerson(name, age, job){ var o = new Object() o.name = name o.age = age o.job = job o.sayName = function(){ alert(this.name) } return o } var person = createPerson("Greag", 29, "Software Engineer") person.sayName()
每次調用這個createPerson()都能返回一個三個屬性一個方法的,工廠模式雖然解決了多個相似對象的問題,但卻沒有解決對象識別的問題,於是新的模式就出現了
(2)構造函數模式
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name) } }
var person = new Person("Nic", 22, "Software Engineer")
person.sayName()
構造函數雖然好用但並不是沒有缺點,就是每個方法都要在實例上創建一遍,因為每定義了一個函數就相當於實例化了一個對象,所以構造函數的定義相當與
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName =new Function(
"alert(this.name)"
) // 與聲明函數在邏輯上是相等的
}
var person1 = new Person("Greg", 22, "Doctor");
var person2 = new Person("Nic", 22, "Software Engineer");
這樣就會導致不同的實例上的同名函數是不同的 alert( person1.sayName == person2.sayName) //false 創建兩個完成相同任務的Function完全沒有必要,於是又出現了原型模式
(3)原型模式
我們每創建一個函數都會有一個property(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途就是包含可以由特定的類型的所有實例共享的屬性和方法,也就是我們不必在構造函數中添加對象的信息,可以直接添加到原型對象上,
//原型模式 function Person(){} Person.prototype.name = "Nic" Person.prototype.age = 22 Person.prototype.sayName = function(){ alert(this.name) } var person1 = new Person(); var person2 = new Person(); alert(person1.sayName == person2.sayName) //true
簡潔的原型語法
//簡潔的原型語法 function Person(){} Person.prototype = { name:"Nic", age:22, sayName:function(){ alert(this.name) } }
原型模式也不是沒有缺點,首先他省略了為構造函數傳遞初始化參數這一環節,結果所有實例在相同的情況下都取得相同的屬性值,原型模式最大的問題就是其共享的本質所導致,對於包含引用屬性的來說,問題就很突出。例
function Person(){}; Person.prototype = { constructor: Person, name: "nic", age: 23, friends: ["Court", "shelby"] } var person1 = new Person(); var person2 = new Person(); person1.friends.push("Van") alert(person1.friends) //Court, shelby, Van alert(person2.friends) //Court, shelby, Van alert(person1.friends === person2.friends) //true
我們的初衷往往不是這樣,這也是我們很少看見有人直接用原型模式的原因。
(4)組合使用構造函數和原型模式
創建自定義類型最常見的方式就是組合使用構造函數模式和原型模式,構造函數定義實例屬性,原型模式定義方法和共享屬性,例
//組合構造函數模式和原型模式 function Person(name, age, job){ this.name = name, this.age = age, this.job = job, this.friends = ["Court", "Shelby"] } Person.prototype = { constructor: Person, sayName: function(){ alert(this.name) } } var person1 = new Person("Nic", 23, "Software Engineer") var person2 = new Person("Greg", 22, "Doctor") person1.friends.push("Van") alert(person1.friends) //"Court", "Shelby", "Van" alert(person2.friends) //"Court", "Shelby" alert(person1.friends === person2.friends) //false alert(person1.sayName === person2.sayName) //true
Javascript高級程序設計--讀書筆記之面向對象(一)