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

首頁 > 編程 > JavaScript > 正文

淺析在javascript中創建對象的各種模式

2019-11-20 10:08:35
字體:
來源:轉載
供稿:網友

最近在看《javascript高級程序設計》(第二版)

javascript中對象的創建

•工廠模式

•構造函數模式

•原型模式

•結合構造函數和原型模式

•原型動態模式

面向對象的語言大都有一個類的概念,通過類可以創建多個具有相同方法和屬性的對象。雖然從技術上講,javascript是一門面向對象的語言,但是javascript沒有類的概念,一切都是對象。任意一個對象都是某種引用類型的實例,都是通過已有的引用類型創建;引用類型可以是原生的,也可以是自定義的。原生的引用類型有:Object、Array、Data、RegExp、Function。 !引用類型就是一種數據結構,將數據和功能組織在一起,通常被稱為類。 缺乏類概念的javascript中,需要解決的問題就是如何高效的創建對象。

1.1.0.創建對象的一般方法

var person = {}; //對象字面量表示,等同于var person = new Objcect();person.name = 'evansdiy';person.age = '22';person.friends = ['ajiao','tiantian','pangzi'];person.logName = function() {  console.log(this.name);}

基于Object引用類型,創建了一個對象,該對象包含四個屬性,其中一個為方法。如果需要很多類似person的實例,那就會有許多重復的代碼。

1.1.1.工廠模式 [top]

通過一個可以包含了對象細節的函數來創建對象,然后返回這個對象。

function person(name,age,friends) {  var o = {    name: name,    age: age,    friends: friends,    logName: function() {      console.log(this.name);    }  };  return o;}var person1 = person('Evansdiy','22',['ajiao','tiantian','pangzi']);

每次調用person函數,都會通過該函數內部的對象o創建新的對象,然后返回,除此之外,這個為了創建新對象而存在的內部對象o沒有其他的用途。另外,無法判斷工廠模式創建的對象的類型。

1.1.2.構造函數模式 [top]

function Person(name,age,job) {  this.name = name;  this.age = age;  this.job = job;  this.logName = function() {    console.log(this.name);  }}//通過new操作符創建Person的實例var person1 = new Person('boy-a','22','worker');var person2 = new Person('girl-b','23','teacher');person1.logName(); //boy-aperson2.logName(); //girl-a

對比工廠模式,可以發現,這里并不需要創建中間對象,沒有return。另外,可以將構造函數的實例標識為一種特定的類型,這就解決了對象識別的問題(通過檢查實例的constructor屬性,或利用instanceof操作符檢查該實例是否通過某個構造函數創建)。

console.log(person1.constructor == Person);//constructor位于構造函數原型中,并指向構造函數,結果為true

console.log(person1 instanceof Person);//通過instanceof操作符,判斷person1是否為構造函數Person的實例但構造函數模式也有自己的問題,實際上,logName方法在每個實例上都會被重新創建一次,需要注意的是,通過實例化創建的方法且并不相等,以下代碼將會得到false:

console.log(person1.logName == person2.logName);//false我們可以將方法移到構造器外部(變為全局函數)來解決這個問題:

function logName() {  console.log(this.name);}function logAge() {  console.log(this.age);}

但是,在全局下創建的全局函數實際上只能被經由Person創建的實例調用,這就有點名不副實了;如果方法很多,還需要逐一定義,缺少封裝性。

1.1.3.原型模式 [top]

javascript中的每一個函數都包含一個指向prototype屬性的指針(大部分瀏覽器可以通過內部屬性__proto__訪問),prototype屬性是一個對象,其中包含了由某種引用類型創建的所有實例共享的屬性和方法。 

function Person() {}Person.name = 'evansdiy';Person.prototype.friends = ['ajiao','jianjian','pangzi'];Person.prototype.logName = function() {  console.log(this.name);}var person1 = new Person();person1.logName();//'evansdiy'

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

1.定義了一個構造函數Person,Person函數自動獲得一個prototype屬性,該屬性默認只包含一個指向Person的constructor屬性;

