JavaScript中建立對象的模式匯總_javascript技巧

來源:互聯網
上載者:User

JavaScript中建立對象的模式匯總

**JavaScript建立對象模式:

對象字面量
原廠模式
建構函式模式
原型模式
結合建構函式和原型模式
原型動態模式
**

物件導向的語言大都有一個類的概念,通過類可以建立多個具有相同方法和屬性的對象。雖然從技術上講,javascript是一門物件導向的語言,但是javascript沒有類的概念,一切都是對象。任意一個對象都是某種參考型別的執行個體,都是通過已有的參考型別建立;參考型別可以是原生的,也可以是自訂的。

1、對象字面量

var person = {    name : 'Nicholas';    age : '22';    job :"software Engineer"    sayName: function() {      alter(this.name);  }}

例子中建立一個名為person的對象,並為它添加了三個屬性(name,age,job)和一個方法(sayName()),其中,sayName()方法用於顯示this.name(被解析為person.name)的值。

對象字面量可以用來建立單個對象,但這個方法有個明顯的缺點:使用同一個介面建立很多個物件,會產生大量重複的代碼。

2、原廠模式

原廠模式是軟體工程領域中一種廣為人知的設計模式,原廠模式抽象了建立具體對象的過程,用函數來封裝以特定的介面建立對象的細節。

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");

函數creatPerson{}能夠根據接受的參數構建一個包含所有必要資訊的Person對象。可以無數次的調用這個函數,每次都會返回一個包含三個屬性一個方法的對象。

工廠模型雖然解決了建立多個相似對象的問題,卻沒有解決對象識別的問題(即怎麼知道一個對象的類型)。

3、建構函式模式

function Person(name,age,job) {  this.name = name;  this.age = age;  this.job = job;  this.sayName = function() {    alert(this.name);  }}//通過new操作符建立Person的執行個體var person1 = new Person("Nicholas",22,"software Engineer");var person2 = new Person("Greg",24,"student");person1.sayName(); //Nicholasperson2.sayName(); //Greg

與原廠模式不同的是

沒有顯示的建立對象

直接將屬性和方法賦給了this對象

沒有return語句

建立Person的新執行個體,必須使用new操作符。調用建構函式的4個步驟:

建立一個新對象

將建構函式的範圍賦給新對象(this指向了這個新對象)

執行建構函式中的代碼

返回新對象

這個例子中建立的所有對象既是Object的執行個體,也是Person執行個體。可以通過instanceof操作符驗證。

alert(person1 instanceof Object);//true

建構函式模式也有自己的問題,實際上,sayName方法在每個執行個體上都會被重新建立一次,需要注意的是,通過執行個體化建立的方法並不相等,以下代碼可以證明

alert(person1.sayName == person2.sayName);//false

可以將方法移到構造器的外部作為全域函數來解決這個問題。

function Person(name,age,job) {  this.name = name;  this.age = age;  this.job = job;  }function sayName() {    alert(this.name);  }

在全域下建立的全域函數實際上只能被經由Person建立的執行個體調用,這就有點名不副實了;如果對象需要定義很對方法,那麼就要定義很多個全域函數,缺少封裝性。

4、原型模式

JavaScript中建立的每個函數都有一個prototype(原型)屬性,它是一個指標,指向一個對象,包含了可以由特定類型的所有執行個體共用的屬性和方法(讓所有的對象執行個體共用它的屬性和方法)

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(); //Nicholasalert(person1.sayName == person2.sayName);//true

以上代碼做了這幾件事情:

定義了一個建構函式Person,Person函數自動獲得一個prototype屬性,該屬性預設只包含一個指向Person的constructor屬性
通過Person.prototype添加三個屬性,和一個方法

建立一個Person的執行個體,隨後在執行個體上調用了sayName()方法

使用Person建構函式和Person.prototype建立執行個體的代碼為例,展示個對象之間的關係

使用Person建構函式和Person.prototype建立執行個體的代碼為例,展示個對象之間的關係

 

