javascript 中對於對象的描述:javascript
ECMA-262 把對象的定義爲:「無序屬性的集合,其屬性能夠包含基本值,對象或者函數。」嚴格來說,這就至關於說對象是一組沒有特定順序的值。對象的每一個屬性或方法都有一個名字,而每一個名字都映射到一個值。正是由於這樣,咱們能夠把 javascript 中的對象想象成散列表:無非就是一組名值對,其中值能夠是數據或函數。
java
javascript 中九種建立對象的方式:ide
一、原生 Object 構造函數函數
二、對象字面量表示法this
三、工廠模式spa
四、構造函數模式prototype
五、原型模式指針
六、組合使用構造函數模式和原型模式orm
七、動態原型模式對象
八、寄生構造函數模式
九、穩妥構造函數模式
一、原生 Object 構造函數
具體示例:
// 建立對象
var person = new Object();
// 爲對象添加屬性
person.name = "luochen";
person.age = 22;
person.job = "student";
// 爲對象添加方法
person.sayJob = function(){
alert(this.job);
};
PS:上面的例子建立了一個名爲 person 的對象,併爲它添加了三個屬性和一個方法。
二、對象字面量表示法
具體示例:
// 建立對象
var person = {
name: "luochen",
age: 22,
job: "student",
sayJob: function(){
alert(this.job);
}
};
PS:雖然 Object 構造函數或對象字面量均可以用來建立單個對象,但這些方式有個明顯的缺點:使用同一個接口建立多個對象,會產生大量的重複代碼。
三、工廠模式
具體示例:
// 自定義建立對象的函數
function createPerson(name,age,job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayJob = function(){
alert(this.job);
};
return o;
}
var person1 = createPerson("luochen",22,"student");
PS:工廠模式的原理就是自定義一個函數,用函數來封裝以特定接口建立對象的細節。這個函數能夠接收一些必要參數用來初始化對象,函數內部最後將這個新對象返出,在函數外部將這個調用這個函數的結果賦值給一個新變量。工廠模式雖然解決了建立多個類似對象的問題,但卻沒有解決對象識別的問題。
四、構造函數模式
具體示例:
// 建立自定義構造函數,從而定義自定義對象類型的屬性和方法
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayJob = function(){
alert(this.job);
};
}
var person1 = new Person("luochen",22,"student");
PS:構造函數模式和工廠模式的區別:
一、沒有顯示地建立對象
二、直接將屬性和方法賦值給了 this 對象
三、沒有 return 語句
以 new 操做符調用構造函數建立對象實際上會經歷如下4個步驟:
一、建立一個新對象
二、將構造函數的做用域賦給新對象(所以 this 就指向了這個新對象)
三、執行構造函數中的代碼(爲這個新對象添加屬性)
四、返回新對象
建立自定義的構造函數意味着未來能夠將它的實例標識爲一種特定的類型;而這正是構造函數模式賽過工廠模式的地方。構造函數有個明顯的缺點就是每一個方法都要在每一個實例上從新建立一遍,即不一樣實例上的同名函數是不相等的。
五、原型模式
具體示例:
// 不在構造函數中定義對象實例的信息,而是能夠將這些信息直接添加到原型對象中
function Person(){
}
Person.prototype.name = "luochen";
Person.prototype.age = 22;
Person.prototype.job = "student";
Person.prototype.sayJob = function(){
alert(this.job);
};
var person1 = new Person();
person1.sayJob();
PS:咱們建立的每一個函數都有一個 prototype 的原型屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含能夠由特定類型的全部實例共享的屬性和方法,即 prototype 屬性指向的那個對象是全部實例的原型對象。原型模式與構造函數模式最大的不一樣之處在於:由原型模式建立的對象共享全部的屬性和方法(即便用同一組屬性和同一個函數)。要格外記住的是:經過原型模式建立的對象實例都不包含屬性和方法,但咱們能夠調用 person1.sayJob() 這是爲啥呢???其實這是經過查找對象屬性的過程來實現的。每當代碼讀取某個對象的某個屬性或方法時,都會執行一次搜索,目標是具備給定名字的屬性。搜索首先從對象實例自己開始。若是在實例中找到了具備給定名字的屬性,則返回該屬性的值;若是沒有找到,則會繼續搜索指針(實例的內部屬性 `Prototype`)指向的原型對象,在原型對象中查找具備給定名字的屬性。若是在原型對象中找到了這個屬性,則返回該屬性的值。
// 原型模式更常見的作法是用一個包含全部屬性和方法的對象字面量來重寫整個原型對象
function Person(){
}
Person.prototype = {
// 用對象字面量來重寫整個原型對象,constructor 屬性也就變成了新對象的 constructor 屬性(指向 Object 構造函數),再也不指向 Person 函數
constructor: Person,
name: "luochen",
age: 22,
job: "student",
sayJob: function(){
alert(this.job);
}
};
var person1 = new Person();
PS:原型模式省略了給構造函數傳遞參數這一環節,結果全部的實例在默認狀況下都將取得相同的屬性值,而且當原型對象上有一個引用類型值的屬性時,在一個對象實例上對其值的修改,結果會在全部實例中反映出來。
六、組合使用構造函數模式和原型模式
具體示例:
// 構造函數模式用於定義實例屬性,而原型模式用於定義方法和共享的屬性
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["tom","jerry"];
}
Person.prototype = {
constructor: Person,
sayJob: function(){
alert(this.job);
}
};
var person1 = new Person("luochen",22,"student");
var person2 = new Person("shelby",30,"enginner");
person1.friends.push("van");
alert(person1.friends); // "tom,jerry,van"
alert(person2.friends); // "tom,jerry"
alert(person1.friends == person2.friends); // false
alert(person1.sayJob == person2.sayJob); // true
PS:經過組合使用構造函數模式和原型模式建立的對象實例都會有本身的一份實例屬性的副本,但同時又共享着對方法的引用,最大限度地節省了內存。這種模式是目前使用最普遍,認同度最高的一種建立自定義類型的方法。能夠說是用來定義引用類型的一種默認模式。
七、動態原型模式
具體示例:
// 把全部信息都封裝在構造函數中,在構造函數中經過檢查原型初始化以後應該存在的任何屬性和方法是否存在,來決定是否須要初始化原型
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
// 判斷是否初始化原型
if(typeof this.sayJob != "function"){
Person.prototype.sayJob = function(){
alert(this.job);
};
}
}
var person = new Person("luochen",22,"student");
person.sayJob();
PS:對於採用這種模式建立的對象,還可使用 instanceof 操做符肯定它的類型。使用動態原型模式時,不能使用對象字面量重寫原型,若是在已經建立了實例的狀況下重寫原型,那麼就會切斷現有實例與新原型之間的聯繫。
八、寄生構造函數模式
具體示例:
// 這種模式的基本思想是建立一個函數,該函數的做用僅僅是封裝建立對象的代碼,而後在返回新建立的對象
function Person(name,age,job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayJob = function(){
alert(this.job);
};
return o;
}
var person = new Person("luochen",22,"student");
person.sayJob();
PS:這種模式除了使用 new 操做符並把使用的包裝函數叫作構造函數以外,跟工廠模式實際上是如出一轍的。構造函數在不返回值的狀況下,默認會返回新對象實例。而經過在構造函數的末尾添加一個 return 語句,就能夠重寫調用構造函數時返回的值。這種模式的缺點是不能經過 instanceof 操做符來肯定對象的類型,由於返回的對象與構造函數或者與構造函數的原型屬性之間沒有關係。
九、穩妥構造函數模式
具體示例:// 穩妥構造函數遵循與寄生構造函數相似的模式,但有兩點不一樣:一是新建立對象的實例方法不引用 this;二是不使用 new 操做符調用構造函數function Person(name,age,job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayJob = function(){ alert(name); }; return o;}var person = Person("luochen",22,"student");person.sayJob();PS:變量 person 中保存的是一個穩妥對象(指的是沒有公共屬性,並且其方法也不引用 this 的對象),而除了調用 sayJob() 方法外,沒有別的方式能夠訪問其數據成員。與寄生構造函數模式類似,使用穩妥構造函數模式建立的對象與構造函數之間也沒有什麼關係,所以 instanceof 操做符對這種對象也沒有意義。