2.通過Person.prototype添加三個屬性,其中一個作為方法;

3.創建一個Person的實例,隨后在實例上調用了logName()方法。

這里需要注意的是logName()方法的調用過程:

1.在person1實例上查找logName()方法,發現沒有這個方法,于是追溯到person1的原型

2.在person1的原型上查找logame()方法,有這個方法,于是調用該方法 基于這樣一個查找過程,我們可以通過在實例上定義原型中的同名屬性,來阻止該實例訪問原型上的同名屬性,需要注意的是,這樣做并不會刪除原型上的同名屬性,僅僅是阻止實例訪問。

var person2 = new Person();

person2.name = 'laocai';如果我們不再需要實例上的屬性時,可以通過delete操作符刪除。

delete person2.name;利用for-in循環枚舉出實例可以訪問到的所有屬性(不論該屬性存在于實例或是原型中):

for(i in person1) {  console.log(i);}

同時,也可以利用hasOwnProperty()方法判斷某個屬性到底存在于實例上,還是存在于原型中,只有當屬性存在于實例中,才會返回true:

console.log(person1.hasOwnProperty('name'));//true!hasOwnProperty來自Object的原型,是javascript中唯一一個在處理屬性時不查找原型鏈的方法。[via javascript秘密花園] 另外,也可以通過同時使用in操作符和hasOwnProperty()方法來判斷某個屬性存在于實例中還是存在于原型中:

console.log(('friends' in person1) && !person1.hasOwnProperty('friends'));先判斷person1是否可以訪問到friends屬性,如果可以,再判斷這個屬性是否存在于實例當中(注意前面的!),如果不存在于實例中,就說明這個屬性存在于原型中。 前面提到,原型也是對象,所以我們可以用對象字面量表示法書寫原型,之前為原型添加代碼的寫法可以修改為: 

Person.prototype = {  name: 'evansdiy',  friends: ['ajiao','jianjian','pangzi'],  logName: function() {    console.log(this.name);  }}

由于對象字面量語法重寫了整個prototype原型,原先創建構造函數時默認取得的constructor屬性會指向Object構造函數:

//對象字面量重寫原型之后

console.log(person1.constructor);//Object不過,instanceof操作符仍會返回希望的結果:

//對象字面量重寫原型之后

console.log(person1 instanceof Person);//true當然,可以在原型中手動設置constructor的值來解決這個問題。

Person.prototype = {  constructor: Person,  ......}

如果在創建對象實例之后修改原型對象,那么對原型的修改會立即在所有對象實例中反映出來:

function Person() {};var person1 = new Person();Person.prototype.name = 'evansdiy';console.log(person1.name);//'evansdiy'

實例和原型之間的連接僅僅是一個指針,而不是一個原型的拷貝,在原型實際上是一次搜索過程,對原型對象的所做的任何修改都會在所有對象實例中反映出來,就算在創建實例之后修改原型,也是如此。 如果在創建對象實例之后重寫原型對象,情況又會如何?

function Person() {};var person1 = new Person1();//創建的實例引用的是最初的原型//重寫了原型Person.prototype = {  friends: ['ajiao','jianjian','pangzi']}var person2 = new Person();//這個實例引用新的原型console.log(person2.friends);console.log(person1.friends);

以上代碼在執行到最后一行時會出現未定義錯誤,如果我們用for-in循環枚舉person1中的可訪問屬性時,會發現,里頭空無一物,但是person2卻可以訪問到原型上的friends屬性。 !重寫原型切斷了現有原型與之前創建的所有對象實例的聯系,之前創建的對象實例的原型還在,只不過是舊的。

//創建person1時,原型對象還未被重寫,因此,原型對象中的constructor還是默認的Person()

console.log(person1.constructor);//Person()

//但是person2的constructor指向Object()

