前言
????即使不了解Javascript的設(shè)計(jì)原理和繼承機(jī)制這些東西的時(shí)候,我們依然能很好的使用Javascript去設(shè)計(jì)前端頁(yè)面及功能。
????這得力于傳統(tǒng)jquery時(shí)的前端開(kāi)發(fā)我們把大部分的業(yè)務(wù)邏輯封裝在后臺(tái),前端代碼的邏輯性大大降低,我們只需要使用一點(diǎn)點(diǎn)j和ava語(yǔ)法類似的知識(shí)就能寫(xiě)出所需的javascript代碼。
????這時(shí)候我們不需要考慮繼承,不需要考慮復(fù)雜的封裝,甚至連this關(guān)鍵字我們都用的極少。但在接觸了react,vue這些前端框架之后就有必要詳細(xì)的了解與學(xué)習(xí)Javascript了,Javascript已經(jīng)變成一個(gè)獨(dú)立于后端的完整的前端框架的一個(gè)基礎(chǔ)。
對(duì)象及對(duì)象的創(chuàng)建
????Javascript是一種基于對(duì)象(object-based)的語(yǔ)言,你遇到的所有東西幾乎都是對(duì)象。但是,它又不是一種真正的面向?qū)ο缶幊蹋∣OP)語(yǔ)言,因?yàn)樗恼Z(yǔ)法中沒(méi)有"子類"和"父類"的概念,也沒(méi)有"類"(class)和"實(shí)例"(instance)的區(qū)分。我們舉幾個(gè)例子,一下的都是對(duì)象。

????這些基礎(chǔ)的數(shù)據(jù)類型也是對(duì)象但是不在本章的討論訪問(wèn)之內(nèi)。

這兩行都是等價(jià)的,都生成了一個(gè)名為fun1的(函數(shù))對(duì)象。

????這是我們比較常見(jiàn)的對(duì)象方式,用大括號(hào)的方式創(chuàng)建對(duì)象,采用鍵值對(duì)的方式描述對(duì)象屬性。

????這個(gè)對(duì)象的結(jié)果其實(shí)和第三個(gè)對(duì)象是一樣的都是可以用{}來(lái)表述的。
????我們可以很清楚的看出這都是對(duì)象,完全沒(méi)有類的概念,我們最后一個(gè)例子里的Object是類么?不,不是的。接下來(lái)就要說(shuō)明一下對(duì)象的創(chuàng)建方式。
????對(duì)象的創(chuàng)建方式只有一種,那就是

