亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

淺談JavaScript對象的創建方式

2019-11-20 09:42:43
字體:
來源:轉載
供稿:網友

通過Object構造函數或對象字面量創建對象時,使用同一個接口創建很多對象時,會產生大量的重復代碼。為了簡化,引入了工廠模式。

工廠模式

function createPerson(name, age, job) {  var obj = new Object();  obj.name = name;  obj.age = age;  obj.job = job;  obj.sayHello(){    alert(this.name);  };  return obj;}var p1 = createPerson("xxyh", 19, "programmer");var p2 = createPerson("zhangsan", 18, "student");

這種創建對象的方式大大簡化了代碼,然而也存在不足,那就是無法確定對象的類型。為了解決這個問題,出現下面這種模式。

構造函數模式

創建自定義的構造函數,從而定義自定義對象類型的屬性和方法。

function Person(name, age, job) {  this.name = name;  this.age = age;  this.job = job;  this.sayName = function () {    alert(this.name);  };}var p1 = new Person("xxyh", 19, "programmer");var p2 = new Person("Jack", 18, "student");

上例中,Person()取代了createPerson(),除此之外,還有幾點不同:

•沒有顯示地創建對象;

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

•沒有return語句

創建Person對象,必須使用new操作符。分為4個步驟:

•創建一個新對象

•將構造函數的作用域賦給新對象

•執行構造函數中的代碼

•返回新對象

p1和p2分別保存著Person的一個實例。

alert(p1.constructor == Person);  // truealert(p2.constructor == Person);  // true

檢測類型時最好使用instanceof:

alert(p1 instanceof Object);  // truealert(p1 instanceof Person);  // truealert(p2 instanceof Object);  // truealert(p2 instanceof Person);  // true

p1和p2都是Object的實例,因為所有對象均繼承自Object。

2.1將構造函數當作函數

// 當作構造函數使用var person = new Person("xxyh", 19, "programmer");person.sayName();  // "xxyh"http:// 當作普通函數Person("zhangsan", 18, "student");  // 添加到windowwindow.sayName();  // "zhangsan"http:// 在另一個對象的作用域中調用var obj = new Object();Person.call(obj, "Jack", 29, "manager");obj.sayName();  // "Jack",obj擁有了所有屬性和方法

2.2構造函數的問題

使用構造函數的問題,就是每個方法都要在每個實例上重新創建一遍。p1和p2都有一個sayName()方法,但是他們不是一個Function的實例。在JavaScript中,函數時對象,因此每定義一個函數,就實例化了一個對象。

構造函數也可以這樣定義:

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

因此,不同實例上的同名函數時不相等的:

alert(p1.sayName == p2.sayName);  // false

然而,創建兩個同樣功能的Function是多余的,根本不需要在執行代碼前就把函數綁定到特定對象上面。

function Person(name, age, job) {  this.name = name;  this.age = age;  this.job = job;  this.sayName = sayName;}function sayName() {  alert(this.name);}var p1 = new Person("xxyh", 19, "programmer");var p2 = new Person("Jack", 18, "student");

上面將sayName()的定義移到構造函數外部,然后在構造函數內部將屬性sayName設置為全局的sayName函數。這樣,sayName包含了指向函數的指針,p1和p2共享了全局作用域中定義的同一個sayName()函數。

但是,這樣做又出現了新問題:在全局作用域中定義的函數只能被某個對象調用。而且如果對象定義了很多方法,那么引用類型就失去了封裝性。

原型鏈模式

每個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象。這個對象的用途是:包含可以由特定類型的所有實例共享的屬性和方法。prototype是通過調用構造函數而創建的那個對象實例的原型對象。使用原型對象的好處是可以讓所有對象實例共享它所包含的屬性和方法。這就是說不必在構造函數中定義對象實例的信息,而是將這些信息添加到原型對象中。

