1、什麼是對象?html
面 向對象(Object-Oriented,OO)的語言有一個標誌,那就是都有類的概念,例如C++、Java等;可是ECMAScript沒有類的概 念。ECMAScript-262把對象定義爲:無序屬性的集合,其屬性能夠包含基本值、對象或者函數。通俗一點的理解就是,ECMAScript中的對 象就是一組數據和功能的集合,經過new操做符後跟要建立的對象類型的名稱來建立。每一個對象都基於一個引用類型建立。引用能夠是原生類型(相關介紹:引用類型),或者開發人員自定義的類型。web
2、Object對象app
跟其餘OO語言同樣,Object對象類型是全部它的實例的基礎。Object對象類型所具備的任何屬性和方法一樣也存在於更具體的對象中。函數
//建立object對象 var o = new Object(); //若沒有參數傳遞,能夠省略圓括號,但不推薦使用 var o = new Object;
Object的每一個實例都具備共同的基本屬性和方法this
屬性或者方法 | 說明 |
constructor | 指向建立當前對象的構造函數 |
hasOwnProperty(name) | 檢測給定屬性name在實例對象(不是原型對象)中是否存在。name以字符串形式指定 |
isPropertyOf(object) | 檢測傳入的對象object是否該方法調用者的原型對象。通常格式:Class.prototype.isPropertyOf(object) |
propertyIsEnumerable(pr) | 檢測屬性pr可否用for-in循環枚舉。屬性pro用字符串形式指定 |
toLocaleString() | 返回對象的字符串表示。與地區和環境對應 |
toString() | 返回對象的字符串表示 |
valueOf() | 返回對象的字符串、數值或布爾值表示 |
3、對象的屬性類型spa
在ECMAScript 5中,定義了用於描述屬性的各類特徵的內部特性,爲實現JavaScript引擎服務,因此這些特性在JavaScript中不能直接訪問。屬性類型有兩種:數據屬性和訪問器屬性。prototype
一、數據屬性rest
數據屬性包含一個數據值的位置,在這個位置對數據進行讀取和寫入。ECMAScript定義了4個特性來描述數據屬性的行爲:code
特性 | 說明 |
[[Configurable]] | 表示可否經過delete刪除屬性從而從新定義屬性、可否修改屬性的特性、可否把屬性修改成訪問器屬性。默認值是true |
[[Enumerable]] | 表示能都經過for-in循環返回屬性。默認值是true |
[[Writable]] | 表示可否修改屬性。默認值是true |
[[Value]] | 表述屬性的數據值。默認值是undefined |
二、訪問器屬性htm
訪問器屬性不包含數據值,不能直接定義。讀取訪問器屬性時,調用getter函數,該函數負責返回有效值;寫入訪問器屬性時,調用setter函數並傳入新值。訪問器也有4個屬性:
特性 | 說明 |
[[Configurable]] | 表示可否經過delete刪除屬性從而從新定義屬性、可否修改屬性的特性、可否把屬性修改成訪問器屬性。默認值是true |
[[Enumerable]] | 表示能都經過for-in循環返回屬性。默認值是true |
[[Get]] | 讀取屬性時調用的函數,默認是undefined |
[[Set]] | 寫入屬性時調用的函數,默認是undefined |
怎麼獲取對象屬性的默認特性呢?
var person = { name:"dwqs", age:20, interesting:"coding", blog:"www.ido321.com" }; var desc = Object.getOwnPropertyDescriptor(person,"age"); alert(desc.value); //20 alert(desc.configurable); //true alert(desc.enumerable); //true alert(desc.writable); //true
使用ECMAScript 5的Object.getOwnPropertyDescriptor(object,prop)獲取給定屬性的描述符:object 是屬性所在的對象,prop是給定屬性的字符串形式,返回一個對象。若prop是訪問器屬性,返回的對象包含configurable、 enumerable、set、get;若prop是數據屬性,返回的對象包含configurable、enumerable、writable、 value。
屬性的特性都不能直接定義,ECMAScript提供了Object.defineProperty(obj,prop,desc):obj是屬性所在的對象,prop是給定屬性的字符串形式,desc包含特性集合的對象。
var person = {
name:「dwqs」,
age:20,
interesting:「coding」,
blog:「www.ido321.com」
};
//定義sex屬性,writable是false,因此不能修改
Object.defineProperty(person,「sex」,{
writable:false,
value:「male」
});
alert(person.sex); //male
//在嚴格模式下出錯,非嚴格模式賦值被忽略
person.sex=「female」; //writable是false,因此不能修改
alert(person.sex); //male
能夠屢次調用Object.defineProperty()修改特性,可是,若將 configurable定義爲false,則不能再調用Object.defineProperty()方法將其修改成true。此外,調用 Object.defineProperty()時若不指定特性的值,則configurable、enumerable和writable的默認值是 false。
var person = { name:"dwqs", age:20, interesting:"coding", blog:"www.ido321.com" }; Object.defineProperty(person,"sex",{ configurable:false, value:"male" }); alert(person.sex); //male delete person.sex; //configurable是false,嚴格模式下出錯,非嚴格模式下忽略此操做 alert(person.sex); //male //拋出Cannot redefine property: sex錯誤 Object.defineProperty(person,"sex",{ configurable:true, value:"male" }); alert(person.sex); //不能彈框 delete person.sex; alert(person.sex);//不能彈框
也能夠用Object.defineProperties(obj,props)同時定義多個屬性:obj是屬性所在的對象,props是一個包含多個屬性定義的對象
var book={};
Object.defineProperties(book,{
_year:{
value:2014
},
edition:{
value:1
},
year:{
get:function()
{
return this._year;
},
set:function(newValue)
{
if(newValue > 2014)
{
this._year = newValue;
this.edition += newValue – 2014
}
}
}
});
var descs = Object.getOwnPropertyDescriptor(book,「_year」);
alert(descs.value); //2014
//調用Object.defineProperty()時若不指定特性的值,則configurable、enumerable和writable的默認值是false。
alert(descs.configurable); //false
alert(typeof descs.get); //undefined
get和set能夠不指定,也能夠值指定兩者之一。只有get表示屬性是隻讀的,只有set表示屬性只能寫入不能讀取。
var person = { name:"dwqs", age:20, interesting:"coding", blog:"www.ido321.com" }; Object.defineProperty(person,"sex",{ configurable:false, value:"male" }); alert(Object.keys(person)); //name,age,interesting,blog alert(Object.getOwnPropertyNames(person)); //name,age,interesting,blog,sex
由於sex屬性是用defineProperty()方法定義,而對於未指定的enumerable的值默認是false。因此第一次彈框沒有返回sex屬性,而第二次返回了。
4、建立對象的方式
一、工廠模式
function Person(name,age,blog) { var o = new Object(); o.name = name; o.age = age; o.blog = blog; o.interest = function() { alert("I like coding and writing blog!!!"); } return o; } var per1 = Person("dwqs",20,"www.ido321.com"); alert(per1.name); //dwqs
優勢:節省代碼量,防止冗餘。
缺點:不能識別對象,即建立的每一個實例都有相同的屬性,不能反應對象的類型。
二、構造函數模式
function Person(name,age,blog) { this.name = name; this.age = age; this.blog = blog; this.interest = function() { alert("I like coding and writing blog!!!"); } } var per1 = new Person("dwqs",20,"www.ido321.com"); alert(per1.name);
優勢:建立的每一個實例都不一樣,能夠識別不一樣對象。
缺點:建立一個實例,實例共有的方法都會從新建立。對應的解決方案能夠把方法定義到全局上去,或者定義在原型對象上。
function Person(name,age,blog) { this.name = name; this.age = age; this.blog = blog; this.interest = my; } function my() { alert("I like coding and writing blog!!!"); }
這樣,Person的全部實例均共享了my()方法。
三、原型模式
function Person() { } Person.prototype.name = "dwqs"; Person.prototype.age = 20; Person.prototype.blog = "www.ido321.com"; Person.prototype.interest = function() { alert("I like coding and writing blog!!!"); } var per1 = new Person(); alert(per1.name); //dwqs var per2 = new Person(); alert(per1.interest == per2.interest); //true
per1和per2共享了全部原型上定義的屬性和方法,顯然,不能保持每一個實例的獨立性了,不是咱們想要的。具體關於原型,後續筆記在解釋。
四、原型模式+構造函數模式(推薦使用)
function Person(name,age,blog) { this.name = name; this.age = age; this.blog = blog; } Person.prototype.interest = function() { alert("I like coding and writing blog!!!"); } var per1 = new Person("dwqs",20,"www.ido321.com"); alert(per1.name); //dwqs var per2 = new Person("i94web",22,"www.i94web.com"); alert(per2.blog); //www.i94web.com
構造函數定義每一個實例的不一樣屬性,原型共享共同的方法和屬性,最大限度的節省內存。
五、動態原型模式
function Person(name,age,blog) { this.name = name; this.age = age; this.blog = blog; if(typeof this.interest != "function") { Person.prototype.interest = function() { alert("I like coding and writing blog!!!"); }; } } var per1 = new Person("dwqs",20,"www.ido321.com"); per1.interest(); //I like coding and writing blog!!!
將全部信息均封裝在構造函數中,在須要的時候,初始化原型。
六、寄生構造函數模式
function Person(name,age,blog) { var o = new Object(); o.name = name; o.age = age; o.blog = blog; o.interest = function() { alert("I like coding and writing blog!!!"); } return o; } var per1 = Person("dwqs",20,"www.ido321.com"); alert(per1.name); //dwqs
形式跟工廠模式同樣,但這個能夠在特殊狀況下用來爲對象建立構造函數,而且使用new操做符建立對象,而工廠模式沒有使用new,直接使用返回的對象。例如,在不能修改原生對象Array時,爲其添加一個新方法
function SpecialArray() { var values = new Array(); values.push.apply(values,arguments); values.toPipedString = function() { return this.join("|"); }; return values; } var colors = new SpecialArray("red","blue","yellow"); alert(colors.toPipedString()); //red|blue|yellow
須要說明的是,寄生構造函數模式返回的對象與構造函數或者構造函數的原型對象沒有關係,因此不能用instanceof操做符來肯定對象類型。
七、穩妥構造函數模式
function Person(name,age,blog) { var o = new Object(); o.sayName = function() { alert(name); } return o; } var per1 = Person("dwqs"); per1.sayName(); //dwqs
以這種方式建立的對象,除了sayName()方法以外,沒有其餘辦法訪問name的值。per1稱爲穩妥對象。穩妥對象指沒有公共屬性,其方法也不引用this的對象。
穩妥構造函數模式與寄生構造函數有兩點區別:新建對象的實例方法不引用this;不使用new操做符調用構造函數。