關於javascript中對象的理解
其實,javascript中的對象就類似於java中所說的對象,區別就在於,javascript對象中的屬性有類型的區分:
1、數據屬性
數據屬性包含一個數據值的位置,在這個位置可以讀取和寫入值。
屬性的特性:
[[Configurable]]:表示能否通過delete 刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改爲訪問器屬性--默認爲true;
[[Writable]]:表示能否修改屬性的值--默認爲true;
[[Value]]:包含這個屬性的數據值--默認爲undefined;
[[Enumerable]]:表示能否通過for-in循環返回屬性--默認爲true。
e.g.
//創建了一個名爲name的屬性,爲它指定的值,也就是[[Value]]特性將被設置爲"Jack"
var person = {
name:"Jack"
};
修改方法
//接受三個參數,屬性所在的對象,屬性的名字和一個描述符對象,描述符必須是:configurable、enumerable、writable和value中的一個或多個
//注意:一旦將configurable設置爲false,就不能再把它變回可配置的了。在調用該方法是,如果不指定,configurable、enumerable、writable默認爲false
Object.defineProperty(person,"name",{
writable:false,
value:"James"
});
alert(person.name);//"James"
person.name="George";
alert(person.name);//"James"
2、訪問器屬性
[[Enumerable]]:表示能否通過for-in循環返回屬性--默認爲true
[[Get]]:在讀取屬性時調用的函數--默認爲undefined
[[Set]]:在寫入屬性時調用的函數--默認爲undefined
e.g.
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;
}
}
});
針對這些屬性的特性,javascript還有相應的讀取屬性特性的方法:Object.getOwnPropertyDescriptor()方法。e.g.
var descriptor = Object.getOwnPropertyDescriptor(book,"_year");//讀取屬性特性
創建對象
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;
}
2、構造函數模式
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
/*
* 創建對象的新實例,必須使用new操作符,經歷的具體步驟如下:
* 1、創建一個新的對象
* 2、將構造函數的作用域賦給新對象(因此this就指向了這個新對象)
* 3、執行構造函數中的代碼(爲這個對象添加屬性)
* 4、返回新對象--不需要return語句
*/
var person2 = new Person("Jerry",22,"Engineer");
與工廠模式的區別:- 沒有顯示地創建對象
- 直接將屬性和方法賦給了this對象
- 沒有return語句
3、原型模式
function Person(){
}
Person.prototype.name = "Jack";
Person.prptotype.age = 22;
Person.prototype.job = "Sofyware Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.name = "George";
alert(person1.name);//"George"--來自實例
alert(person2.name);//"Jack"--來自原型
注意:雖然可以通過對象實例訪問保存在原型對象中的屬性的值,但卻不能通過對象實例重寫原型對象中的屬性的值。
這裏又有一個新的概念:屏蔽。
如果我們在實例中添加了一個屬性,並且這個屬性又恰好跟實例原型中的某一屬性同名,那我們在實例中創建該屬性,該屬性就將會屏蔽原型中的同名屬性。
有關原型模式的其他方法:
hasOwnProperty():可以檢測一個屬性是否存在於實例中,還是存在於原型中--當屬性存在於對象實例中時,纔會返回true(該方法繼承自Object)
in操作符:
in操作符有兩種使用方式:
1、在for-in循環中使用;
2、單獨使用:in操作符會在 通過對象可以訪問到指定屬性值時返回true,不管這個屬性是對象實例中的還是原型中的。
function Person(){
}
Person.prototype.name = "Jack";
Person.prptotype.age = 22;
Person.prototype.job = "Sofyware Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.name = "George";
alert(person1.name);//"George"--來自實例
alert(person2.name);//"Jack"--來自原型
alert(person2.hasOwnProperty("name"));//false
alert("name" in person2);//true
delete person1.name;
alert(person2.hasOwnProperty("name"));
alert("name" in person2);//true
根據上面的東西,總結了一個小技巧。
當屬性的in操作符返回true而hasOwnProperty()返回false時,就可以確定屬性是原型中的屬性。