function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = 19;Person.prototype.job = "programmer";Person.prototype.sayName = function () {  alert(this.name);};var person1 = new Person();person1.sayName(); // "xxyh"var person2 = new Person();person2.sayName(); // "xxyh"alert(person1.sayName == person2.sayName); // true

3.1理解原型對象

只要創建一個新函數,就會為該函數創建一個prototype屬性,這個屬性指向函數的原型對象。在默認情況下,所有原型對象都會自動獲得一個constructor屬性。這個屬性包含一個指向prototype屬性所在函數的指針。Person.prototype.constructor指向Person。

當調用構造函數創建一個實例,實例的內部將包含指向構造函數的原型對象的指針(內部屬性),稱為[[Prototype]]。在Firefox、Safari和Chrome通過_proto_訪問。這個連接存在于實例與構造函數的原型對象之間,而不是存在于實例與構造函數之間。

下圖展示了各個對象之間的關系:

Person.prototype指向了原型對象,而Person.prototype.constructor又指回了Person。原型中除了constructor屬性,還有其他添加的屬性。Person實例中都包含一個內部屬性,該屬性僅僅指向了Person.prototype,它們和構造函數沒有直接關系。

雖然無法訪問[[Prototype]],但是可以通過isPrototypeOf()方法來確定對象之間是否存在這種關系。

alert(Person.prototype.isPrototypeOf(person1));  // truealert(Person.prototype.isPrototypeOf(person2));  // true

在讀取某個對象的屬性時,都會執行一次搜索,目標是具有給定名字的屬性。搜索首先從對象實例本身開始。搜索首先從對象實例本身出發開始,如果在實例中找到了具有給定名字的屬性,則返回該屬性的值;如果沒有找到,則繼續搜索指針指向的原型對象,在原型對象中查找給定名字的屬性。如果在原型對象中找到了這個屬性,則返回屬性的值。

可以通過對象實例訪問保存在原型中的值,但卻不能通過對象實例重寫原型中的值。如果在實例中添加一個與實例原型中的一個屬性同名的屬性,該屬性將會屏蔽原型中的屬性。

function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () {  alert(this.name);};var person1 = new Person();var person2 = new Person();person1.name = "oooo";alert(person1.name);  // "oooo"alert(person2.name);  // "xxyh"

上例中,person1中的name屬性屏蔽了原型中的name屬性。

當對象實例添加一個屬性時,這個屬性就會屏蔽原型對象中保存的同名屬性。這也就是說,這個屬性的存在會阻止對原型中那個屬性的訪問。使用delete可以完成刪除實例屬性。

function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () {  alert(this.name);};var person1 = new Person();var person2 = new Person();person1.name = "oooo";alert(person1.name);  // "oooo"alert(person2.name);  // "xxyh"delete person1.name;alert(person1.name);  // "xxyh"

hasOwnProperty()可以檢測一個屬性是存在于實例中,還是存在于原型中。

function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () {  alert(this.name);};var person1 = new Person();var person2 = new Person();alert(person1.hasOwnProperty("name"));  // falseperson1.name = "oooo";alert(person1.hasOwnProperty("name"));  // true

下圖展示了不同情況的實現與原型的關系:

3.2原型與in操作符

使用in操作符的方式:單獨使用、在for-in循環中使用。在單獨使用時,in操作符會在通過對象能夠訪問給定屬性時返回true,無論該屬性存在于實例中還是原型中。

function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () {  alert(this.name);};var person1 = new Person();alert("name" in person1);  // trueperson1.name = "oooo";alert("name" in person1);  // true

結合前面的hasOwnProperty()特點,可以確定某個屬性是原型中的屬性還是實例中的屬性。如果in操作符返回true而hasOwnProperty返回false,則屬性是原型中的屬性。

function hasPrototypeProperty(object, name) {  return !object.hasOwnProperty(name)&& (name in object);}

接下來,看看hasPrototypeProperty()的用法:

function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () {  alert(this.name);};var person = new Person();alert(hasPrototypeProperty(person, "name"));  // trueperson.name = "oooo";alert(hasPrototypeProperty(person, "name"));  // false

