js中創(chuàng)建對象的幾種方式
前言
不管是哪門語言,千變?nèi)f化不離其宗,深入理解其本質(zhì),方能應(yīng)用自如。對應(yīng)到j(luò)s,閉包,原型,函數(shù),對象等是需要花費大功夫思考、理解的。本文穿插了js原型和函數(shù)的相關(guān)知識,討論了批量創(chuàng)建對象的幾種方式以及它們的優(yōu)缺點。
正文
說起創(chuàng)建對象,最容易想到的便是通過對象字面量方式直接定義一個對象吧,但這種方式只能創(chuàng)建少量,單獨且相互間無聯(lián)系的對象。若要批量創(chuàng)建對象,該如何?
工廠模式
工廠模式非常直觀,將創(chuàng)建對象的過程抽象為一個函數(shù),用函數(shù)封裝以特定接口創(chuàng)建對象的細(xì)節(jié)。如下所示:
function createStudent(name,sex,grade){ var o = new Object(); o.name = name; o.sex = sex; o.grade = grade; o.sayName = function(){ console.log(this.name); } return o; } var s1 = createStudent('Claiyre','famale',1);
通俗地講,工廠模式就是將創(chuàng)建對象的語句放在一個函數(shù)里,通過傳入?yún)?shù)來創(chuàng)建特定對象,最后返回創(chuàng)建的對象。
工廠模式雖然可以創(chuàng)建多個相似的對象,但卻不能解決對象標(biāo)識的問題,即怎樣知道一個對象的類型。構(gòu)造函數(shù)模式應(yīng)運而生。
構(gòu)造函數(shù)模式
構(gòu)造函數(shù)模式是java語言創(chuàng)建對象的通用方式。兩種語言用構(gòu)造函數(shù)創(chuàng)建對象的方式略有不同,注意區(qū)別。
在JavaScript中沒有類的概念,函數(shù)即為一等公民,因此,不必顯式聲明某個類,直接創(chuàng)建構(gòu)造函數(shù)即可,類的方法和屬性在構(gòu)造函數(shù)中(或原型對象上)處理。構(gòu)造函數(shù)模式的示例代碼如下:
function Student(name,sex,grade){ this.name = name; this.sex = sex; this.grade = grade; this.sayName = function(){ console.log(this.name); } } var s2 = new Student('孫悟空','male',2);
細(xì)心的朋友一定發(fā)現(xiàn)了構(gòu)造函數(shù)的函數(shù)名首字母是大寫的,而普通函數(shù)首字母則是小寫,這是眾多OO語言約定俗成的規(guī)定,雖然大多數(shù)情況下不大寫也不會報錯,但是為了代碼的規(guī)范性和可讀性,還是應(yīng)該將構(gòu)造函數(shù)的首字母大寫,與普通函數(shù)區(qū)別開。
與工廠模式相比,用構(gòu)造模式創(chuàng)建對象有以下幾點不同:
- 沒有顯示地創(chuàng)建對象
- 直接將屬性和方法賦給this對象
- 沒有return語句
此外,還應(yīng)注意到要創(chuàng)建Student的實例,必須要使用new操作符,創(chuàng)建的實例對象將有一個constructor(構(gòu)造器)屬性,指向Person構(gòu)造函數(shù)。調(diào)用構(gòu)造函數(shù)創(chuàng)建對象經(jīng)過了以下幾個過程:
- 創(chuàng)建一個新對象
- 將構(gòu)造函數(shù)的作用域賦給新對象(因此this就指向了這個新對象)
- 執(zhí)行構(gòu)造函數(shù)中的代碼
- 返回新對象(不需要顯式返回)
構(gòu)造函數(shù)雖好用,但也不是沒有缺點。使用構(gòu)造函數(shù)的主要問題是:每個方法都要在每個實例上創(chuàng)建一遍。在ECMAScript中,函數(shù)即對象,因此每定義一個函數(shù),也就是實例化了一個對象。下面的例子證明了這個缺點。
var s3 = new Student('唐僧','male',3); var s4 = new Student('白骨精','female',4); s3.sayName(); s4.sayName(); console.log(s3.sayName == s4.sayName);
運行結(jié)果:
也就是說通過構(gòu)造函數(shù)實例化的多個對象的方法,是多個不同的方法,但它們內(nèi)部的代碼以及實現(xiàn)的功能是相同的,這就造成了一定的資源浪費。
幸運的是,這個問題可以用原型模式來解決。
原型模式
js中,每個函數(shù)都有一個prototype屬性,它是一個指針,指向一個對象,叫做原型對象,原型對象包含了可以由特定類型的所有實例對象共享的屬性和方法。此外,這個對象有一個與生自來的屬性constructor,指向創(chuàng)建對象的構(gòu)造方法。
使用原型模式可以讓所有的實例共享原型對象中的屬性和方法,也就是說,不必再構(gòu)造函數(shù)中定義對象實例的信息。用代碼表示如下:
function Student_1(){ } Student_1.prototype.name = 'Claiyre'; Student_1.prototype.sex = 'female'; Student_1.prototype.class = 5; Student_1.prototype.sayName = function (){ console.log(this.name); } var s5 = new Student_1(); s5.sayName(); //Claiyre var s6 = new Student_1(); s6.sayName(); //Claiyre
一張圖勝過千言萬語,下圖清楚地闡釋了各個對象和原型對象間的關(guān)系:
了解過原型后,可以繼續(xù)在實例對象上增添屬性或方法:
s6.name = 'John'; s6.sayName(); //John
當(dāng)要讀取某個對象的屬性時,都會執(zhí)行一次搜索,搜索首先從對象實例本身開始,如果在實例中找到了這個屬性,則搜索結(jié)束,返回實例屬性的值;若實例上沒有找到,則繼續(xù)向?qū)ο蟮脑蛯ο笱由欤阉鲗ο蟮脑蛯ο?,若在原型對象上找到了,則返回原型上相應(yīng)屬性的值,若沒有找到,則返回undefined。因此,實例對象屬性會覆蓋原型對象上的同名屬性,所以上面第二行代碼輸出的是John。
- Object.getPrototypeOf(object)方法返回參數(shù)對象的原型對象。
- Object.keys(object)方法返回對象上課枚舉的實例屬性。
原型中的所有屬性都是被所有實例所共享的,這種共享對于函數(shù)來說非常合適,對于包含基本值的屬性也說的過去(實例屬性會覆蓋原型同名屬性),但對于那些包含引用類型的屬性,可有大麻煩了
Student_1.prototype.friends = ['aa','bb']; console.log('s6的朋友' + s6.friends); s5.friends.push('cc'); console.log('s5的朋友' + s5.friends); console.log('s6的朋友' + s6.friends);
運行結(jié)果:
問題來了,我們只想改變s5的朋友列表,但由于原型模式的共享本質(zhì),s6的朋友列表也隨之改變了。
因此,很少單獨使用原型模式。
組合使用構(gòu)造函數(shù)和原型模式
構(gòu)造函數(shù)模式用于定義實例屬性,原型模式則用于定義方法和共享的屬性。這種混合模式不僅支持向構(gòu)造函數(shù)傳入?yún)?shù),還最大限度地節(jié)約了內(nèi)存,可謂是集兩模式之長。示例代碼如下:
function Student(name,sex,grade){ this.name = name; this.sex = sex; this.grade = grade; } Student.prototype.sayName = function(){ console.log(this.name); } Student.prototype.school = 'Joooh school';
其他模式
除了以上幾種常見的模式外,批量創(chuàng)建對象的方式還有
- 動態(tài)原型模式:僅在第一次調(diào)用構(gòu)造函數(shù)時,將方法賦給原型對象的相應(yīng)屬性,其他示例的處理方式同構(gòu)造函數(shù)模式
- 寄生構(gòu)造函數(shù)模式:僅僅封裝創(chuàng)建對象的代碼,然后再返回新創(chuàng)建的對象,仍使用new操作符調(diào)用
- 穩(wěn)妥構(gòu)造函數(shù)模式:沒有公共屬性,只有私有變量和方法,以及一些get/set方法,用以處理私有變量。
結(jié)語
每種模式都有各自的優(yōu)缺點,具體要使用哪種,還需結(jié)合實際場景,深入理解,靈活運用。
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!
相關(guān)文章
js實現(xiàn)隨機(jī)點名系統(tǒng)(實例講解)
下面小編就為大家?guī)硪黄猨s實現(xiàn)隨機(jī)點名系統(tǒng)(實例講解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10js 按照指定間隔 向字符串中插入隨機(jī)字符串的實現(xiàn)代碼
看到論壇有人問,覺得有意思,就試著寫了一下。2010-03-03javascript實現(xiàn)簡單的html5視頻播放器
網(wǎng)頁視頻音頻播放器大家并不陌生,在IE中我們可以運行ActiveX來嵌入微軟的Media Player或者其他的本地播放器,當(dāng)然可能大部分我們都是使用Flash來制作播放器。在HTML5發(fā)展迅速的今天,讓我們嘗試用HTML5來制作網(wǎng)頁播放器吧,畢竟無論是PC還是移動設(shè)備,HTML5是未來的趨勢2015-05-05改變文件域的樣式實現(xiàn)思路同時兼容ie、firefox
正如標(biāo)題所言只是模擬了file文件域的外觀,其實起作用的還是文件域file,這樣就很方便,感興趣的朋友可以了解下2013-10-10Echarts基本用法_動力節(jié)點Java學(xué)院整理
這篇文章主要介紹了Echarts基本用法,詳解的介紹了Echarts的基本用法和實例,有興趣的可以了解一下2017-08-08JavaScript中統(tǒng)計Textarea字?jǐn)?shù)并提示還能輸入的字符
是在文本框中輸入文字的時候,會自動統(tǒng)計輸入的字符,并顯示用戶還能輸入的字符,其實js也可以實現(xiàn),下面就以示例的方式為大家講解下2014-06-06