console.log(person2.constructor);//Object()需要注意的是,原型模式忽略了為構造函數傳遞參數的過程,所有的實例都取得相同的屬性值。同時,原型模式還存在著一個很大的問題,就是原型對象中的引用類型值會被所有實例共享,對引用類型值的修改,也會反映到所有對象實例當中。

function Person() {};Person.prototype = {  friends: ['ajiao','tiantian','pangzi']}var person1 = new Person();var person2 = new Person();person1.friends.push('laocai');console.log(person2.friends);//['ajiao','tiantian','pangzi','laocai']

修改person1的引用類型值friends,意味著person2中的friends也會發生變化,實際上,原型中保存的friends實際上只是一個指向堆中friends值的指針(這個指針的長度是固定的,保存在棧中),實例通過原型訪問引用類型值時,也是按指針訪問,而不是訪問各自實例上的副本(這樣的副本并不存在)。

1.1.4.結合構造函數和原型模式創建對象 [top]

結合構造函數和原型模式的優點,彌補各自的不足,利用構造函數傳遞初始化參數,在其中定義實例屬性,利用原型定義公用方法和公共屬性,該模式應用最為廣泛。

function Person(name,age) {  this.name = name;  this.age = age;  this.friends = ['ajiao','jianjian','pangzi'];}Person.prototype = {  constructor: Person,  logName: function() {    console.log(this.name);  }}var person1 = new Person('evansdiy','22');var person2 = new Person('amy','21');person1.logName();//'evansdiy'person1.friends.push('haixao');console.log(person2.friends.length);//3

1.1.5.原型動態模式 [top]

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

function Person(name,age) {  this.name = name;  this.age = age;  if(typeof this.logName != 'function') {    Person.prototype.logName = function() {      console.log(this.name);    };    Person.prototype.logAge = function() {      console.log(this.age);    };  };}var person1 = new Person('evansdiy','22');//初次調用構造函數,此時修改了原型var person2 = new Person('amy','21');//此時logName()方法已經存在,不會再修改原型

需要注意的是,該模式不能使用對象字面量語法書寫原型對象(這樣會重寫原型對象)。若重寫原型,那么通過構造函數創建的第一實例可以訪問的原型對象不會包含if語句中的原型對象屬性。

function Person(name,age) {  this.name = name;  this.age = age;  if(typeof this.logName != 'function') {    Person.prototype = {      logName: function() {        console.log(this.name);      },      logAge: function() {        console.log(this.Age);      }    }  };}var person1 = new Person('evansdiy','22');var person2 = new Person('amy','21');person2.logName();//'amy'person1.logName();//logName()方法不存在

