這篇文章主要為大家展示了“JS面向?qū)ο蟮某绦蛟O(shè)計(jì)的示例分析”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“JS面向?qū)ο蟮某绦蛟O(shè)計(jì)的示例分析”這篇文章吧。
創(chuàng)新互聯(lián)建站是一家專注于網(wǎng)站設(shè)計(jì)、成都網(wǎng)站設(shè)計(jì)與策劃設(shè)計(jì),昂仁網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)建站做網(wǎng)站,專注于網(wǎng)站建設(shè)10余年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:昂仁等地區(qū)。昂仁做網(wǎng)站價(jià)格咨詢:18982081108
面向?qū)ο蟮恼Z言有一個(gè)標(biāo)志,即擁有類的概念,抽象實(shí)例對(duì)象的公共屬性與方法,基于類可以創(chuàng)建任意多個(gè)實(shí)例對(duì)象,一般具有封裝、繼承、多態(tài)的特性!但JS中對(duì)象與純面向?qū)ο笳Z言中的對(duì)象是不同的,ECMA標(biāo)準(zhǔn)定義JS中對(duì)象:無序?qū)傩缘募?,其屬性可以包含基本值、?duì)象或者函數(shù)。可以簡單理解為JS的對(duì)象是一組無序的值,其中的屬性或方法都有一個(gè)名字,根據(jù)這個(gè)名字可以訪問相映射的值(值可以是基本值/對(duì)象/方法)。
一、理解對(duì)象:
第一種:基于Object對(duì)象
var person = new Object(); person.name = 'My Name'; person.age = 18; person.getName = function(){ return this.name; }
第二種:對(duì)象字面量方式(比較清楚的查找對(duì)象包含的屬性及方法)
var person = { name : 'My name', age : 18, getName : function(){ return this.name; } }
JS的對(duì)象可以使用‘.'操作符動(dòng)態(tài)的擴(kuò)展其屬性,可以使用'delete'操作符或?qū)傩灾翟O(shè)置為'undefined'來刪除屬性。如下:
person.newAtt='new Attr';//添加屬性 alert(person.newAtt);//new Attr delete person.age; alert(person.age);//undefined(刪除屬性后值為undefined);
二、對(duì)象屬性類型
ECMA-262第5版定義了JS對(duì)象屬性中特征(用于JS引擎,外部無法直接訪問)。ECMAScript中有兩種屬性:數(shù)據(jù)屬性和訪問器屬性
1、數(shù)據(jù)屬性:
數(shù)據(jù)屬性指包含一個(gè)數(shù)據(jù)值的位置,可在該位置讀取或?qū)懭胫?,該屬性?個(gè)供述其行為的特性:
[[configurable]]:表示能否使用delete操作符刪除從而重新定義,或能否修改為訪問器屬性。默認(rèn)為true;
[[Enumberable]]:表示是否可通過for-in循環(huán)返回屬性。默認(rèn)true;
[[Writable]]:表示是否可修改屬性的值。默認(rèn)true;
[[Value]]:包含該屬性的數(shù)據(jù)值。讀取/寫入都是該值。默認(rèn)為undefined;如上面實(shí)例對(duì)象person中定義了name屬性,其值為'My name',對(duì)該值的修改都反正在這個(gè)位置
要修改對(duì)象屬性的默認(rèn)特征(默認(rèn)都為true),可調(diào)用Object.defineProperty()方法,它接收三個(gè)參數(shù):屬性所在對(duì)象,屬性名和一個(gè)描述符對(duì)象(必須是:configurable、enumberable、writable和value,可設(shè)置一個(gè)或多個(gè)值)。
如下:(瀏覽器支持:IE9+、Firefox 4+、Chrome、Safari5+)
var person = {}; Object.defineProperty(person, 'name', { configurable: false, writable: false, value: 'Jack' }); alert(person.name);//Jack delete person.name; person.name = 'lily'; alert(person.name);//Jack
可以看出,delete及重置person.name的值都沒有生效,這就是因?yàn)檎{(diào)用defineProperty函數(shù)修改了對(duì)象屬性的特征;值得注意的是一旦將configurable設(shè)置為false,則無法再使用defineProperty將其修改為true(執(zhí)行會(huì)報(bào)錯(cuò):can't redefine non-configurable property);
2、訪問器屬性:
它主要包括一對(duì)getter和setter函數(shù),在讀取訪問器屬性時(shí),會(huì)調(diào)用getter返回有效值;寫入訪問器屬性時(shí),調(diào)用setter,寫入新值;該屬性有以下4個(gè)特征:
[[Configurable]]:是否可通過delete操作符刪除重新定義屬性;
[[Numberable]]:是否可通過for-in循環(huán)查找該屬性;
[[Get]]:讀取屬性時(shí)調(diào)用,默認(rèn):undefined;
[[Set]]:寫入屬性時(shí)調(diào)用,默認(rèn):undefined;
訪問器屬性不能直接定義,必須使用defineProperty()來定義,如下:
var person = { _age: 18 }; Object.defineProperty(person, 'isAdult', { get: function () { if (this._age >= 18) { return true; } else { return false; } } }); alert(person.isAdult?'成年':'未成年');//成年
從上面可知,定義訪問器屬性時(shí)getter與setter函數(shù)不是必須的,并且,在定義getter與setter時(shí)不能指定屬性的configurable及writable特性;
此外,ECMA-262(5)還提供了一個(gè)Object.defineProperties()方法,可以用來一次性定義多個(gè)屬性的特性:
var person = {}; Object.defineProperties(person,{ _age:{ value:19 }, isAdult:{ get: function () { if (this._age >= 18) { return true; } else { return false; } } } }); alert(person.isAdult?'成年':'未成年');//成年
上述代碼使用Object.defineProperties()方法同時(shí)定義了_age及isAudlt兩個(gè)屬性的特性
此外,使用Object.getOwnPropertyDescriptor()方法可以取得給定屬性的特性:
var descriptor = Object.getOwnPropertyDescriptor(person,'_age'); alert(descriptor.value);//19
對(duì)于數(shù)據(jù)屬性,可以取得:configurable,enumberable,writable和value;
對(duì)于訪問器屬性,可以取得:configurable,enumberable,get和set
三、創(chuàng)建對(duì)象
使用Object構(gòu)造函數(shù)或?qū)ο笞置媪慷伎梢詣?chuàng)建對(duì)象,但缺點(diǎn)是創(chuàng)建多個(gè)對(duì)象時(shí),會(huì)產(chǎn)生大量的重復(fù)代碼,因此下面介紹可解決這個(gè)問題的創(chuàng)建對(duì)象的方法
1、工廠模式
function createPerson(name, age, job) { var o = new Object(); o.name = name; o.age = age; o.job = job; o.getName = function () { return this.name; } return o;//使用return返回生成的對(duì)象實(shí)例 } var person = createPerson('Jack', 19, 'SoftWare Engineer');
創(chuàng)建對(duì)象交給一個(gè)工廠方法來實(shí)現(xiàn),可以傳遞參數(shù),但主要缺點(diǎn)是無法識(shí)別對(duì)象類型,因?yàn)閯?chuàng)建對(duì)象都是使用Object的原生構(gòu)造函數(shù)來完成的。
2、構(gòu)造函數(shù)模式
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.getName = function () { return this.name; } } var person1 = new Person('Jack', 19, 'SoftWare Engineer'); var person2 = new Person('Liye', 23, 'Mechanical Engineer');
使用自定義的構(gòu)造函數(shù)(與普通函數(shù)一樣,只是用它來創(chuàng)建對(duì)象),定義對(duì)象類型(如:Person)的屬性和方法。它與工廠方法區(qū)別在于:
沒有顯式地創(chuàng)建對(duì)象
直接將屬性和方法賦值給this對(duì)象;
沒有return語句;
此外,要?jiǎng)?chuàng)建Person的實(shí)例,必須使用new關(guān)鍵字,以Person函數(shù)為構(gòu)造函數(shù),傳遞參數(shù)完成對(duì)象創(chuàng)建;實(shí)際創(chuàng)建經(jīng)過以下4個(gè)過程:
創(chuàng)建一個(gè)對(duì)象
將函數(shù)的作用域賦給新對(duì)象(因此this指向這個(gè)新對(duì)象,如:person1)
執(zhí)行構(gòu)造函數(shù)的代碼
返回該對(duì)象
上述由Person構(gòu)造函數(shù)生成的兩個(gè)對(duì)象person1與person2都是Person的實(shí)例,因此可以使用instanceof判斷,并且因?yàn)樗袑?duì)象都繼承Object,因此person1 instanceof Object也返回真:
alert(person1 instanceof Person);//true; alert(person2 instanceof Person);//true; alert(person1 instanceof Object);//true; alert(person1.constructor === person2.constructor);//ture;
雖然構(gòu)造函數(shù)方式比較不錯(cuò),但也存在缺點(diǎn),那就是在創(chuàng)建對(duì)象時(shí),特別針對(duì)對(duì)象的屬性指向函數(shù)時(shí),會(huì)重復(fù)的創(chuàng)建函數(shù)實(shí)例,以上述代碼為基礎(chǔ),可以改寫為:
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.getName = new Function () {//改寫后效果與原代碼相同,不過是為了方便理解 return this.name; } }
上述代碼,創(chuàng)建多個(gè)實(shí)例時(shí),會(huì)重復(fù)調(diào)用new Function();創(chuàng)建多個(gè)函數(shù)實(shí)例,這些函數(shù)實(shí)例還不是一個(gè)作用域中,當(dāng)然這一般不會(huì)有錯(cuò),但這會(huì)造成內(nèi)存浪費(fèi)。當(dāng)然,可以在函數(shù)中定義一個(gè)getName = getName的引用,而getName函數(shù)在Person外定義,這樣可以解決重復(fù)創(chuàng)建函數(shù)實(shí)例問題,但在效果上并沒有起到封裝的效果,如下所示:
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.getName = getName; } function getName() {//到處是代碼,看著亂??! return this.name; }
3、原型模式
JS每個(gè)函數(shù)都有一個(gè)prototype(原型)屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)對(duì)象,它是所有通過new操作符使用函數(shù)創(chuàng)建的實(shí)例的原型對(duì)象。原型對(duì)象最大特點(diǎn)是,所有對(duì)象實(shí)例共享它所包含的屬性和方法,也就是說,所有在原型對(duì)象中創(chuàng)建的屬性或方法都直接被所有對(duì)象實(shí)例共享。
function Person(){ } Person.prototype.name = 'Jack';//使用原型來添加屬性 Person.prototype.age = 29; Person.prototype.getName = function(){ return this.name; } var person1 = new Person(); alert(person1.getName());//Jack var person2 = new Person(); alert(person1.getName === person2.getName);//true;共享一個(gè)原型對(duì)象的方法
原型是指向原型對(duì)象的,這個(gè)原型對(duì)象與構(gòu)造函數(shù)沒有太大關(guān)系,唯一的關(guān)系是函數(shù)的prototype是指向這個(gè)原型對(duì)象!而基于構(gòu)造函數(shù)創(chuàng)建的對(duì)象實(shí)例也包含一個(gè)內(nèi)部指針為:[[prototype]]指向原型對(duì)象。
實(shí)例屬性或方法的訪問過程是一次搜索過程:
首先從對(duì)象實(shí)例本身開始,如果找到屬性就直接返回該屬性值;
如果實(shí)例本身不存在要查找屬性,就繼續(xù)搜索指針指向的原型對(duì)象,在其中查找給定名字的屬性,如果有就返回;
基于以上分析,原型模式創(chuàng)建的對(duì)象實(shí)例,其屬性是共享原型對(duì)象的;但也可以自己實(shí)例中再進(jìn)行定義,在查找時(shí),就不從原型對(duì)象獲取,而是根據(jù)搜索原則,得到本實(shí)例的返回;簡單來說,就是實(shí)例中屬性會(huì)屏蔽原型對(duì)象中的屬性;
原型與in操作符
一句話:無論原型中屬性,還是對(duì)象實(shí)例的屬性,都可以使用in操作符訪問到;要想判斷是否是實(shí)例本身的屬性可以使用object.hasOwnProperty(‘a(chǎn)ttr')來判斷;
原生對(duì)象中原型
原生對(duì)象中原型與普通對(duì)象的原型一樣,可以添加/修改屬性或方法,如以下代碼為所有字符串對(duì)象添加去左右空白原型方法:
String.prototype.trim = function(){ return this.replace(/^\s+/,'').replace(/\s+$/,''); } var str = ' word space '; alert('!'+str.trim()+'!');//!word space!
原型模式的缺點(diǎn),它省略了為構(gòu)造函數(shù)傳遞初始化參數(shù),這在一定程序帶來不便;另外,最主要是當(dāng)對(duì)象的屬性是引用類型時(shí),它的值是不變的,總是引用同一個(gè)外部對(duì)象,所有實(shí)例對(duì)該對(duì)象的操作都會(huì)其它實(shí)例:
function Person() { } Person.prototype.name = 'Jack'; Person.prototype.lessons = ['Math','Physics']; var person1 = new Person(); person1.lessons.push('Biology'); var person2 = new Person(); alert(person2.lessons);//Math,Physics,Biology,person1修改影響了person2
4、組合構(gòu)造函數(shù)及原型模式
目前最為常用的定義類型方式,是組合構(gòu)造函數(shù)模式與原型模式。構(gòu)造函數(shù)模式用于定義實(shí)例的屬性,而原型模式用于定義方法和共享的屬性。結(jié)果,每個(gè)實(shí)例都會(huì)有自己的一份實(shí)例屬性的副本,但同時(shí)又共享著對(duì)方方法的引用,最大限度的節(jié)約內(nèi)存。此外,組合模式還支持向構(gòu)造函數(shù)傳遞參數(shù),可謂是集兩家之所長。
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.lessons = ['Math', 'Physics']; } Person.prototype = { constructor: Person,//原型字面量方式會(huì)將對(duì)象的constructor變?yōu)镺bject,此外強(qiáng)制指回Person getName: function () { return this.name; } } var person1 = new Person('Jack', 19, 'SoftWare Engneer'); person1.lessons.push('Biology'); var person2 = new Person('Lily', 39, 'Mechanical Engneer'); alert(person1.lessons);//Math,Physics,Biology alert(person2.lessons);//Math,Physics alert(person1.getName === person2.getName);//true,//共享原型中定義方法
在所接觸的JS庫中,jQuery類型的封裝就是使用組合模式來實(shí)例的?。。?/p>
5、動(dòng)態(tài)原型模式
組合模式中實(shí)例屬性與共享方法(由原型定義)是分離的,這與純面向?qū)ο笳Z言不太一致;動(dòng)態(tài)原型模式將所有構(gòu)造信息都封裝在構(gòu)造函數(shù)中,又保持了組合的優(yōu)點(diǎn)。其原理就是通過判斷構(gòu)造函數(shù)的原型中是否已經(jīng)定義了共享的方法或?qū)傩?,如果沒有則定義,否則不再執(zhí)行定義過程。該方式只原型上方法或?qū)傩灾欢x一次,且將所有構(gòu)造過程都封裝在構(gòu)造函數(shù)中,對(duì)原型所做的修改能立即體現(xiàn)所有實(shí)例中:
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.lessons = ['Math', 'Physics']; } if (typeof this.getName != 'function') {//通過判斷實(shí)例封裝 Person.prototype = { constructor: Person,//原型字面量方式會(huì)將對(duì)象的constructor變?yōu)镺bject,此外強(qiáng)制指回Person getName: function () { return this.name; } } } var person1 = new Person('Jack', 19, 'SoftWare Engneer'); person1.lessons.push('Biology'); var person2 = new Person('Lily', 39, 'Mechanical Engneer'); alert(person1.lessons);//Math,Physics,Biology alert(person2.lessons);//Math,Physics alert(person1.getName === person2.getName);//true,//共享原型中定義方法
以上是“JS面向?qū)ο蟮某绦蛟O(shè)計(jì)的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
本文標(biāo)題:JS面向?qū)ο蟮某绦蛟O(shè)計(jì)的示例分析
網(wǎng)頁鏈接:http://aaarwkj.com/article34/gihepe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)、品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站營銷、網(wǎng)站維護(hù)、網(wǎng)站策劃、網(wǎng)站改版
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)