JavaScript中創(chuàng)建對象的模式匯總
JavaScript中創(chuàng)建對象的模式匯總
**JavaScript創(chuàng)建對象模式:
對象字面量
工廠模式
構(gòu)造函數(shù)模式
原型模式
結(jié)合構(gòu)造函數(shù)和原型模式
原型動態(tài)模式
**
面向?qū)ο蟮恼Z言大都有一個類的概念,通過類可以創(chuàng)建多個具有相同方法和屬性的對象。雖然從技術(shù)上講,javascript是一門面向?qū)ο蟮恼Z言,但是javascript沒有類的概念,一切都是對象。任意一個對象都是某種引用類型的實(shí)例,都是通過已有的引用類型創(chuàng)建;引用類型可以是原生的,也可以是自定義的。
1、對象字面量
var person = { name : 'Nicholas'; age : '22'; job :"software Engineer" sayName: function() { alter(this.name); } }
例子中創(chuàng)建一個名為person的對象,并為它添加了三個屬性(name,age,job)和一個方法(sayName()),其中,sayName()方法用于顯示this.name(被解析為person.name)的值。
對象字面量可以用來創(chuàng)建單個對象,但這個方法有個明顯的缺點(diǎn):使用同一個接口創(chuàng)建很多對象,會產(chǎn)生大量重復(fù)的代碼。
2、工廠模式
工廠模式是軟件工程領(lǐng)域中一種廣為人知的設(shè)計(jì)模式,工廠模式抽象了創(chuàng)建具體對象的過程,用函數(shù)來封裝以特定的接口創(chuàng)建對象的細(xì)節(jié)。
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=creatPerson("Nicholas",22,"software Engineer"); var person2=creatPerson("Greg",24,"student");
函數(shù)creatPerson{}能夠根據(jù)接受的參數(shù)構(gòu)建一個包含所有必要信息的Person對象??梢詿o數(shù)次的調(diào)用這個函數(shù),每次都會返回一個包含三個屬性一個方法的對象。
工廠模型雖然解決了創(chuàng)建多個相似對象的問題,卻沒有解決對象識別的問題(即怎么知道一個對象的類型)。
3、構(gòu)造函數(shù)模式
function Person(name,age,job) { this.name = name; this.age = age; this.job = job; this.sayName = function() { alert(this.name); } } //通過new操作符創(chuàng)建Person的實(shí)例 var person1 = new Person("Nicholas",22,"software Engineer"); var person2 = new Person("Greg",24,"student"); person1.sayName(); //Nicholas person2.sayName(); //Greg
與工廠模式不同的是
沒有顯示的創(chuàng)建對象
直接將屬性和方法賦給了this對象
沒有return語句
創(chuàng)建Person的新實(shí)例,必須使用new操作符。調(diào)用構(gòu)造函數(shù)的4個步驟:
創(chuàng)建一個新對象
將構(gòu)造函數(shù)的作用域賦給新對象(this指向了這個新對象)
執(zhí)行構(gòu)造函數(shù)中的代碼
返回新對象
這個例子中創(chuàng)建的所有對象既是Object的實(shí)例,也是Person實(shí)例。可以通過instanceof操作符驗(yàn)證。
alert(person1 instanceof Object);//true
構(gòu)造函數(shù)模式也有自己的問題,實(shí)際上,sayName方法在每個實(shí)例上都會被重新創(chuàng)建一次,需要注意的是,通過實(shí)例化創(chuàng)建的方法并不相等,以下代碼可以證明
alert(person1.sayName == person2.sayName);//false
可以將方法移到構(gòu)造器的外部作為全局函數(shù)來解決這個問題。
function Person(name,age,job) { this.name = name; this.age = age; this.job = job; } function sayName() { alert(this.name); }
在全局下創(chuàng)建的全局函數(shù)實(shí)際上只能被經(jīng)由Person創(chuàng)建的實(shí)例調(diào)用,這就有點(diǎn)名不副實(shí)了;如果對象需要定義很對方法,那么就要定義很多個全局函數(shù),缺少封裝性。
4、原型模式
JavaScript中創(chuàng)建的每個函數(shù)都有一個prototype(原型)屬性,它是一個指針,指向一個對象,包含了可以由特定類型的所有實(shí)例共享的屬性和方法(讓所有的對象實(shí)例共享它的屬性和方法)
function Person() {} Person.prototype.name ="Nicholas"; Person.prototype.age = 22; Person.prototype.job = "software Engineer"; Person.prototype.sayName(){ alert(this.name); }; var person1 = new Person(); person1.sayName(); //Nicholas alert(person1.sayName == person2.sayName);//true
以上代碼做了這幾件事情:
定義了一個構(gòu)造函數(shù)Person,Person函數(shù)自動獲得一個prototype屬性,該屬性默認(rèn)只包含一個指向Person的constructor屬性
通過Person.prototype添加三個屬性,和一個方法
創(chuàng)建一個Person的實(shí)例,隨后在實(shí)例上調(diào)用了sayName()方法
使用Person構(gòu)造函數(shù)和Person.prototype創(chuàng)建實(shí)例的代碼為例,展示個對象之間的關(guān)系
使用Person構(gòu)造函數(shù)和Person.prototype創(chuàng)建實(shí)例的代碼為例,展示個對象之間的關(guān)系
圖中展示了Person構(gòu)造函數(shù)、Person的原型屬性以及Person的兩個實(shí)例,之間的關(guān)系。Person.prototype指向了原型對象,Person.prototype.constructor有指回了Person。原型對象中除了包含constructor屬性,還包含后來添加的其他屬性和方法,Person的兩個實(shí)例person1和person2都包含一個內(nèi)部屬性,該屬性僅指向Person.prototype。
sayName()方法的調(diào)用過程:
在person1實(shí)例上查找logName()方法,發(fā)現(xiàn)沒有這個方法,于是追溯到person1的原型
在person1的原型上查找sayame()方法,有這個方法,于是調(diào)用該方法
基于這樣一個查找過程,我們可以通過在實(shí)例上定義原型中的同名屬性,來阻止該實(shí)例訪問原型上的同名屬性,需要注意的是,這樣做并不會刪除原型上的同名屬性,僅僅是阻止實(shí)例訪問。
function Person() {} Person.prototype.name ="Nicholas"; Person.prototype.age = 22; Person.prototype.job = "software Engineer"; Person.prototype.sayName(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name="Greg" alert(person1.name) //Greg 來自實(shí)例 alert(person2.name) //Nicholas 來自原型
使用delete操作符可以完全刪除實(shí)例屬性
delete person1.name; alert(person1.name) //Nicholas 來自原型
使用hasOwnProperty()方法可以檢測一個屬性是存在于實(shí)例還是原型中
function Person() {} Person.prototype.name ="Nicholas"; Person.prototype.age = 22; Person.prototype.job = "software Engineer"; Person.prototype.sayName(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); alert(person1,hasOwnProperty("name"));//false person1.name="Greg" alert(person1.name) //Greg 來自實(shí)例 alert(person1,hasOwnProperty("name"));//true alert(person2.name) //Nicholas 來自原型 alert(person2,hasOwnProperty("name"));//false delete person1.name; alert(person1.name) //Nicholas 來自原型 alert(person1,hasOwnProperty("name"));//false
下圖展示了在不同情況下實(shí)例與原型之間的關(guān)系
簡單的原型語法
function Person() {} Person.prototype={ name :"Nicholas", age : 22, job : "software Engineer", sayName:function(){ alert(this.name); } };
在上面的代碼中constructor屬性不再指向Person了,通過constructor無法確定對象的類型了??梢韵裣旅孢@樣特意將他設(shè)置回適當(dāng)?shù)闹?/p>
function Person() {} Person.prototype={ constructor:Person, name :"Nicholas", age : 22, job : "software Engineer", sayName:function(){ alert(this.name); } };
重設(shè)constructor屬性會導(dǎo)致它的[[Enumerable]]特性被設(shè)置為true,默認(rèn)情況,原生的constructor屬性是不可枚舉的,可以使用Object.defineProperty()方法來改變
Object.defineProperty(Person.prototype,"constructor",{ enumerable:false, value:Person });
原型中查找值的過程是一次搜索,原型對象所做的任何修改都能從實(shí)例上立即反應(yīng)出來
var friend=new Person(); Person.prototype.sayHi=function(){ alert("hi); } friend,sayHi();//"hi"(沒有問題)
person實(shí)例是在添加新方法之前創(chuàng)建的,但仍可以訪問新添加的方法,原因是實(shí)例與原型之間的松散連接關(guān)系
重寫原型對象后的情況
function Person() {} var friend=new Person(); Person.prototype={ name :"Nicholas", age : 22, job : "software Engineer", sayName:function(){ alert(this.name); } }; friend.sayName();//error
調(diào)用friend.sayName()時發(fā)生錯誤的原因是,friend指向的原型中不包含以該字段命名的屬性,如下圖。
原型對象的問題
原型對象省略了為構(gòu)造函數(shù)傳遞初始化參數(shù)這一環(huán)節(jié),所有勢力在默認(rèn)情況下都取得相同的屬性值。原型模型最大的問題是有其共享本性所導(dǎo)致的。當(dāng)原型模型包含引用類型的屬性來說,問題就比較嚴(yán)重了。來看下面的例子。
function Person() {} Person.prototype={ constructor:Person, name :"Nicholas", age : 22, job : "software Engineer", friends:["Shelby","Court"], sayName:function(){ alert(this.name); } }; var person1=new Person(); var person2=new Person(); person1.friend.push("Van"); alert(person1.friends);//"Shelby,Court,Van" alert(person2.friends);//"Shelby,Court,Van" alert(person1.friends==person2.friends);//true
5、組合使用構(gòu)造函數(shù)模式和原型模式
組合使用構(gòu)造函數(shù)模式和原型模式中,構(gòu)造函數(shù)用于定義實(shí)例屬性,原型模型用于定義方法和共享的屬性。這樣每個實(shí)例都會有自己的一份實(shí)例屬性的副本,同時也可以共享對方法的引用,最大限度的節(jié)省了內(nèi)存。
function Person(name,age,job) { this.name = name; this.age = age; this.job = job; this.friends=["Shelby","Court"]; } Person.prototype={ constructor:Person, sayName:function(){ alert(this.name); } } var person1=new Person("Nicholas",22,"software Engineer"); var person2 = new Person("Greg",24,"student"); person1.friend.push("Van"); alert(person1.friends);//"Shelby,Court,Van" alert(person2.friends);//"Shelby,Court" alert(person1.friends==person2.friends);//false alert(person1.sayName==person2.sayName);//true
6、動態(tài)原型模式
原型動態(tài)模式將需要的所有信息都封裝到構(gòu)造函數(shù)中,通過if語句判斷原型中的某個屬性是否存在,若不存在(在第一次調(diào)用這個構(gòu)造函數(shù)的時候),執(zhí)行if語句內(nèi)部的原型初始化代碼。
function Person(name,age) { this.name = name; this.age = age; this.job =job; //方法 if(typeof this.sayName != 'function') { Person.prototype.sayName = function() { alert(this.name); }; } } var friend = new Person('Nicholas','22','Software Engineer');//初次調(diào)用構(gòu)造函數(shù),此時修改了原型 var person2 = new Person('amy','21');//此時sayName()方法已經(jīng)存在,不會再修改原型
推薦閱讀:
js面向?qū)ο笾R妱?chuàng)建對象的幾種方式(工廠模式、構(gòu)造函數(shù)模式、原型模式)
以上所述是小編給大家介紹的JavaScript中創(chuàng)建對象的模式,希望對大家有所幫助!
- JavaScript對象創(chuàng)建模式實(shí)例匯總
- 深入理解JavaScript系列(48):對象創(chuàng)建模式(下篇)
- 深入理解JavaScript系列(47):對象創(chuàng)建模式(上篇)
- JS中創(chuàng)建自定義類型的常用模式總結(jié)【工廠模式,構(gòu)造函數(shù)模式,原型模式,動態(tài)原型模式等】
- javascript工廠模式和構(gòu)造函數(shù)模式創(chuàng)建對象方法解析
- 淺談js對象的創(chuàng)建和對6種繼承模式的理解和遐想
- js面向?qū)ο笾R妱?chuàng)建對象的幾種方式(工廠模式、構(gòu)造函數(shù)模式、原型模式)
- 詳解 javascript對象創(chuàng)建模式
相關(guān)文章
javascript獲取四位數(shù)字或者字母的隨機(jī)數(shù)
這篇文章主要介紹了javascript獲取四位數(shù)字或者字母的隨機(jī)數(shù),需要的朋友可以參考下2015-01-01控制頁面按鈕在后臺執(zhí)行期間不重復(fù)提交的JS方法
下面的代碼可以避免這種情況的發(fā)生,要等第一次執(zhí)行完返回?cái)?shù)據(jù)到前臺后才能提交第二次。2013-06-06Redux實(shí)現(xiàn)組合計(jì)數(shù)器的示例代碼
本篇文章主要介紹了Redux實(shí)現(xiàn)組合計(jì)數(shù)器的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07