1. 對象字面量方式
對象字面量方式是建立自定義對象的首選模式,簡單方便。php
var per = { name:'zhangsan', age:25, job:'html', sayName:function(){ alert(this.name); } }
**缺點:**使用同一個接口建立不少對象,會產生大量的重複代碼。好比我想再建立一個per1對象,我就得把上面的代碼再從新寫一遍,改變不一樣的屬性值。html
**二、工廠模式**
工廠模式抽象了建立具體對象的過程。因爲在ECMAScript中沒法建立類,開發人員就發明了一種函數,用函數來封裝以特定接口建立對象的細節,以下面的例子:前端
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',30,'java'); var person2 = createPerson('zhao',25,'php'); //前端全棧學習交流圈:866109386 //面向1-3經驗年前端開發人員 //幫助突破技術瓶頸,提高思惟能力
函數createPerson()可以根據接受到的參數來構建一個包含全部必要信息的Person對象。能夠無數次的調用這個函數,而每次它都會返回一個包含三個屬性和一個方法的對象。html5
缺點:工廠模式雖然解決了建立多個類似對象的問題,但卻沒有解決對象識別的問題(即怎樣知道一個對象的類型)。java
**三、構造函數模式**
可使用構造函數模式將前面的例子重寫以下:數組
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',30,'java'); var person2 = new Person('zhao',25,'php'); //前端全棧學習交流圈:866109386 //面向1-3經驗年前端開發人員 //幫助突破技術瓶頸,提高思惟能力
建立自定義的構造函數意味着未來能夠將它的實例標識爲一種特定的類型。而這正是構造函數模式賽過工廠模式的地方。函數
然而,使用構造函數的主要問題,就是每一個方法都要在每一個實例上從新建立一遍。在上面的例子中,person1和person2都有一個名爲sayName()的方法,但那兩個方法不是同一個Function的實例,建立兩個完成一樣任務的Function實例的確沒有必要;何況有this對象在,根本不用在執行代碼前就把函數綁定到特定對象上面。所以能夠像下面這樣,經過把函數定義轉移到構造函數外部來解決這個問題。學習
function Person(name,age,job){ this.name= name; this.age = age; this.job = job; this.sayName = sayName(); } function sayName(){ alert(this.name); } var person1 = createPerson('zhang',30,'java'); var person2 = createPerson('zhao',25,'php');
在這個例子中,咱們把sayName()函數的定義轉移到構造函數外部。而在構造函數內部,咱們將sayName屬性設置成等於全局的sayName函數,這樣person1和person2對象就共享了在全局做用域中定義的同一個sayName()函數。這樣確實解決了兩個函數在作同一件事的問題,但是新問題又來了:在全局做用域中定義的函數實際上只能被某個對象調用,這讓全局做用域有點名存實亡。更讓人沒法接受的是:若是對象須要定義不少方法,那麼就要定義不少全局函數。好在,這些問題能夠經過使用原型模式來解決。this
**四、原型模式**
咱們建立的每一個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含能夠由特定類型的全部實例共享的屬性和方法。使用原型對象的好處是可讓全部的對象實例共享他所包含的屬性和方法。prototype
function Person(){} Person.prototype.name = 'zhang'; Person.prototype.age = '22'; Person.prototype.job = 'html5'; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person();
原型模式也不是沒有缺點。首先,它省略了爲構造函數傳遞初始化參數這一環節,結果全部實例在默認狀況下都將取得相同的屬性值。雖然這會在某種程度上帶來一些不方便,但還不是原型的最大問題。原型模式的最大問題是由共享的本性所致使的。
原型中全部屬性是被不少實例共享的,這種共享對於函數很是合適。對於那些包含基本值的屬性倒也說的過去,經過在實例上添加一個同名屬性,能夠隱藏原型中的對應屬性。而後,對於包含引用類型的屬性來講,問題就比較突出了。
function Person(){} Person.prototype = { constructor:Person, name:'zhang', age :'22', job :'html5', friends:\['wang','li'\], sayName : function(){ alert(this.name); } }; var person1 = new Person(); var person2 = new Person(); person1.friends.push('zhao'); alert(person1.friends); //'wang,li,zhao' alert(person2.friends); //'wang,li,zhao' alert(person1.friends === person2.friends); //true
從上面的打印的結果咱們就能夠知道爲何不多人單獨使用原型模式了,實例通常都是要有屬於本身的所有屬性的。
**五、組合使用構造函數模式和原型模式**
組合使用構造函數模式和原型模式,是建立自定義類型的最多見方式。構造函數模式用於定義實例屬性,而原型模式用於定義方法和共享的屬性。結果,每一個實例都會有本身的一份實例屬性的副本,但同時又共享着對方法的引用,最大限度的節省了內存。
function Person(name,age,job){ this.name= name; this.age = age; this.job = job; this.friends = \['wang','li'\]; } Person.prototype = { constructor:Person, sayName : function(){ alert(this.name); } } var person1 = new Person('zhang',26,'java',); var person2 = new Person('sun',25,'php'); person1.friends.push('zhao'); alert(person1.friends); //'wang,li,zhao' alert(person2.friends); //'wang,li' alert(person1.friends === person2.friends); //false
在上面的例子中,實例屬性都是在構造函數中定義的,而由全部實例共享的屬性constructor和方法satName()則是在原型中定義的。而修改了person1.friends(向其中添加一個新字符串),並不會影響到person2.friends,由於他們分別引用了不一樣的數組。