首先創(chuàng)建一個簡單的對象
let obj = {
name:"xiaohong",
age:15
}
其中的name和age為對象實例obj的屬性,而在ECMAScript中包括兩種屬性,數據屬性和訪問器屬性。
數據屬性: 包含一個數據值的位置,在這個位置上可以對數據進行讀,寫,刪除操作,“xiaohong”和 15 就屬于數據屬性,有4個用來描述其行為的特性:
[[Configurable]]:表示是否能通過delete刪除對象中的屬性從而定義新的屬性, 能否修改屬性的特性,能否把屬性修改為訪問器屬性,其默認值為true。
[[Enumerable]] :表示能否通過 for-in循環(huán)返回屬性,其默認值為true
[[Writable]]:表示能否修改屬性的值,其默認值為true
[[Value]]: 包含這個屬性的數據值,其默認值為undefined,讀取屬性值或者修改屬性值都是在該位置進行操作
如果按照上述操作直接創(chuàng)建對象以及添加屬性時,上述四個操作行為都會自動設定為默認值,如果需要修改屬性的默認值行為,可以通過Object.defineProperty(obj,name,{}),該方法接收三個參數,依次為屬性所在的對象,屬性名,以及描述符對象,其中描述符對象只能為 Configurable,Enumerable,Writable,Value,可以設定其中的一個或者多個。
let obj = {
name:"xiaohong",
age:15
}
Object.defineProperty(obj,"class",{
Value:"3班",
Writable:false,
Configurable:false
})
通過Object.defineProperty方法操作后,添加的class數據值為“3班”,不可以進行修改和刪除操作。
訪問器屬性:不包含數據只,但是包含一對getter和setter函數(兩個函數都不是必須的),在讀取訪問器屬性時,會調用getter函數,在寫入訪問器屬性時,會調用setter函數,訪問器屬性有以下4個特性:
[[Configurable]]:表示是否能通過delete刪除對象中的屬性從而定義新的屬性, 能否修改屬性的特性,能否把屬性修改為訪問器屬性,其默認值為true。
[[Enumerable]]:表示能否通過 for-in循環(huán)返回屬性,其默認值為true
[[Get]]:在讀取屬性時調用的函數,默認值為undefined
[[Set]]:在寫入屬性時調用的函數,默認值為undefined
let obj = {
name:"小紅",
age:15
}
Object.defineProperty(obj,"change",{
get:function(){
console.log(this.name+","+this.age);
},
set:function(value){
this.age = value;
}
})
obj.change; //小紅,15
obj.change = 20;
obj.change; //小紅,20
如果想通過方法定義多個屬性以及定義他們的數據屬性和訪問器屬性,可以通過Object.defineProperties(obj,{})
let obj = {};
Object.defineProperties(obj,{
name:{
Value:"小紅",
Writable:true
},
age:{
Value:15,
Writable:true
},
class:{
set:function(value){
this.name = value;
},
get:function(){
console.log(this.name+","+this.age);
}
}
})
obj.class; //小紅,15
obj.change = 20;
obj.change; //小紅,20
優(yōu)化創(chuàng)建對象過程的幾種模式
在創(chuàng)建單一對象以及添加屬性時,可以直接使用基本的創(chuàng)建方法以及可以通過點運算符添加屬性或者Object.defineProperty()方法修改對象屬性的默認行為,但是如果需要使用相同的接口以及屬性來創(chuàng)建多個對象時,如果使用原始的方法來創(chuàng)建屬性相同的對象的時候,便會產生代碼耦合以及大量重復代碼,通過以下幾種模式來創(chuàng)建對象以及進行相關的操作,可以優(yōu)化此類問題。
工廠模式
function obj(name,age){
let o = new Object();
o.name = name;
o.age = age;
return o;
}
let first = obj("小紅",15);
first.name; //小紅
此模式通過一個公共函數接口,并在函數內部創(chuàng)建對象,并為對象添加屬性,最后返回該對象,省略了通過new運算符來創(chuàng)建對象的過程,缺點是雖然可以創(chuàng)建一個統(tǒng)一的公共接口,但是工廠模式解決不了對象識別的問題(即無法識別對象的類型)
構造函數模式
function Obj(name,age){
this.name = name;
this.age = age;
this.con = con;
}
function con(){
console.log(this.name+","+this.age);
}
let o = new Obj("小紅",15);
該模式與工廠模式相比,不需要在函數內部創(chuàng)建對象實例,直接將屬性和方法賦值給了this對象,沒有return語句,但是在創(chuàng)建新的對象時必須使用new運算符,否則this會指向window對象并將屬性和方法添加到window對象中。
原型模式
對于我們創(chuàng)建的每一個函數,都會有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法,也就是說所有該函數創(chuàng)建的實例對象都可以共同訪問到這個函數中的原型屬性和方法,這也是原型模式構造對象的好處,不必再將需要共享的屬性放到構造方法中而是可以直接放到這個函數的原型對象中。
function obj(){};
obj.prototype = {
name:"小紅",
age:15,
sayname:function(){
console.log(this.name+","+this.age);
}
}
let s1 = new obj();
console.log(s1.name); //小紅
let s2 = new obj();
console.log(s1.name); //小紅