欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

跟我學(xué)習(xí)javascript創(chuàng)建對(duì)象(類)的8種方法

 更新時(shí)間:2015年11月20日 10:00:43   作者:小平果118  
跟我學(xué)習(xí)javascript創(chuàng)建對(duì)象(類)的8種方法,每一種方法都有詳細(xì)的介紹,不知道javascript如何創(chuàng)建對(duì)象的朋友,不要錯(cuò)過(guò)這篇文章。

8中javascript創(chuàng)建對(duì)象(類)的方法,依依介紹給大家,希望大家喜歡。

1. 使用Object構(gòu)造函數(shù)來(lái)創(chuàng)建一個(gè)對(duì)象

下面代碼創(chuàng)建了一個(gè)person對(duì)象,并用兩種方式打印出了Name的屬性值。 

 var person = new Object();
  person.name="kevin";
  person.age=31;
  alert(person.name);
  alert(person["name"])

上述寫法的另外一種表現(xiàn)形式是使用對(duì)象字面量創(chuàng)建一個(gè)對(duì)象,不要奇怪person[“5”],這里是合法的;另外使用這種加括號(hào)的方式字段之間是可以有空格的如person[“my age”].

var person = 
  {
    name:"Kevin",
    age:31,
    5:"Test"
  };
  alert(person.name);
  alert(person["5"]);

雖然Object 構(gòu)造函數(shù)或?qū)ο笞置媪慷伎梢杂脕?lái)創(chuàng)建單個(gè)對(duì)象,但這些方式有個(gè)明顯的缺點(diǎn):使用同一個(gè)接口創(chuàng)建很多對(duì)象,會(huì)產(chǎn)生大量的重復(fù)代碼。為解決這個(gè)問(wèn)題,人們開(kāi)始使用工廠模式的一種變體。

2、工廠模式

工廠模式是軟件工程領(lǐng)域一種廣為人知的設(shè)計(jì)模式,這種模式抽象了創(chuàng)建具體對(duì)象的過(guò)程,考慮到在ECMAScript 中無(wú)法創(chuàng)建類,開(kāi)發(fā)人員就發(fā)明了一種函數(shù),用函數(shù)來(lái)封裝以特定接口創(chuàng)建對(duì)象的細(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 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");

工廠模式雖然解決了創(chuàng)建多個(gè)相似對(duì)象的問(wèn)題,但卻沒(méi)有解決對(duì)象識(shí)別的問(wèn)題(即怎樣知道一個(gè)對(duì)象的類型)。隨著JavaScript
的發(fā)展,又一個(gè)新模式出現(xiàn)了。

3. 構(gòu)造函數(shù)模式

像Object 和Array 這樣構(gòu)造函數(shù),在運(yùn)行時(shí)會(huì)自動(dòng)出現(xiàn)在執(zhí)行環(huán)境中。此外,也可以創(chuàng)建自定義的構(gòu)造函數(shù),從而定義自定義對(duì)象類型的屬性和方法。例如,可以使用構(gòu)造函數(shù)模式將前面的例子重寫如下?!?/p>

function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function(){
  alert(this.name);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

在這個(gè)例子中,Person()函數(shù)取代了createPerson()函數(shù)。我們注意到,Person()中的代碼除了與createPerson()中相同的部分外,還存在以下不同之處:

  • 沒(méi)有顯式地創(chuàng)建對(duì)象;
  • 直接將屬性和方法賦給了this 對(duì)象;
  • 沒(méi)有return 語(yǔ)句。

要?jiǎng)?chuàng)建Person 的新實(shí)例,必須使用new 操作符。以這種方式調(diào)用構(gòu)造函數(shù)實(shí)際上會(huì)經(jīng)歷以下4個(gè)步驟:

(1) 創(chuàng)建一個(gè)新對(duì)象;
(2) 將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此this 就指向了這個(gè)新對(duì)象);
(3) 執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性);
(4) 返回新對(duì)象。
在前面例子的最后,person1 和person2 分別保存著Person 的一個(gè)不同的實(shí)例。這兩個(gè)對(duì)象都有一個(gè)constructor(構(gòu)造函數(shù))屬性,該屬性指向Person,如下所示。

alert(person1.constructor == Person); //true
alert(person2.constructor == Person); //true

對(duì)象的constructor 屬性最初是用來(lái)標(biāo)識(shí)對(duì)象類型的。但是,提到檢測(cè)對(duì)象類型,還是instanceof操作符要更可靠一些。我們?cè)谶@個(gè)例子中創(chuàng)建的所有對(duì)象既是Object 的實(shí)例,同時(shí)也是Person的實(shí)例,這一點(diǎn)通過(guò)instanceof 操作符可以得到驗(yàn)證。

alert(person1 instanceof Object); //true
alert(person1 instanceof Person); //true
alert(person2 instanceof Object); //true
alert(person2 instanceof Person); //true

