構(gòu)造函數(shù)與 new 命令

一 對(duì)象的概念

“面向?qū)ο缶幊獭保∣bject Oriented Programming这敬,縮寫為OOP)是目前主流的編程范式。它的核心思想是將真實(shí)世界中各種復(fù)雜的關(guān)系媳叨,抽象為一個(gè)個(gè)對(duì)象腥光,然后由對(duì)象之間的分工與合作关顷,完成對(duì)真實(shí)世界的模擬。

傳統(tǒng)的過程式編程(procedural programming)由一系列函數(shù)或一系列指令組成武福,而面向?qū)ο缶幊痰某绦蛴梢幌盗袑?duì)象組成议双。每一個(gè)對(duì)象都是功能中心,具有明確分工捉片,可以完成接受信息平痰、處理數(shù)據(jù)、發(fā)出信息等任務(wù)伍纫。因此宗雇,面向?qū)ο缶幊叹哂徐`活性、代碼的可重用性莹规、模塊性等特點(diǎn)赔蒲,容易維護(hù)和開發(fā),非常適合多人合作的大型軟件項(xiàng)目良漱。

那么嘹履,“對(duì)象”(object)到底是什么?

我們從兩個(gè)層次來理解债热。

(1)“對(duì)象”是單個(gè)實(shí)物的抽象砾嫉。

一本書、一輛汽車窒篱、一個(gè)人都可以是“對(duì)象”焕刮,一個(gè)數(shù)據(jù)庫、一張網(wǎng)頁墙杯、一個(gè)與遠(yuǎn)程服務(wù)器的連接也可以是“對(duì)象”配并。當(dāng)實(shí)物被抽象成“對(duì)象”,實(shí)物之間的關(guān)系就變成了“對(duì)象”之間的關(guān)系高镐,從而就可以模擬現(xiàn)實(shí)情況溉旋,針對(duì)“對(duì)象”進(jìn)行編程。

(2)“對(duì)象”是一個(gè)容器嫉髓,封裝了“屬性”(property)和“方法”(method)观腊。

所謂“屬性”,就是對(duì)象的狀態(tài)算行;所謂“方法”梧油,就是對(duì)象的行為(完成某種任務(wù))。比如州邢,我們可以把動(dòng)物抽象為animal對(duì)象儡陨,“屬性”記錄具體是那一種動(dòng)物,“方法”表示動(dòng)物的某種行為(奔跑、捕獵骗村、休息等等)嫌褪。

二 構(gòu)造函數(shù)

“面向?qū)ο缶幊獭钡牡谝徊剑褪且伞皩?duì)象”胚股。

前面說過渔扎,“對(duì)象”是單個(gè)實(shí)物的抽象。通常需要一個(gè)模板信轿,表示某一類實(shí)物的共同特征晃痴,然后“對(duì)象”根據(jù)這個(gè)模板生成。

典型的面向?qū)ο缶幊陶Z言(比如 C++ 和 Java)财忽,存在“類”(class)這個(gè)概念倘核。所謂“類”就是對(duì)象的模板,對(duì)象就是“類”的實(shí)例即彪。但是紧唱,JavaScript語言的對(duì)象體系,不是基于“類”的隶校,而是基于構(gòu)造函數(shù)(constructor)和原型鏈(prototype)漏益。

JavaScript語言使用構(gòu)造函數(shù)(constructor)作為對(duì)象的模板。所謂“構(gòu)造函數(shù)”深胳,就是專門用來生成“對(duì)象”的函數(shù)绰疤。它提供模板,描述對(duì)象的基本結(jié)構(gòu)舞终。一個(gè)構(gòu)造函數(shù)轻庆,可以生成多個(gè)對(duì)象,這些對(duì)象都有相同的結(jié)構(gòu)敛劝。

構(gòu)造函數(shù)的寫法就是一個(gè)普通的函數(shù)余爆,但是有自己的特征和用法。

var Vehicle=function(){

this.price=1000;

};

上面代碼中夸盟,Vehicle就是構(gòu)造函數(shù)蛾方,它提供模板,用來生成對(duì)象實(shí)例上陕。為了與普通函數(shù)區(qū)別桩砰,構(gòu)造函數(shù)名字的第一個(gè)字母通常大寫。

構(gòu)造函數(shù)的特點(diǎn)有兩個(gè)唆垃。

三 new 命令

基本用法

new命令的作用五芝,就是執(zhí)行構(gòu)造函數(shù),返回一個(gè)實(shí)例對(duì)象辕万。

varVehicle=function(){this.price=1000;};varv=newVehicle();v.price// 1000

上面代碼通過new命令,讓構(gòu)造函數(shù)Vehicle生成一個(gè)實(shí)例對(duì)象,保存在變量v中渐尿。這個(gè)新生成的實(shí)例對(duì)象醉途,從構(gòu)造函數(shù)Vehicle繼承了price屬性。在new命令執(zhí)行時(shí)砖茸,構(gòu)造函數(shù)內(nèi)部的this隘擎,就代表了新生成的實(shí)例對(duì)象,this.price表示實(shí)例對(duì)象有一個(gè)price屬性凉夯,它的值是1000货葬。

使用new命令時(shí),根據(jù)需要劲够,構(gòu)造函數(shù)也可以接受參數(shù)震桶。

varVehicle=function(p){this.price=p;};varv=newVehicle(500);

new命令本身就可以執(zhí)行構(gòu)造函數(shù),所以后面的構(gòu)造函數(shù)可以帶括號(hào)征绎,也可以不帶括號(hào)蹲姐。下面兩行代碼是等價(jià)的。

varv=newVehicle();varv=newVehicle;

一個(gè)很自然的問題是人柿,如果忘了使用new命令柴墩,直接調(diào)用構(gòu)造函數(shù)會(huì)發(fā)生什么事?

這種情況下凫岖,構(gòu)造函數(shù)就變成了普通函數(shù)江咳,并不會(huì)生成實(shí)例對(duì)象。而且由于后面會(huì)說到的原因哥放,this這時(shí)代表全局對(duì)象扎阶,將造成一些意想不到的結(jié)果。

varVehicle=function(){this.price=1000;};varv=Vehicle();v.price// Uncaught TypeError: Cannot read property 'price' of undefinedprice// 1000

上面代碼中婶芭,調(diào)用Vehicle構(gòu)造函數(shù)時(shí)东臀,忘了加上new命令。結(jié)果犀农,price屬性變成了全局變量惰赋,而變量v變成了undefined。

因此呵哨,應(yīng)該非常小心赁濒,避免出現(xiàn)不使用new命令、直接調(diào)用構(gòu)造函數(shù)的情況孟害。為了保證構(gòu)造函數(shù)必須與new命令一起使用拒炎,一個(gè)解決辦法是,在構(gòu)造函數(shù)內(nèi)部使用嚴(yán)格模式挨务,即第一行加上use strict击你。

functionFubar(foo,bar){'use strict';this._foo=foo;this._bar=bar;}Fubar()// TypeError: Cannot set property '_foo' of undefined

上面代碼的Fubar為構(gòu)造函數(shù)玉组,use strict命令保證了該函數(shù)在嚴(yán)格模式下運(yùn)行。由于在嚴(yán)格模式中丁侄,函數(shù)內(nèi)部的this不能指向全局對(duì)象惯雳,默認(rèn)等于undefined,導(dǎo)致不加new調(diào)用會(huì)報(bào)錯(cuò)(JavaScript不允許對(duì)undefined添加屬性)鸿摇。

另一個(gè)解決辦法石景,是在構(gòu)造函數(shù)內(nèi)部判斷是否使用new命令,如果發(fā)現(xiàn)沒有使用拙吉,則直接返回一個(gè)實(shí)例對(duì)象潮孽。

functionFubar(foo,bar){if(!(thisinstanceofFubar)){returnnewFubar(foo,bar);}this._foo=foo;this._bar=bar;}Fubar(1,2)._foo// 1(newFubar(1,2))._foo// 1

上面代碼中的構(gòu)造函數(shù),不管加不加new命令筷黔,都會(huì)得到同樣的結(jié)果往史。

new命令的原理

使用new命令時(shí),它后面的函數(shù)調(diào)用就不是正常的調(diào)用必逆,而是依次執(zhí)行下面的步驟怠堪。

創(chuàng)建一個(gè)空對(duì)象,作為將要返回的對(duì)象實(shí)例

將這個(gè)空對(duì)象的原型名眉,指向構(gòu)造函數(shù)的prototype屬性

將這個(gè)空對(duì)象賦值給函數(shù)內(nèi)部的this關(guān)鍵字

開始執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼

也就是說粟矿,構(gòu)造函數(shù)內(nèi)部,this指的是一個(gè)新生成的空對(duì)象损拢,所有針對(duì)this的操作陌粹,都會(huì)發(fā)生在這個(gè)空對(duì)象上。構(gòu)造函數(shù)之所以叫“構(gòu)造函數(shù)”福压,就是說這個(gè)函數(shù)的目的掏秩,就是操作一個(gè)空對(duì)象(即this對(duì)象),將其“構(gòu)造”為需要的樣子荆姆。

如果構(gòu)造函數(shù)內(nèi)部有return語句蒙幻,而且return后面跟著一個(gè)對(duì)象,new命令會(huì)返回return語句指定的對(duì)象胆筒;否則邮破,就會(huì)不管return語句,返回this對(duì)象仆救。

varVehicle=function(){this.price=1000;return1000;};(newVehicle())===1000// false

上面代碼中抒和,構(gòu)造函數(shù)Vehicle的return語句返回一個(gè)數(shù)值。這時(shí)彤蔽,new命令就會(huì)忽略這個(gè)return語句摧莽,返回“構(gòu)造”后的this對(duì)象。

但是顿痪,如果return語句返回的是一個(gè)跟this無關(guān)的新對(duì)象镊辕,new命令會(huì)返回這個(gè)新對(duì)象油够,而不是this對(duì)象。這一點(diǎn)需要特別引起注意丑蛤。

varVehicle=function(){this.price=1000;return{price:2000};};(newVehicle()).price// 2000

上面代碼中叠聋,構(gòu)造函數(shù)Vehicle的return語句撕阎,返回的是一個(gè)新對(duì)象受裹。new命令會(huì)返回這個(gè)對(duì)象,而不是this對(duì)象虏束。

另一方面棉饶,如果對(duì)普通函數(shù)(內(nèi)部沒有this關(guān)鍵字的函數(shù))使用new命令,則會(huì)返回一個(gè)空對(duì)象镇匀。

functiongetMessage(){return'this is a message';}varmsg=newgetMessage();msg// {}typeofmsg// "Object"

上面代碼中照藻,getMessage是一個(gè)普通函數(shù),返回一個(gè)字符串汗侵。對(duì)它使用new命令幸缕,會(huì)得到一個(gè)空對(duì)象。這是因?yàn)閚ew命令總是返回一個(gè)對(duì)象晰韵,要么是實(shí)例對(duì)象发乔,要么是return語句指定的對(duì)象。本例中雪猪,return語句返回的是字符串栏尚,所以new命令就忽略了該語句。

new命令簡化的內(nèi)部流程只恨,可以用下面的代碼表示译仗。

function_new(/* 構(gòu)造函數(shù) */constructor,/* 構(gòu)造函數(shù)參數(shù) */param1){// 將 arguments 對(duì)象轉(zhuǎn)為數(shù)組varargs=[].slice.call(arguments);// 取出構(gòu)造函數(shù)varconstructor=args.shift();// 創(chuàng)建一個(gè)空對(duì)象,繼承構(gòu)造函數(shù)的 prototype 屬性varcontext=Object.create(constructor.prototype);// 執(zhí)行構(gòu)造函數(shù)varresult=constructor.apply(context,args);// 如果返回結(jié)果是對(duì)象官觅,就直接返回纵菌,則返回 context 對(duì)象return(typeofresult==='object'&&result!=null)?result:context;}// 實(shí)例varactor=_new(Person,'張三',28);

new.target

函數(shù)內(nèi)部可以使用new.target屬性。如果當(dāng)前函數(shù)是new命令調(diào)用休涤,new.target指向當(dāng)前函數(shù)咱圆,否則為undefined。

functionf(){console.log(new.target===f);}f()// falsenewf()// true

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末滑绒,一起剝皮案震驚了整個(gè)濱河市闷堡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疑故,老刑警劉巖杠览,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異纵势,居然都是意外死亡踱阿,警方通過查閱死者的電腦和手機(jī)管钳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來软舌,“玉大人才漆,你說我怎么就攤上這事》鸬悖” “怎么了醇滥?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長超营。 經(jīng)常有香客問我鸳玩,道長,這世上最難降的妖魔是什么演闭? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任不跟,我火速辦了婚禮,結(jié)果婚禮上米碰,老公的妹妹穿的比我還像新娘窝革。我一直安慰自己,他們只是感情好吕座,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布虐译。 她就那樣靜靜地躺著,像睡著了一般米诉。 火紅的嫁衣襯著肌膚如雪菱蔬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天史侣,我揣著相機(jī)與錄音拴泌,去河邊找鬼。 笑死惊橱,一個(gè)胖子當(dāng)著我的面吹牛蚪腐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播税朴,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼回季,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了正林?” 一聲冷哼從身側(cè)響起泡一,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎觅廓,沒想到半個(gè)月后鼻忠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杈绸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年帖蔓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了矮瘟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡塑娇,死狀恐怖澈侠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情埋酬,我是刑警寧澤哨啃,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站奇瘦,受9級(jí)特大地震影響棘催,放射性物質(zhì)發(fā)生泄漏劲弦。R本人自食惡果不足惜耳标,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望邑跪。 院中可真熱鬧次坡,春花似錦、人聲如沸画畅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轴踱。三九已至症脂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間淫僻,已是汗流浹背诱篷。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留雳灵,地道東北人棕所。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像悯辙,于是被迫代替她去往敵國和親琳省。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前言 典型的面向?qū)ο缶幊陶Z言(比如C++和Java)躲撰,存在“類”(class)這個(gè)概念针贬。所謂“類”就是對(duì)象的模板,...
    我是王小一閱讀 761評(píng)論 1 5
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理拢蛋,服務(wù)發(fā)現(xiàn)桦他,斷路器,智...
    卡卡羅2017閱讀 134,659評(píng)論 18 139
  • 集裝箱生活區(qū)內(nèi)瓤狐,逼仄的住所瞬铸,干旱的環(huán)境批幌,寒冷的氣候,也磨滅不了人的精神嗓节。 轉(zhuǎn)動(dòng)的風(fēng)車是生活的色彩荧缘,是積極向上的精神...
    湖大最可愛的人閱讀 797評(píng)論 0 0
  • 今早,快到公司時(shí)拦宣,卻恰恰被堵了截粗。車停著,透過窗鸵隧,一位五六十歲的老人從左邊進(jìn)入了我的視線绸罗。 老人衣著樸素,神態(tài)平和豆瘫。...
    皆無罷了閱讀 361評(píng)論 1 0
  • 深藍(lán)色的毛呢珊蟀,有著內(nèi)涵、廣闊外驱、深邃的含義育灸,這一季時(shí)尚色彩,穩(wěn)重又顯時(shí)尚昵宇,沉靜又融合優(yōu)雅磅崭。 立領(lǐng)是順應(yīng)發(fā)展要求出現(xiàn)的...
    宮澤恩惠閱讀 547評(píng)論 0 0