????所以我們很清楚了,Object是一個(gè)構(gòu)造函數(shù)(對(duì)象)。
????這么設(shè)計(jì)的原因是因?yàn)楫?dāng)初javascript的設(shè)計(jì)者并不打算引入"類"(class)的概念,因?yàn)橐坏┯辛?類",Javascript就是一種完整的面向?qū)ο缶幊陶Z(yǔ)言了,這好像有點(diǎn)太正式了,而且增加了初學(xué)者的入門(mén)難度。不過(guò)他在設(shè)計(jì)創(chuàng)建對(duì)象的方式上卻借鑒了C++和java的語(yǔ)法,引用了new關(guān)鍵字,但是javascript是沒(méi)有類的?那么new后面跟著是什么呢?它發(fā)現(xiàn)java與C++對(duì)象的創(chuàng)建都必須執(zhí)行構(gòu)造函數(shù)(constructor),于是乎他就做了簡(jiǎn)化的設(shè)計(jì),在Javascript語(yǔ)言中,new命令后面跟的不是類,而是構(gòu)造函數(shù)。
????所以以上四種范例其本質(zhì)上都是javascript通過(guò)new 構(gòu)造函數(shù)的方式隱式或顯式幫我們創(chuàng)建的。我們先詳細(xì)的了解一下構(gòu)造函數(shù)的創(chuàng)建方式再細(xì)說(shuō)范例中是如何隱式創(chuàng)建的對(duì)象。
構(gòu)造函數(shù) construct
示例:
????7丨console.log(zs); //[object Object] ?
{[functions]: , __proto__: { },age: 23,name:"zhangsan",sex: "man"}
????可以看到我們根據(jù)man構(gòu)造函數(shù)創(chuàng)建了一個(gè)對(duì)象zs,對(duì)象有name,age和sex 屬性。在這里面我們可以清楚的看到構(gòu)造函數(shù)給對(duì)象設(shè)置屬性的方式是this關(guān)鍵字,this關(guān)鍵字動(dòng)態(tài)指向的是創(chuàng)建的對(duì)象(關(guān)于this的其它問(wèn)題會(huì)另起一章介紹),this關(guān)鍵字后跟著的屬性或方法就是該對(duì)象的屬性或方法。但是如果構(gòu)造方法有返回值,那生成的對(duì)象就是構(gòu)造方法的返回值了,所以大家在寫(xiě)構(gòu)造方法時(shí)要特別注意,示例如下:
????看到zs的值變成了{(lán)info:‘error’},所以寫(xiě)構(gòu)造函數(shù)的時(shí)候最好也不要寫(xiě)返回值。但是我發(fā)另一很奇怪的情況,示例如下
丨:"zhangsan",sex: "man"}
????我們看到如果返回的是基本類型,整型,字符串類型等的那構(gòu)造函數(shù)還是生效了,這另我十分費(fèi)解。不過(guò)只要記住在我們寫(xiě)構(gòu)造函數(shù)時(shí)不去寫(xiě)返回值也就能規(guī)避這種問(wèn)題。
????構(gòu)造函數(shù)創(chuàng)建的方式也不是完全完美的,比如看下面的示例中的sex屬性,如果通過(guò)man構(gòu)造函數(shù)創(chuàng)建出來(lái)的對(duì)象sex都固定是“man”,那每個(gè)對(duì)象都要分配內(nèi)存來(lái)存儲(chǔ)sex屬性是不是有些浪費(fèi)呢?或者就是有些屬性要給所有對(duì)象共用的呢?比如對(duì)象的方法,完全不需要隨著對(duì)象變化,該如何處理?

????為了解決這個(gè)問(wèn)題,javascript為構(gòu)造函數(shù)(函數(shù)類型對(duì)象)提供了prototype屬性。
順便給大家推薦一個(gè)裙,它的前面是 537,中間是631,最后就是 707。想要學(xué)習(xí)前端的小伙伴可以加入我們一起學(xué)習(xí),互相幫助。群里每天晚上都有大神免費(fèi)直播上課,如果不是想學(xué)習(xí)的小伙伴就不要加啦。(537-631-707)
prototype屬性
????prototype只能用于函數(shù)對(duì)象,如果你給其它非函數(shù)對(duì)象增加prototype屬性,執(zhí)行器會(huì)報(bào)出該對(duì)象無(wú)prototype屬性錯(cuò)誤。
????我們先來(lái)一個(gè)示例來(lái)看prototype如何使用
????我們看到構(gòu)造函數(shù)通過(guò)prototype屬性增加的屬性或方法是給所有對(duì)象共享的。我們把那些需要共享的方法和屬性放在prototype屬性里,那些不需要共享的屬性和方法,就放在構(gòu)造函數(shù)里面。
????而實(shí)現(xiàn)過(guò)程是這樣的,當(dāng)實(shí)例對(duì)象一旦創(chuàng)建,將自動(dòng)引用prototype對(duì)象的屬性和方法。也就是說(shuō),實(shí)例對(duì)象的屬性和方法,分成兩種,一種是本地的,另一種是引用的。
????我們?cè)倏匆粋€(gè)示例
????我們看到只有通過(guò)prototype屬性修改sex對(duì)象才能更新全部對(duì)象的sex屬性,而單單修改某個(gè)對(duì)象的sex屬性是無(wú)法全局修改的,對(duì)于這個(gè)我不知道是如何實(shí)現(xiàn)的,有知道的不吝賜教。
????我們?cè)倏匆粋€(gè)示例

????這個(gè)示例只是prototype下屬性的修改方式改為對(duì)整個(gè)prototype屬性的對(duì)象進(jìn)行設(shè)置。這種方式可以么?可以,而且修改成這樣對(duì)上一個(gè)示例的輸出完全沒(méi)有影響。但是個(gè)人還是不推薦這種方式,因?yàn)閜rototype屬性還有一個(gè)特別的方法constructor。
constructor
????我們先介紹下constructor屬性