創(chuàng)建自定義的構(gòu)造函數(shù)意味著將來(lái)可以將它的實(shí)例標(biāo)識(shí)為一種特定的類型;而這正是構(gòu)造函數(shù)模式勝過(guò)工廠模式的地方。在這個(gè)例子中,person1 和person2 之所以同時(shí)是Object 的實(shí)例,是因?yàn)樗袑?duì)象均繼承自O(shè)bject。

構(gòu)造函數(shù)的問(wèn)題

構(gòu)造函數(shù)模式雖然好用,但也并非沒(méi)有缺點(diǎn)。使用構(gòu)造函數(shù)的主要問(wèn)題,就是每個(gè)方法都要在每個(gè)實(shí)例上重新創(chuàng)建一遍。

ECMAScript 中的函數(shù)是對(duì)象,因此每定義一個(gè)函數(shù),也就是實(shí)例化了一個(gè)對(duì)象。從邏輯角度講,此時(shí)的構(gòu)造函數(shù)也可以這樣定義。

function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = new Function("alert(this.name)"); // 與聲明函數(shù)在邏輯上是等價(jià)的
}

從這個(gè)角度上來(lái)看構(gòu)造函數(shù),更容易明白每個(gè)Person 實(shí)例都包含一個(gè)不同的Function 實(shí)例(以顯示name 屬性)的本質(zhì)。說(shuō)明白些,以這種方式創(chuàng)建函數(shù),會(huì)導(dǎo)致不同的作用域鏈和標(biāo)識(shí)符解析,但創(chuàng)建Function 新實(shí)例的機(jī)制仍然是相同的。因此,不同實(shí)例上的同名函數(shù)是不相等的,以下代碼可以證明這一點(diǎn)。

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

然而,創(chuàng)建兩個(gè)完成同樣任務(wù)的Function 實(shí)例的確沒(méi)有必要;況且有this 對(duì)象在,根本不用在執(zhí)行代碼前就把函數(shù)綁定到特定對(duì)象上面。因此,大可像下面這樣,通過(guò)把函數(shù)定義轉(zhuǎn)移到構(gòu)造函數(shù)外部來(lái)解決這個(gè)問(wèn)題。

function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = sayName;
}
function sayName(){
  alert(this.name);
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

如果對(duì)象需要定義很多方法,那么就要定義很多個(gè)全局函數(shù),于是我們這個(gè)自定義的引用類型就絲毫沒(méi)有封裝性可言了。好在,這些問(wèn)題可以通過(guò)使用原型模式來(lái)解決。

4、原型模式

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
  alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true

要理解原型對(duì)象,可見(jiàn)我的另一篇博客:JavaScript prototype詳解

前面例子中每添加一個(gè)屬性和方法就要敲一遍Person.prototype。為減少不必要的輸入,也為了從視覺(jué)上更好地封裝原型的功能,更常見(jiàn)的做法是用一個(gè)包含所有屬性和方法的對(duì)象字面量來(lái)重寫整個(gè)原型對(duì)象,如下面的例子所示。

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

在上面的代碼中,我們將Person.prototype 設(shè)置為等于一個(gè)以對(duì)象字面量形式創(chuàng)建的新對(duì)象。最終結(jié)果相同,但有一個(gè)例外:constructor 屬性不再指向Person 了。前面曾經(jīng)介紹過(guò),每創(chuàng)建一個(gè)函數(shù),就會(huì)同時(shí)創(chuàng)建它的prototype 對(duì)象,這個(gè)對(duì)象也會(huì)自動(dòng)獲得constructor 屬性。而我們?cè)谶@里使用的語(yǔ)法,本質(zhì)上完全重寫了默認(rèn)的prototype 對(duì)象,因此constructor 屬性也就變成了新對(duì)象的constructor 屬性(指向Object 構(gòu)造函數(shù)),不再指向Person 函數(shù)。此時(shí),盡管instanceof操作符還能返回正確的結(jié)果,但通過(guò)constructor 已經(jīng)無(wú)法確定對(duì)象的類型了,如下所示。

var friend = new Person();
alert(friend instanceof Object); //true
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //false
alert(friend.constructor == Object); //true

在此,用instanceof 操作符測(cè)試Object 和Person 仍然返回true,但constructor 屬性則等于Object 而不等于Person 了。如果constructor 的值真的很重要,可以像下面這樣特意將它設(shè)置回適當(dāng)?shù)闹怠?/p>

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

需要注意一點(diǎn)就是:實(shí)例中的指針僅指向原型,而不指向構(gòu)造函數(shù)。