在使用for-in循環時返回的是所有能夠通過對象訪問的、可枚舉的屬性,包括實例中的屬性和原型中的屬性。屏蔽了原型中不可枚舉數據(即[[Enumerable]]標記為false的屬性)的實例屬性也會在for-in中返回,因為根據規定,開發人員定義的屬性都是可枚舉的。

要取得對象上所有可枚舉的實例屬性,可以使用Object.keys()方法。

function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () {  alert(this.name);};var keys = Object.keys(Person.prototype);alert(keys);      // name, age, job, sayNamevar p1 = new Person();p1.name = "oooo";p1.age = 15;var p1_keys = Object.keys(p1);alert(p1_keys);     // name, age

如果需要得到所有實例屬性,可以使用Object.getOwnPropertyNames()方法

var keys = Object.getOwnPropertyNames(Person.prototype);alert(keys);  // "constructor,name,age,job,sayName"

3.3更簡單的原型語法

為了精簡輸入,用一個包含所有屬性和方法的對象字面量來重寫整合原型對象。

function Person() {   }Person.prototype = {  name : "xxyh",  age : 18,  job : "programmer",  sayName : function () {    alert(this.name);  }};

上面將Person.prototype設置為等于一個以對象字面量形式創建的新對象。結果相同,但是constructor屬性不在指向Person了。

通過instanceof能返回正確結果,但是constructor無法確定對象的類型:

var boy = new Person();alert(boy instanceof Object);    // truealert(boy instanceof Person);    // truealert(boy.constructor == Person);  // falsealert(boy.constructor == Object);  // true

可以通過下面的方式設置constructor的值:

function Person() {}Person.prototype = {  constructor : Person,  name : "xxyh",  age : 18,  job : "programmer",  sayName : function () {    alert(this.name);  }};

3.4原型鏈的動態性

由于在原型中查找值的過程是一次搜索,因此對原型對象所做的任何修改都會反映到實例上。但是如果重寫整個原型對象,結果就不同了。調用構造函數時會為實例添加一個指向最初原型的[[prototype]]指針,而把原型修改為另一個對象就等于切斷了構造函數與最初原型的聯系。實例中的指針僅指向原型,而不指向構造函數。

function Person() {}var boy = new Person();Person.prototype = {  constructor : Person,  name : "xxyh",  age : 29,  job : "programmer",  sayName : function () {    alert(this.name);  }};boy.sayName();  // 錯誤

具體過程如下:

從上面可以看出,重寫原型對象切斷了現有原型與任何之前已經存在的對象實例之間的聯系;它們引用的是最初的原型。

3.5原生對象的原型

所有原生引用類型都是在構造函數的原型上定義了方法。通過原生對象的原型,不僅可以取得默認方法,而且可以定義新方法。

String.prototype.startsWith = function (text) {  return this.indexOf(text) == 0;};var msg = "good morning";alert(msg.startsWith("good")); // true

3.6原型對象的問題

原型模式存在兩個問題:

•在默認情況下都取得相同的屬性值。

•原型中的所有屬性是實例共享的

下面看一個例子:

function Person() {}Person.prototype = {  constructor: Person,  name: "xxyh",  age : 18,  job : "programmer",  friends:["張三", "李四"],  sayName: function () {    alert(this.name);  }};var p1 = new Person();var p2 = new Person();p1.friends.push("王五");alert(p1.friends);         // 張三,李四,王五alert(p2.friends);         // 張三,李四,王五alert(p1.friends == p2.friends);  // true

上面通過p1.friends添加了一項,由于friends數組存在于Person.prototype中,所以在p2.friends也反映出來了??墒?,實例一般都是要有屬于自己的全部屬性的。

組合使用構造函數模式和原型模式

構造函數模式用于定義實例屬性,原型模式用于定義方法和共享的屬性。這樣,每個實例都會有自己的一份實例屬性的副本,但是同時又共享著對方法的引用。

