摘要:有一函數(shù)若是用來(lái)生成對(duì)象,則稱為構(gòu)造函數(shù)名。屬性指定了使用該構(gòu)造函數(shù)生成的對(duì)象實(shí)例繼承了哪個(gè)對(duì)象實(shí)例。因此,只要利用,就能在構(gòu)造函數(shù)中,為未來(lái)利用此構(gòu)造函數(shù)生成的對(duì)象實(shí)例,添加成員屬性和成員方法了。
與其它編程語(yǔ)言不一樣的是,javascript的面向?qū)ο蟛⒎且蕾囉诔橄蟮?strong>類,而是通過原型鏈,將一個(gè)個(gè)具體的對(duì)象實(shí)例進(jìn)行連接,位于原型鏈下游的對(duì)象實(shí)例可以讀取/使用位于上游的對(duì)象實(shí)例的屬性/方法。
下文由簡(jiǎn)及深,試圖一步步理清javascript面向?qū)ο蟮谋举|(zhì)。
javascript定義了最基礎(chǔ)的對(duì)象類型Object,并且為這一對(duì)象類型定義了許多成員方法。其它許多原生對(duì)象類型,實(shí)際上都是繼承自Object,比如說(shuō)Function、Date等。想要生成一個(gè)Object對(duì)象類型的對(duì)象實(shí)例也不是一件什么難事:
var obj = {a: 2333}; //又或者是利用Object()這一構(gòu)造函數(shù) var obj = new Object();
實(shí)際上,更符合面向?qū)ο笏枷氲膽?yīng)該是利用構(gòu)造函數(shù)來(lái)生成對(duì)象實(shí)例。
生成對(duì)象實(shí)例的運(yùn)算符new,以及構(gòu)造函數(shù)constructor 如何使用new這一運(yùn)算符來(lái)生成對(duì)象實(shí)例在其它編程語(yǔ)言中,new往往也是用來(lái)生成對(duì)象實(shí)例的,用法一般是這樣:new ClassName[([arguments])],而生成出來(lái)的對(duì)象實(shí)例也被冠以“ClassName對(duì)象”這樣的稱謂;而javascript則大不相同,由于原生沒有類這一概念,因此構(gòu)造函數(shù)便取而代之:new constructor[([arguments])],而稱謂也改為“constructor對(duì)象”或"constructor類型的對(duì)象",構(gòu)造函數(shù)名直接就等同于數(shù)據(jù)類型了。
function A() {} //有一函數(shù)(若是用來(lái)生成對(duì)象,則稱為構(gòu)造函數(shù))名A。 var obj = new A(); //使用構(gòu)造函數(shù)A來(lái)生成實(shí)例對(duì)象obj console.dir(obj); //打印實(shí)例對(duì)象obj
從上圖可知,利用構(gòu)造函數(shù)A生成的實(shí)例對(duì)象obj的數(shù)據(jù)類型為A,另外,我們留意到obj有且只有一個(gè)__proto__屬性,這是什么呢?先別急,下面就說(shuō)到。
詳述構(gòu)造函數(shù)constructor從上文可知,要想生成對(duì)象實(shí)例,必須使用構(gòu)造函數(shù)(constructor),即便是var arr = [];或var obj = {}這樣的形式,javascript也會(huì)在內(nèi)部調(diào)用Function()、Object()這樣預(yù)設(shè)的構(gòu)造函數(shù)(由于是預(yù)設(shè)的構(gòu)造函數(shù)/數(shù)據(jù)類型,因此不需顯式指定)。
繼續(xù)沿用上述例子,這次我們把構(gòu)造函數(shù)A打印出來(lái)看看長(zhǎng)什么樣兒:
function A() {} var obj = new A(); console.dir(A);
實(shí)際上,構(gòu)造函數(shù)跟普通的函數(shù)并無(wú)二致,只是因?yàn)橛猛荆ㄓ脕?lái)生成對(duì)象實(shí)例),因此才冠以“構(gòu)造函數(shù)”的大名。從上圖看,我們略過一些與面向?qū)ο鬅o(wú)關(guān)的屬性(arguments/caller/length/name),以及其函數(shù)作用域(
特別注明是“構(gòu)造函數(shù)中的prototype屬性”,是因?yàn)?,?duì)于一般的函數(shù)來(lái)說(shuō),prototype屬性沒什么意義。prototype屬性指定了使用該構(gòu)造函數(shù)生成的對(duì)象實(shí)例繼承了哪個(gè)對(duì)象實(shí)例。
如上述的function A()的prototype屬性指向了一個(gè)默認(rèn)的Object類型的對(duì)象實(shí)例(在javascript中,變量只是對(duì)象實(shí)例的一個(gè)引用,因此此處用“指向”比較準(zhǔn)確),那么,用function A()作為構(gòu)造函數(shù)實(shí)例化的obj實(shí)際上就是繼承了那默認(rèn)的Object類型的對(duì)象實(shí)例,雖然obj本身并沒有自定義的屬性/方法,但是能通過obj調(diào)用繼承回來(lái)的所有屬性/方法。
既然構(gòu)造函數(shù)的prototype屬性能指定繼承的對(duì)象實(shí)例,那么只要我們修改這prototype屬性,使其指向其它對(duì)象實(shí)例,那么就可以達(dá)到實(shí)現(xiàn)繼承任意對(duì)象的效果了,看下面代碼:
var car = { //一個(gè)普通的Object類型實(shí)例對(duì)象 status: "stop" } function audi() {} //構(gòu)造函數(shù)audi audi.prototype = car; //修改構(gòu)造函數(shù)audi的prototype屬性,使其指向car console.dir(audi); var audiQ3 = new audi(); //利用構(gòu)造函數(shù)audi生成的數(shù)據(jù)類型為audi的實(shí)例對(duì)象 console.dir(audiQ3);
先來(lái)看看構(gòu)造函數(shù)audi打印出來(lái)的結(jié)果:
從audi.prototype.status可以看出,此時(shí)的audi.prototype的確是指向{status: "stop"}這個(gè)對(duì)象實(shí)例了。
那么接下來(lái)看看利用修改后的構(gòu)造函數(shù)audi所生成的對(duì)象實(shí)例audiQ3:
我們可以發(fā)現(xiàn)audiQ3這一實(shí)例對(duì)象的數(shù)據(jù)類型是audi(與構(gòu)造函數(shù)同名),另外,audiQ3其下只有__proto__這唯一一個(gè)成員屬性,繼續(xù)查看__proto__,赫然發(fā)現(xiàn),里面竟然有status: "stop"。沒錯(cuò),__proto__屬性正是指向{status: "stop"}這個(gè)對(duì)象實(shí)例的一個(gè)引用。
原型鏈的接點(diǎn):__proto__通過對(duì)象實(shí)例中的__proto__屬性,繼承的對(duì)象實(shí)例得以與被繼承的對(duì)象實(shí)例鏈接起來(lái),于是,一環(huán)扣一環(huán),形成了一條由對(duì)象實(shí)例、指向被繼承對(duì)象實(shí)例的引用所構(gòu)成的鏈條:原型鏈。
由于__proto__是由構(gòu)造函數(shù)的prototype屬性決定的(也可以說(shuō)是prototype直接賦值給__proto__),因此我們可以通過修改prototype屬性來(lái)操縱這條原型鏈。
再談構(gòu)造函數(shù)構(gòu)造函數(shù),主要用來(lái)在創(chuàng)建對(duì)象時(shí)初始化對(duì)象, 即為對(duì)象成員變量賦初始值,那么,javascript里的構(gòu)造函數(shù),是怎么實(shí)現(xiàn)這樣的功能的呢?以下面的DEMO作為示例說(shuō)明:
function car() { //定義了一個(gè)名為car的構(gòu)造函數(shù) this.status = "stop"; //為日后使用car這一構(gòu)造函數(shù)來(lái)生成的對(duì)象實(shí)例添加個(gè)status成員變量,并賦初始值"stop" this.start = function() { //為對(duì)象實(shí)例添加一個(gè)名為start的成員方法 this.status = "running"; } } var audiQ3 = new car(); //利用car生成一個(gè)對(duì)象實(shí)例,并將其賦給變量audiQ3 console.dir(audiQ3); audiQ3.start(); //調(diào)用audiQ3的start方法 console.dir(audiQ3);
首先來(lái)看構(gòu)造函數(shù)car,我們看到this.status = "stop";,這this是指代car這一function嗎?不是的,這個(gè)this實(shí)際上是指向當(dāng)前函數(shù)執(zhí)行時(shí)的上下文環(huán)境,用在構(gòu)造函數(shù)時(shí),指的則是新生成的對(duì)象實(shí)例(在本DEMO中指的是audiQ3)。因此,只要利用this,就能在構(gòu)造函數(shù)中,為未來(lái)利用此構(gòu)造函數(shù)生成的對(duì)象實(shí)例,添加成員屬性和成員方法了。
javascript原生支持的原型繼承方式:Object.createECMAScript 5定義了一種原生的原型繼承方式:Object.create,我們可以通過這種方式更簡(jiǎn)便地實(shí)現(xiàn)原型繼承。
語(yǔ)法Object.create(proto, [ propertiesObject ])參數(shù)
proto 一個(gè)對(duì)象,作為新創(chuàng)建對(duì)象的原型。示例
propertiesObject 可選。該參數(shù)對(duì)象是一組屬性與值,該對(duì)象的屬性名稱將是新創(chuàng)建的對(duì)象的屬性名稱,值是屬性描述符(這些屬性描述符的結(jié)構(gòu)與Object.defineProperties()的第二個(gè)參數(shù)一樣)。注意:該參數(shù)對(duì)象不能是undefined,另外只有該對(duì)象中自身?yè)碛械目擅杜e的屬性才有效,也就是說(shuō)該對(duì)象的原型鏈上屬性是無(wú)效的。
var car = { status: "stop", start: function() { this.status = "running" } } var audiQ3 = Object.create(car); console.dir(audiQ3);
怎么樣,利用Object.create這種方法是不是很簡(jiǎn)單就實(shí)現(xiàn)了原型繼承呢?實(shí)際上,這是ECMAScript 5給我們做了一下封裝,相當(dāng)于:
function (proto) { var constructor = function(){} constructor.prototype = proto; return new constructor(); }瀏覽器兼容性修復(fù)
考慮到ECMAScript 5在IE上到IE10才完全支持,因此我們有必要對(duì)低版本的IE瀏覽器進(jìn)行兼容,實(shí)際上也很簡(jiǎn)單,對(duì)上面的代碼稍作修改即可:
if(typeof Object.create !== "function") { Object.create = function(proto) { var constructor = function(){} constructor.prototype = proto; return new constructor(); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/78481.html
摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類是相似對(duì)象的描述,稱為類的定義,是該類對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過對(duì)類的實(shí)體化形成的對(duì)象。一類的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過類的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類是相似對(duì)象的描述,稱為類的定義,是該類對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過對(duì)類的實(shí)體化形成的對(duì)象。一類的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過類的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類是相似對(duì)象的描述,稱為類的定義,是該類對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過對(duì)類的實(shí)體化形成的對(duì)象。一類的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過類的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:學(xué)習(xí),總繞不開原型,原型鏈,繼承等等這些知識(shí)。對(duì)象那么好,怎么才能找一個(gè)呸,其實(shí)是創(chuàng)建創(chuàng)建對(duì)象的方法對(duì)象字面量工廠模式構(gòu)造函數(shù)模式原型模式等。原型鏈有什么用來(lái)談?wù)劺^承,繼承可以利用構(gòu)造函數(shù),使用屬性等來(lái)實(shí)現(xiàn)。 初學(xué)者學(xué)習(xí)javascript可能會(huì)感覺很困擾,但是你一旦真正了解了它,我相信你會(huì)愛上它。學(xué)習(xí)ECMAScript,總繞不開原型,原型鏈,繼承等等這些知識(shí)。今天把它們放在一塊兒,...
摘要:首先,需要來(lái)理清一些基礎(chǔ)的計(jì)算機(jī)編程概念編程哲學(xué)與設(shè)計(jì)模式計(jì)算機(jī)編程理念源自于對(duì)現(xiàn)實(shí)抽象的哲學(xué)思考,面向?qū)ο缶幊淌瞧湟环N思維方式,與它并駕齊驅(qū)的是另外兩種思路過程式和函數(shù)式編程。 JavaScript 中的原型機(jī)制一直以來(lái)都被眾多開發(fā)者(包括本人)低估甚至忽視了,這是因?yàn)榻^大多數(shù)人沒有想要深刻理解這個(gè)機(jī)制的內(nèi)涵,以及越來(lái)越多的開發(fā)者缺乏計(jì)算機(jī)編程相關(guān)的基礎(chǔ)知識(shí)。對(duì)于這樣的開發(fā)者來(lái)說(shuō) J...
閱讀 867·2021-10-25 09:45
閱讀 3284·2021-09-22 14:58
閱讀 3844·2021-08-31 09:43
閱讀 915·2019-08-30 15:55
閱讀 917·2019-08-29 13:51
閱讀 1225·2019-08-29 13:02
閱讀 3483·2019-08-29 12:52
閱讀 1961·2019-08-26 13:27