圖中展示了Person建構函式、Person的原型屬性以及Person的兩個執行個體,之間的關係。Person.prototype指向了原型對象,Person.prototype.constructor有指回了Person。原型對象中除了包含constructor屬性,還包含後來添加的其他屬性和方法,Person的兩個執行個體person1和person2都包含一個內部屬性,該屬性僅指向Person.prototype。

sayName()方法的調用過程:

在person1執行個體上尋找logName()方法,發現沒有這個方法,於是追溯到person1的原型

在person1的原型上尋找sayame()方法,有這個方法,於是調用該方法

基於這樣一個尋找過程,我們可以通過在執行個體上定義原型中的同名屬性,來阻止該執行個體訪問原型上的同名屬性,需要注意的是,這樣做並不會刪除原型上的同名屬性,僅僅是阻止執行個體訪問。

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 來自執行個體alert(person2.name) //Nicholas 來自原型

使用delete操作符可以完全刪除執行個體屬性

delete person1.name;alert(person1.name) //Nicholas 來自原型

使用hasOwnProperty()方法可以檢測一個屬性是存在於執行個體還是原型中

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 來自執行個體 alert(person1,hasOwnProperty("name"));//truealert(person2.name) //Nicholas 來自原型 alert(person2,hasOwnProperty("name"));//false delete person1.name;alert(person1.name) //Nicholas 來自原型 alert(person1,hasOwnProperty("name"));//false

下圖展示了在不同情況下執行個體與原型之間的關係

簡單的原型文法

function Person() {} Person.prototype={ name :"Nicholas", age : 22, job : "software Engineer",  sayName:function(){    alert(this.name);    }  };

在上面的代碼中constructor屬性不再指向Person了,通過constructor無法確定對象的類型了。可以像下面這樣特意將他設定回適當的值

function Person() {} Person.prototype={ constructor:Person, name :"Nicholas", age : 22, job : "software Engineer",   sayName:function(){    alert(this.name);    }  };

重設constructor屬性會導致它的[[Enumerable]]特性被設定為true,預設情況,原生的constructor屬性是不可枚舉的,可以使用Object.defineProperty()方法來改變

Object.defineProperty(Person.prototype,"constructor",{  enumerable:false,  value:Person});

原型中尋找值的過程是一次搜尋,原型對象所做的任何修改都能從執行個體上立即反應出來

var friend=new Person();Person.prototype.sayHi=function(){  alert("hi);}friend,sayHi();//"hi"(沒有問題)

person執行個體是在添加新方法之前建立的,但仍可以訪問新添加的方法,原因是執行個體與原型之間的鬆散串連關係
重寫原型對象後的情況

function Person() {}var friend=new Person(); Person.prototype={ name :"Nicholas", age : 22, job : "software Engineer",  sayName:function(){    alert(this.name);    }  };  friend.sayName();//error

調用friend.sayName()時發生錯誤的原因是,friend指向的原型中不包含以該欄位命名的屬性,如下圖。

 

原型對象的問題

原型對象省略了為建構函式傳遞初始化參數這一環節,所有勢力在預設情況下都取得相同的屬性值。原型模型最大的問題是有其共用本性所導致的。當原型模型包含參考型別的屬性來說,問題就比較嚴重了。來看下面的例子。

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、組合使用建構函式模式和原型模式

組合使用建構函式模式和原型模式中,建構函式用於定義執行個體屬性,原型模型用於定義方法和共用的屬性。這樣每個執行個體都會有自己的一份執行個體屬性的副本,同時也可以共用對方法的引用,最大限度的節省了記憶體。

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、動態原型模式

原型動態模式將需要的所有資訊都封裝到建構函式中,通過if語句判斷原型中的某個屬性是否存在,若不存在(在第一次調用這個建構函式的時候),執行if語句內部的原型初始化代碼。

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');//初次調用建構函式,此時修改了原型var person2 = new Person('amy','21');//此時sayName()方法已經存在,不會再修改原型

推薦閱讀:

js物件導向之常見建立對象的幾種方式(原廠模式、建構函式模式、原型模式)

以上所述是小編給大家介紹的JavaScript中建立對象的模式,希望對大家有所協助!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.