constructor屬性是指向構(gòu)造方法的引用,也就是說(shuō)如下兩行代碼是等價(jià)的。

????看起來(lái)好像沒(méi)什么用,但是我們知道prototype可以把自己的屬性傳遞給對(duì)象的。也就是說(shuō)我們可以通過(guò)constructor來(lái)比較兩個(gè)對(duì)象是不是同一個(gè)構(gòu)造器的實(shí)例,示例如下:

????所以通過(guò)man.prototype={…}的方式設(shè)置共享屬性會(huì)破壞constructor屬性。雖然好像破壞了在我們的使用中不會(huì)產(chǎn)生任何影響,但我們還是要知道有這個(gè)屬性的存在及prototype的作用。
????prototype還有一些其他方法,但是通過(guò)man.prototype={…}方式是破壞不了,只是因?yàn)樗袑?duì)象的這些方法都是一致的,比如isPrototypeOf,hasOwnProperty方法,提供幾個(gè)示例,就不詳述了。
????isPrototypeOf 示例是不是來(lái)自該構(gòu)造函數(shù)

????hasOwnProperty 每個(gè)實(shí)例對(duì)象都有該方法,用來(lái)判斷某一個(gè)屬性到底是本地屬性,還是繼承自prototype對(duì)象的屬性

????我們?cè)倏匆幌伦铋_(kāi)始我們說(shuō)的那個(gè)問(wèn)題,所有的對(duì)象生成本質(zhì)上都是通過(guò)構(gòu)造函數(shù)生成的。查看的方法很簡(jiǎn)單,我們知道每個(gè)對(duì)象都有一個(gè)constructor方法,我們只要輸出每個(gè)對(duì)象的constructor方法就能找到他的構(gòu)造函數(shù)。
其它問(wèn)題
????我們說(shuō)了構(gòu)造函數(shù),什么樣才能算是構(gòu)造函數(shù)呢?所有的函數(shù)都可以是構(gòu)造函數(shù),所有的函數(shù)也只有函數(shù)可以擁有有prototype屬性。而函數(shù)也是對(duì)象,如上面例子的fun1函數(shù),它也是由Function()構(gòu)造函數(shù)生成的,fun1是函數(shù)對(duì)象,你可以把fun1當(dāng)對(duì)象用,給他設(shè)置屬性,方法都是完全沒(méi)問(wèn)題的,但是fun1.prototype設(shè)置的屬性也只能給new fun1()生成的對(duì)象使用,不能混淆了。
????有說(shuō)javascript的繼承機(jī)制是依靠prototype屬性(原型鏈{prototype chain}模式)來(lái)實(shí)現(xiàn)的,但是因?yàn)橥ㄟ^(guò)prototype設(shè)置“父對(duì)象”的屬性和方法,只能變成“繼承”共享的屬性和方法,每個(gè)對(duì)象自己私有的屬性和方法是無(wú)法繼承的,還是有一些不一樣的。而且說(shuō)是共享只能說(shuō)是統(tǒng)一賦值,我們通過(guò)對(duì)象去修改prototype提供的屬性并不會(huì)影響其他對(duì)象的該屬性。說(shuō)是繼承但是不太一樣。
????在理解javascript的對(duì)象及對(duì)象的創(chuàng)建時(shí)要牢記兩點(diǎn),一個(gè)是javascript內(nèi)(幾乎)所有的都是對(duì)象,并且對(duì)象都有構(gòu)造函數(shù)和一些默認(rèn)方法。比如我有時(shí)忘記這兩件事,寫(xiě)一些奇怪的范例時(shí)就很懵逼,為什么會(huì)出現(xiàn)這個(gè)結(jié)果。如我常忘記prototype屬性指向的也是對(duì)象,對(duì)象也就會(huì)有constructor,isPrototypeOf 等這些方法。
作者:spongeboblz??
來(lái)源:CSDN????????????????????????????????????????
如果小伙伴覺(jué)得這篇文章不錯(cuò)還請(qǐng)給個(gè)贊吧 ↓↓↓