需要說明的是,各模式都有自己的應用場景,無所謂優劣。

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产一区二区三区免费视频| 一区二区三区国产在线观看| 欧洲永久精品大片ww免费漫画| 国产精品人人做人人爽| 欧美麻豆久久久久久中文| 日韩免费观看视频| 色综合伊人色综合网站| 精品视频久久久久久| 亚洲人午夜精品免费| 亚洲理论在线a中文字幕| 精品一区电影国产| 日本精品一区二区三区在线| 一本色道久久88综合亚洲精品ⅰ| 日韩电影免费观看在线观看| 久久不射热爱视频精品| 国产精品一区久久| 亚洲电影免费观看高清完整版在线| 国产在线观看精品一区二区三区| 国产精品91久久| 亚洲视频欧洲视频| 精品美女国产在线| 久久91亚洲人成电影网站| 日韩精品中文在线观看| 国产一区二区三区在线视频| 日韩精品视频免费专区在线播放| 国产精品视频1区| 国产精品jizz在线观看麻豆| 久久久精品欧美| 91免费版网站入口| 国产精品久久视频| 日韩成人免费视频| 欧美专区在线观看| 九九精品视频在线观看| 国产日韩欧美夫妻视频在线观看| 精品中文字幕乱| 亚洲欧美精品伊人久久| 久久综合国产精品台湾中文娱乐网| 原创国产精品91| 97久久精品人人澡人人爽缅北| 国产一区二区欧美日韩| 欧美极品第一页| 国产亚洲欧洲黄色| 国产成人福利夜色影视| 成人网在线免费看| 伊人久久五月天| 91精品国产色综合久久不卡98| 国内精品视频在线| 欧美性生交xxxxxdddd| 97视频免费在线观看| 欧美黑人国产人伦爽爽爽| 日韩成人黄色av| 久久人人爽人人爽爽久久| 91久久精品国产| 日韩精品在线免费播放| 亚洲综合小说区| 国产精品香蕉在线观看| 日韩电影在线观看永久视频免费网站| 91精品久久久久久久久久入口| 中国china体内裑精亚洲片| 亚洲爱爱爱爱爱| 日本精品一区二区三区在线播放视频| 麻豆乱码国产一区二区三区| 久久青草福利网站| 不卡av电影在线观看| 亚洲精品资源在线| 在线观看欧美日韩国产| 亚洲综合第一页| 日韩av电影手机在线| 国产亚洲欧美一区| 午夜精品蜜臀一区二区三区免费| 亚洲精品一区在线观看香蕉| 亚洲精品福利资源站| 成人免费观看49www在线观看| 国产精品久久在线观看| 欧美精品激情在线观看| 国产精品99久久久久久www| 91精品国产高清自在线| 欧美日韩国产精品一区二区不卡中文| 国产一区二区三区毛片| 91高清免费视频| 亚洲男人天堂古典| 国产精品video| 91精品国产777在线观看| 91精品成人久久| 大胆欧美人体视频| 国产精品第2页| 亚洲综合在线做性| 久久精品在线播放| 中文一区二区视频| 日韩av片免费在线观看| 欧美大片在线看免费观看| 色综合五月天导航| 欧美日韩国产页| 国产经典一区二区| 亚洲欧美综合精品久久成人| 亚洲韩国日本中文字幕| 久久精品亚洲一区| 亚洲三级黄色在线观看| 日韩电影中文 亚洲精品乱码| 国产精品偷伦视频免费观看国产| 国产色婷婷国产综合在线理论片a| 亚洲最新视频在线| 91在线中文字幕| 久久精品视频播放| 国产精品电影网站| 最新91在线视频| 成人黄色大片在线免费观看| 国产精品成人一区二区三区吃奶| 海角国产乱辈乱精品视频| 亚洲成色www8888| 国内精品视频一区| 亚洲精品久久在线| 久久999免费视频| 69av成年福利视频| 精品亚洲一区二区三区在线观看| 日韩中文字幕视频在线观看| 成人羞羞国产免费| 2019中文字幕在线| 久久99热精品这里久久精品| 亚洲黄色www网站| 91亚洲精品视频| 中文字幕久久久av一区| 亚洲成人黄色网| 狠狠久久五月精品中文字幕| 日韩美女在线观看| 欧美成人一区二区三区电影| 日本高清久久天堂| 日韩欧美在线视频| 日韩精品亚洲精品| 欧美一区在线直播| 国产精品视频大全| 777精品视频| 国产精品免费福利| 国模精品系列视频| 久久亚洲国产成人| 国产亚洲精品激情久久| 91亚洲精品久久久久久久久久久久| 国产成人av网址| 亚洲美女精品久久| 91在线视频九色| 亚洲xxxx18| 亚洲男人7777| 奇门遁甲1982国语版免费观看高清| 欧美日韩久久久久| 国产精品在线看| 亚洲欧美日韩天堂一区二区| 亚洲电影免费观看高清完整版在线| 国产精品国产自产拍高清av水多| 国产精品亚洲片夜色在线| 亚洲区在线播放| 国产精品福利在线观看| 日韩三级影视基地| 国产在线拍揄自揄视频不卡99| 久久手机精品视频| 国产mv久久久| 欧美高清视频在线观看| 91精品免费视频| 亚洲精品美女免费| 亚洲精品白浆高清久久久久久| 在线精品高清中文字幕| 黄色成人在线播放| 久久成人综合视频| 26uuu日韩精品一区二区| 国产精品欧美风情|