- 我們可以ECMAScript的對象想象成散列表:無非就是一組名值對连茧,其中值是數(shù)據(jù)或函數(shù)鲤拿。
- 每個對象都是基于一個引用類型創(chuàng)建的恶迈,這個引用類型可以使第五章討論的原生類型款票,也可以是開發(fā)人員定義的類型踏幻。
6.1 理解對象
對象字面量方法
6.1.1 屬性類型
ECMAScript中有兩種屬性:數(shù)據(jù)屬性和訪問器屬性枷颊。
6.2 創(chuàng)建對象
使用一個同一個接口創(chuàng)建很多對象,會產(chǎn)生大量的重復代碼该面。
6.2.1 工廠模式
<pre>
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 person1 = createPerson("zhang",22,"software engineer");
</pre>
工廠模式雖然解決了創(chuàng)建多個對象的問題夭苗,但是沒有解決對象識別的問題(即怎樣知道一個對象的類型)。
6.2.2 構(gòu)造函數(shù)模式
<pre>
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
}
}
var person1 = new Person("zhang",22,"doctor");
</pre>
創(chuàng)建Person的新實例隔缀,必須使用new操作符题造。以這種方式調(diào)用構(gòu)造函數(shù)實際上回經(jīng)歷四個步驟:
- 創(chuàng)建一個新對象;
- 將構(gòu)造函數(shù)的作用域賦給新對象(因此this指向了這個新對象)猾瘸;
- 執(zhí)行構(gòu)造函數(shù)中的代碼
- 返回新對象
構(gòu)造函數(shù)模式和工廠模式差別:
- 沒有顯示創(chuàng)建對象
- 直接將屬性和方法賦給了this對象
- 沒有return語句
構(gòu)造函數(shù)的主要問題界赔,就是每個方法都要在每個實例上重新創(chuàng)建一次。ECMAScript中的函數(shù)是對象牵触,因此每定義一個函數(shù)淮悼,也就是實例化一個對象,不同實例上的同名函數(shù)是不相等的揽思。
<pre>
function Person(){
this.sayName = new Function("alert(this.name)"j);//與聲明函數(shù)在邏輯上是等價的
}
alert(person1.sayName == person2.sayName);//false
</pre>
6.2.3 原型模式
每個函數(shù)都有一個prototype屬性敛惊,這個屬性是一個指針,指向一個對象绰更,這個對象的用途是包含由特定類型的所有實例共享的屬性和方法。
<pre>
function Person(){
}
Person.prototype.name = "zhang";
Person.prototype.age = 22;
Person.prototype.job = "doctor";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.name = "jian";
person1.sayName();//jian
var person2 = new Person();
person2.sayName();//zhang
</pre>
hasOwnProperty()方法可以檢測一個屬性是存在與實例中還是存在與原型中锡宋。這個方法(不要忘記他是從Object繼承來的)只在給定屬性存在于對象實例中時儡湾,才會返回true。
<pre>
function Person(){
}
Person.prototype.name = "zhang";
Person.prototype.age = 22;
Person.prototype.job = "doctor";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.name = "jian";
person1.sayName();
var person2 = new Person();
person2.sayName();
function Person(){
}
Person.prototype.name = "zhang";
Person.prototype.age = 22;
Person.prototype.job = "doctor";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.name = "jian";
person1.sayName();
var person2 = new Person();
person2.sayName();
</pre>
通過使用 hasOwnProperty() 方法执俩,什么時候訪問的是實例屬性徐钠,什么時候訪問的是原型屬性就一清二楚了。調(diào)用 person1.hasOwnProperty( "name") 時役首,只有當 person1 重寫 name 屬性后才會返回 true 尝丐,因為只有這時候 name 才是一個實例屬性,而非原型屬性衡奥。圖 6-2 展示了上面例子在不同情況下的實現(xiàn)與原型的關系(為了簡單起見爹袁,圖中省略了與 Person 構(gòu)造函數(shù)的關系)。
for-in方法
<pre>
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true
person1.name = "Greg";
alert(person1.name); //"Greg" ——來自實例
alert(person1.hasOwnProperty("name")); //true
alert("name" in person1); //true
alert(person2.name); //"Nicholas" ——來自原型
alert(person2.hasOwnProperty("name")); //false
alert("name" in person2); //true
delete person1.name;
alert(person1.name); //"Nicholas" ——來自原型
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true
</pre>
調(diào)用 "name" in person1 始終都返回 true 矮固,無論該屬性存在于實例中還是存在于原型中失息。同時使用 hasOwnProperty() 方法和 in 操作符,就可以確定該屬性到底是存在于對象中,還是存在于原型中盹兢,如下所示邻梆。
<pre>
function hasPrototypeProperty(object, name){
return !object.hasOwnProperty(name) && (name in object);
}
</pre>
更簡單的原型語法
<pre>
function Person(){
}
Person.prototype = {
name:"zhang",
sayName:function(){
alert(this.name);
}
}
</pre>
在上面的代碼中,我們將 Person.prototype 設置為等于一個以對象字面量形式創(chuàng)建的新對象绎秒。最終結(jié)果相同浦妄,但有一個例外: constructor 屬性不再指向 Person 了。前面曾經(jīng)介紹過见芹,每創(chuàng)建一個函數(shù)剂娄,就會同時創(chuàng)建它的 prototype 對象,這個對象也會自動獲得 constructor 屬性辆童。而我們在這里使用的語法宜咒,本質(zhì)上完全重寫了默認的 prototype 對象,因此constructor 屬性也就變成了新對象的 constructor 屬性(指向 Object 構(gòu)造函數(shù))把鉴,不再指向 Person 函數(shù)故黑。此時,盡管 instanceof操作符還能返回正確的結(jié)果庭砍,但通過 constructor 已經(jīng)無法確定對象的類型了场晶,如下所示。
<pre>
var friend = new Person();
alert(friend instanceof Object); //true
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //false
alert(friend.constructor == Object); //true
</pre>
如果constructor很重要怠缸,可以如下代碼設置:
<pre>
function Person(){
}
Person.prototype = {
constructor : Person,
name : "Nicholas",
age : 29,
job: "Software Engineer",
sayName : function () {
alert(this.name);
}
};
</pre>