原型對(duì)象的問(wèn)題:原型模式也不是沒(méi)有缺點(diǎn)。首先,它省略了為構(gòu)造函數(shù)傳遞初始化參數(shù)這一環(huán)節(jié),結(jié)果所有實(shí)例在默認(rèn)情況下都將取得相同的屬性值。雖然這會(huì)在某種程度上帶來(lái)一些不方便,但還不是原型的最大問(wèn)題。原型模式的最大問(wèn)題是由其共享的本性所導(dǎo)致的。

function Person(){
}
Person.prototype = {
  constructor: Person,
  name : "Nicholas",
  age : 29,
  job : "Software Engineer",
  friends : ["Shelby", "Court"],
  sayName : function () {
    alert(this.name);
  }
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Court,Van"
alert(person2.friends); //"Shelby,Court,Van"
alert(person1.friends === person2.friends); //true

5、組合使用構(gòu)造函數(shù)模式和原型模式(最常用)

創(chuàng)建自定義類型的最常見(jiàn)方式,就是組合使用構(gòu)造函數(shù)模式與原型模式。構(gòu)造函數(shù)模式用于定義實(shí)例屬性,而原型模式用于定義方法和共享的屬性。結(jié)果,每個(gè)實(shí)例都會(huì)有自己的一份實(shí)例屬性的副本,但同時(shí)又共享著對(duì)方法的引用,最大限度地節(jié)省了內(nèi)存。另外,這種混成模式還支持向構(gòu)造函數(shù)傳遞參數(shù);可謂是集兩種模式之長(zhǎng)。

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", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true

6、動(dòng)態(tài)原型模式

有其他OO 語(yǔ)言經(jīng)驗(yàn)的開(kāi)發(fā)人員在看到獨(dú)立的構(gòu)造函數(shù)和原型時(shí),很可能會(huì)感到非常困惑。動(dòng)態(tài)原型模式正是致力于解決這個(gè)問(wèn)題的一個(gè)方案,它把所有信息都封裝在了構(gòu)造函數(shù)中,而通過(guò)在構(gòu)造函數(shù)中初始化原型(僅在必要的情況下),又保持了同時(shí)使用構(gòu)造函數(shù)和原型的優(yōu)點(diǎn)。換句話說(shuō),可以通過(guò)檢查某個(gè)應(yīng)該存在的方法是否有效,來(lái)決定是否需要初始化原型。來(lái)看一個(gè)例子。

function Person(name, age, job){
  //屬性
  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", 29, "Software Engineer");
friend.sayName();

7、寄生構(gòu)造函數(shù)模式

通常,在前述的幾種模式都不適用的情況下,可以使用寄生(parasitic)構(gòu)造函數(shù)模式。這種模式的基本思想是創(chuàng)建一個(gè)函數(shù),該函數(shù)的作用僅僅是封裝創(chuàng)建對(duì)象的代碼,然后再返回新創(chuàng)建的對(duì)象;但從表面上看,這個(gè)函數(shù)又很像是典型的構(gòu)造函數(shù)。下面是一個(gè)例子。

function Person(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 friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName(); //"Nicholas"

在這個(gè)例子中,Person 函數(shù)創(chuàng)建了一個(gè)新對(duì)象,并以相應(yīng)的屬性和方法初始化該對(duì)象,然后又返回了這個(gè)對(duì)象。除了使用new 操作符并把使用的包裝函數(shù)叫做構(gòu)造函數(shù)之外,這個(gè)模式跟工廠模式其實(shí)是一模一樣的。構(gòu)造函數(shù)在不返回值的情況下,默認(rèn)會(huì)返回新對(duì)象實(shí)例。

8、穩(wěn)妥構(gòu)造函數(shù)模式

所謂穩(wěn)妥對(duì)象,指的是沒(méi)有公共屬性,而且其方法也不引用this 的對(duì)象。穩(wěn)妥對(duì)象最適合在一些安全的環(huán)境中(這些環(huán)境中會(huì)禁止使用this 和new),或者在防止數(shù)據(jù)被其他應(yīng)用程序(如Mashup程序)改動(dòng)時(shí)使用。穩(wěn)妥構(gòu)造函數(shù)遵循與寄生構(gòu)造函數(shù)類似的模式,但有兩點(diǎn)不同:一是新創(chuàng)建對(duì)象的實(shí)例方法不引用this;二是不使用new 操作符調(diào)用構(gòu)造函數(shù)。按照穩(wěn)妥構(gòu)造函數(shù)的要求,可以將前面的Person 構(gòu)造函數(shù)重寫如下。

function Person(name, age, job){
  //創(chuàng)建要返回的對(duì)象
  var o = new Object();
  //可以在這里定義私有變量和函數(shù)
  //添加方法
  o.sayName = function(){
    alert(name);
  };
//返回對(duì)象
return o;
}

以上javascript創(chuàng)建對(duì)象(類)的8種方法大家有沒(méi)有學(xué)會(huì),希望對(duì)大家的學(xué)習(xí)有所幫助。

相關(guān)文章

最新評(píng)論