function Person(name, age, job) {  this.name = name;  this.age = age;  this.job = job;  this.friends = ["張三", "李四"];}Person.prototype = {  constructor: Person,  sayName: function () {    alert(this.name);  }}var p1 = new Person("蕭蕭弈寒", 18, "programmer");var p2 = new Person("魁拔", 10, "捉妖");p1.friends.push("王五");alert(p1.friends);         // 張三,李四,王五alert(p2.friends);         // 張三,李四alert(p1.friends == p2.friends);  // falsealert(p1.sayName == p2.sayName);  // true

上例中,實例屬性都是在構造函數中定義的,共享屬性constructor和方法sayName()則是在原型中定義的。p1.friends的修改并不會影響到p2.friends的結果。

動態原型模式

動態原型模式把所有信息都封裝在了構造函數中,而通過在構造函數中初始化原型,又保持了同時使用構造函數和原型的優點。這就是說,可以通過檢查某個應該存在的方法是否有效,來決定是否需要初始化原型。

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

這里只在sayName()方法不存在時,才會將它添加到原型中,只會在初次調用構造函數時執行。

寄生構造函數模式

這種模式的思想是創建一個函數,該函數的作用是封裝創建對象的代碼,然后再返回新創建的對象。

function Person(name, age) {  var obj = new Object();  obj.name = name;  obj.age = age;  obj.sayName = function () {    alert(this.name);  }  return obj;}var boy = new Person("xxyh", 19, "programmer");boy.sayName();

需要說明:首先,返回的對象與構造函數或者與構造函數的原型屬性之間沒有關系;構造函數返回的對象與在構造函數外部創建的對象沒有不同。不能依賴instanceof操作符來確定對象類型。

穩妥構造函數模式

穩妥對象指的是沒有公共屬性,而且其方法也不引用this的對象。穩妥構造函數遵循與寄生構造函數類似的模式,但是有兩點不同:

•新創建對象的實例方法不引用this;

•不使用new操作符調用構造函數

重寫Person構造函數如下:

function Person(name, age, job) {  var obj = new Object();  obj.sayName = function () {    alert(name);  };  return obj;}
function Person(name, age, job) {  var obj = new Object();  obj.sayName = function () {    alert(name);  };  return obj;}

以上這篇淺談JavaScript對象的創建方式就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
高跟丝袜一区二区三区| 欧美激情va永久在线播放| 7777kkkk成人观看| 中文字幕日韩电影| 粉嫩av一区二区三区免费野| 久久精品国产电影| 欧美中文字幕在线观看| 精品色蜜蜜精品视频在线观看| 国产精品国产亚洲伊人久久| 在线视频日本亚洲性| 亚洲大胆美女视频| 国产成人精品久久二区二区| 国产精品久久久久久久久久东京| 欧美精品激情在线观看| 亚洲成人aaa| 亚洲欧美一区二区精品久久久| 日韩最新中文字幕电影免费看| 久久夜色撩人精品| 欧美大片欧美激情性色a∨久久| 日韩亚洲综合在线| 亚洲欧洲中文天堂| 日韩美女福利视频| 欧美一级片久久久久久久| 91精品国产91久久久久久最新| 日韩天堂在线视频| 久久人人爽人人爽人人片av高请| 一级做a爰片久久毛片美女图片| 97超碰色婷婷| 国产色综合天天综合网| 久久精品视频网站| 久久国产精品免费视频| 成人有码视频在线播放| 国产成人一区二区| 两个人的视频www国产精品| 国产精品国模在线| 日本高清不卡的在线| 国产亚洲xxx| 久久免费视频网| 久久精品99久久香蕉国产色戒| 57pao成人国产永久免费| 欧美一区深夜视频| 欧美精品电影免费在线观看| 黑人狂躁日本妞一区二区三区| 日韩视频免费观看| 久久视频在线播放| 亚洲香蕉成视频在线观看| 成人av在线天堂| 久久久精品久久久| 26uuu另类亚洲欧美日本老年| 中文字幕亚洲专区| 在线不卡国产精品| 日韩美女在线看| 久久久久久久久久av| 久久久噜久噜久久综合| 51ⅴ精品国产91久久久久久| 亚洲免费视频网站| 日韩在线观看精品| 在线观看欧美视频| 午夜精品一区二区三区视频免费看| 91九色单男在线观看| 日韩欧中文字幕| xxx一区二区| 九九久久国产精品| 国产欧美日韩丝袜精品一区| 欧美疯狂性受xxxxx另类| 中文字幕久热精品在线视频| 久久久亚洲国产| 久久久噜噜噜久久| 精品亚洲一区二区三区四区五区| 欧美午夜精品久久久久久久| 亚洲热线99精品视频| 亚洲性线免费观看视频成熟| 91免费视频国产| 久久免费少妇高潮久久精品99| 青青久久av北条麻妃黑人| 热门国产精品亚洲第一区在线| 色七七影院综合| 国产精品成久久久久三级| 国产精品久久国产精品99gif| 国产偷亚洲偷欧美偷精品| 久久国产精品久久久久| 日韩一区二区av| 国产精品午夜一区二区欲梦| 欧美日韩国产色视频| 亚洲欧洲成视频免费观看| 国产精品尤物福利片在线观看| 一区二区三区www| 91夜夜揉人人捏人人添红杏| 亚洲福利视频二区| 国产精品日日摸夜夜添夜夜av| 欧美多人爱爱视频网站| 欧美精品免费看| 欧美激情第1页| 欧美激情久久久久久| 亚洲国产成人久久综合| 国产精品久久久久久亚洲调教| 国产成人一区二区三区电影| 成人久久一区二区| 欧美激情精品久久久久久免费印度| 国产成人在线精品| 欧美日韩国产一区中文午夜| 国产91色在线播放| 日韩一区av在线| 在线视频一区二区| 欧美理论电影网| 欧美美女操人视频| 少妇高潮 亚洲精品| 亚洲精品动漫100p| 欧美激情精品在线| 亚洲第一综合天堂另类专| 久久久久国产精品一区| 91精品在线播放| 亚洲另类欧美自拍| 亚洲人成啪啪网站| 亚洲人线精品午夜| 正在播放欧美一区| 欧美日韩一区二区免费在线观看| 91国内产香蕉| 欧美激情日韩图片| 国产啪精品视频| 欧美性极品少妇精品网站| 亚洲性夜色噜噜噜7777| 欧美日韩加勒比精品一区| 成人日韩av在线| 精品国产电影一区| 亚洲精品久久久久中文字幕欢迎你| 国产精品福利在线观看网址| 久久噜噜噜精品国产亚洲综合| 69国产精品成人在线播放| 欧美视频裸体精品| 国产精品视频地址| 97色伦亚洲国产| 精品国产91久久久久久老师| 欧美体内谢she精2性欧美| 国产丝袜一区二区三区免费视频| 国产欧美日韩最新| 俺去啦;欧美日韩| 亚洲精品国产精品国产自| 91久久精品国产91性色| 国产日韩欧美中文在线播放| 欧美一级电影免费在线观看| 欧美小视频在线| 日韩av不卡电影| 久久久久久91香蕉国产| 国产精品久久网| 亚洲香蕉伊综合在人在线视看| 亚洲第一免费播放区| 97视频在线观看成人| 粉嫩av一区二区三区免费野| 国产精品99久久久久久久久| 欧美韩国理论所午夜片917电影| 日韩av在线高清| 中文字幕亚洲激情| 精品国产一区二区三区久久狼5月| 欧美日韩综合视频| 久久久亚洲福利精品午夜| 97超视频免费观看| 国产精品一区二区3区| 欧美超级乱淫片喷水| 欧美在线视频a| 欧美巨猛xxxx猛交黑人97人| 国产97免费视| 国产成人精品久久二区二区91| 成人免费观看网址|