阮一峰es6电子书_ES6理解进阶【大前端高薪训练营】
一:面向?qū)ο?#xff1a;類class
面向?qū)ο笕筇匦灾庋b
封裝是面向?qū)ο蟮闹匾瓌t,它在代碼中的體現(xiàn)主要是以下兩點(diǎn):
- 封裝整體:把對(duì)象的屬性和行為封裝為一個(gè)整體,其中內(nèi)部成員可以分為靜態(tài)成員(也叫類成員)和實(shí)例成員,成員之間又可細(xì)分為屬性和方法。
- 訪問控制:外部對(duì)對(duì)象內(nèi)部屬性和行為的訪問權(quán)限,簡(jiǎn)單來分時(shí)就是私有和公有兩種權(quán)限。
以下是基本封裝示例:
面向?qū)ο笕筇匦灾^承
繼承是面向?qū)ο笞铒@著的一個(gè)特性,它在代碼中的體現(xiàn)主要是以下兩點(diǎn):
- 子類對(duì)象具有父類對(duì)象的屬性和行為
- 子類對(duì)象可以有它自己的屬性和行為
以下是定義一個(gè)Cat類并對(duì)上述Animal類的繼承示例:
面向?qū)ο笕筇匦灾鄳B(tài)
多態(tài)指允許不同的對(duì)象對(duì)同一消息做出不同響應(yīng),在Java中,實(shí)現(xiàn)多態(tài)有以下三個(gè)條件:
- 繼承
- 重寫
- 父類引用指向子類對(duì)象
由于JavaScript是弱類型語言,所以JavaScript實(shí)現(xiàn)多態(tài),不存在父類引用指向子類對(duì)象的問題。
以下再定義一個(gè)Dog類,實(shí)現(xiàn)Animal實(shí)例對(duì)象、Cat實(shí)例對(duì)象和Dog實(shí)例對(duì)象對(duì)同樣的cry調(diào)用做出不同的響應(yīng)示例:
二:數(shù)據(jù)類型Symbol
Symbol是一種新的原始數(shù)據(jù)類型,用來表示獨(dú)一無二的值。此外,它也是對(duì)象屬性名的第二種數(shù)據(jù)類型(另一種是字符串)。
接下來列舉幾個(gè)在日常開發(fā)中可能會(huì)用到Symbol數(shù)據(jù)類型的場(chǎng)景:
1):消除魔法字符串
魔術(shù)字符串指的是,在代碼之中多次出現(xiàn)、與代碼形成強(qiáng)耦合的某一個(gè)具體的字符串或者數(shù)值。風(fēng)格良好的代碼,應(yīng)該盡量消除魔術(shù)字符串,改由含義清晰的變量代替。 —阮一峰
如下含有魔法字符串的代碼示例:
在上述代碼中,大量出現(xiàn)的type1與type2字符串就是魔法字符串。我們分析這樣大量使用魔法字符串可能會(huì)出現(xiàn)的問題:
- 在添加邏輯時(shí),我們每次判斷obj的類型都需要輸入該魔法字符串,這時(shí)不但沒有輸入提示需要一個(gè)一個(gè)字符輸入,而且一旦字符少輸、多輸或者輸入錯(cuò)誤,都會(huì)導(dǎo)致代碼運(yùn)行錯(cuò)誤。
- 在修改邏輯時(shí),如果type1變成了type3,那么就需要把代碼里所有的type1找到并替換成type3。
接下來使用Symbol對(duì)上述代碼改造:
2):實(shí)現(xiàn)對(duì)象的保護(hù)成員 / 私有成員
假設(shè)我們對(duì)一個(gè)對(duì)象需要做如下的訪問控制:
- attr1和attr2公有成員:外部可以訪問
- attr3和attr4保護(hù)成員:外部受限訪問,需要引入鍵attr3和attr4才能訪問
- attr5和attr6私有成員:外部不能訪問,僅支持當(dāng)前模塊文件內(nèi)部訪問
以下是沒有實(shí)現(xiàn)訪問控制的代碼:
接下來使用Symbol對(duì)上述代碼改造:
如上代碼就實(shí)現(xiàn)了對(duì)我們所需要的訪問控制,外部對(duì)不能訪問的成員是無法感知的,因?yàn)橥獠繉?duì)這些不能訪問的成員不但不支持讀寫,甚至也不能遍歷和序列號(hào)操作。
在我們以往的日常開發(fā)中,我們基本上對(duì)對(duì)象的訪問控制都是設(shè)置為公有的,很少設(shè)置為私有,設(shè)置為保護(hù)的就更是沒見過。但少歸少,至少說明了ES6引入的Symbol能幫助我們實(shí)現(xiàn)類似Java中保護(hù)和私有成員的訪問控制。
3):實(shí)現(xiàn)類的保護(hù)成員、私有成員
如下示例,封裝一個(gè)集合Collection,它對(duì)模塊外部具有私有屬性size與私有方法logAdd:
三:數(shù)據(jù)結(jié)構(gòu)Set
Set對(duì)于JavaScript而言是一種新的數(shù)據(jù)結(jié)構(gòu),相對(duì)于數(shù)組用于存儲(chǔ)有序、可重復(fù)的元素集合,Set用于存儲(chǔ)有序、不可重復(fù)的元素集合。
接下來列舉幾個(gè)在日常開發(fā)中可能會(huì)用到Set數(shù)據(jù)結(jié)構(gòu)的場(chǎng)景:
1):數(shù)組去重、字符串去重等任何可迭代類型的去重
2):集合間操作:交集、并集、差集
下面截取阮一峰ES6對(duì)Set的說明案例:
四:數(shù)據(jù)結(jié)構(gòu)Map
Map對(duì)于JavaScript而言也是一種新的數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)鍵值對(duì)形式的字典 / 雙列集合。在Map對(duì)象出現(xiàn)之前,我們通常使用Object對(duì)象來做鍵值對(duì)的存儲(chǔ),下面對(duì)比一下Map對(duì)象實(shí)現(xiàn)鍵值對(duì)存儲(chǔ)與普通對(duì)象存儲(chǔ)鍵值對(duì)的區(qū)別:
- 功能角度:Object對(duì)象只能使用字符串或者Symbol類型作為鍵,而Map對(duì)象可以使用任何數(shù)據(jù)類型作為鍵。Map對(duì)象使用引用類型作為鍵時(shí),以內(nèi)存地址是否一致來作為判斷兩個(gè)鍵是否相同的標(biāo)準(zhǔn)。
- 構(gòu)造與讀寫角度:Object對(duì)象字面量構(gòu)造并存儲(chǔ)鍵值對(duì)的方式比Map方便,其讀寫操作也比Map需要調(diào)用get、set方法而言性能更好(性能分析工具初步對(duì)比分析)。
- 常用Api角度:Object對(duì)象的原型為Object.protoype,而Map對(duì)象的原型為Map.prototype,兩者對(duì)常用的鍵值對(duì)操作都有相應(yīng)的api可以調(diào)用,不過Map原型上定義的Api更加純粹一些。
- 序列化角度:Object對(duì)象存儲(chǔ)鍵值時(shí)支持序列化,而Map對(duì)象不支持。
經(jīng)過上面的對(duì)比分析可以得出結(jié)論,不到必須使用引用類型作為鍵的情況下,我們都用Object對(duì)象字面量的方式來定義并存儲(chǔ)鍵值對(duì)會(huì)更好一些。
接下來敘述在日常開發(fā)中可能會(huì)用到Map數(shù)據(jù)結(jié)構(gòu)的場(chǎng)景:
1):實(shí)現(xiàn)對(duì)象之間的一對(duì)一、一對(duì)多、多對(duì)多(橋Map方式)的關(guān)系
經(jīng)驗(yàn)尚淺,日常開發(fā)示例暫時(shí)沒想到,有機(jī)會(huì)補(bǔ)上。但是Map結(jié)構(gòu)的出現(xiàn)告訴了我們這些JavaScript開發(fā)者,此后在JavaScript中我們也可以很簡(jiǎn)單的實(shí)現(xiàn)對(duì)象之間的映射關(guān)系。
五:迭代器Iterator和for of
遍歷器(Iterator)就是這樣一種機(jī)制。它是一種接口,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問機(jī)制。而for…of循環(huán)是ES6 創(chuàng)造出的一種新的遍歷命令,它可以配合迭代器使用,只要實(shí)現(xiàn)了Iterator接口的任意對(duì)象就可以使用for…of循環(huán)遍歷。
在JavaScript常見的數(shù)據(jù)結(jié)構(gòu)如Array、Set、Map、偽數(shù)組arguments等等一系列對(duì)象的原型上都有Symbol.iterator標(biāo)識(shí),并且有默認(rèn)的Iterator實(shí)現(xiàn)。普通對(duì)象是沒有這個(gè)接口標(biāo)識(shí)以及iterator的實(shí)現(xiàn)的,但是我們可以手動(dòng)為普通對(duì)象添加這個(gè)標(biāo)識(shí)以及對(duì)應(yīng)的iterator實(shí)現(xiàn),示例代碼如下:
上述代碼的優(yōu)點(diǎn)是封裝者在對(duì)外界遍歷沒有影響的情況下,對(duì)數(shù)據(jù)進(jìn)行了更細(xì)粒度的管理。是一種解耦合的代碼優(yōu)化操作!
六:promise、generator和Async
這三者都與異步編程有關(guān),之后會(huì)單獨(dú)拎出來寫在另一篇博客當(dāng)中,在此文中就不做贅述了。
七:模板字符串和標(biāo)簽函數(shù)
模板字符串就不做介紹了,標(biāo)簽函數(shù)在定義時(shí)和普通函數(shù)沒什么區(qū)別。區(qū)別在調(diào)用上,標(biāo)簽函數(shù)以模板字符串作為參數(shù)輸入,并且有獨(dú)特的規(guī)則完成形實(shí)參匹配。接下來看一個(gè)簡(jiǎn)單的例子:
上述示例運(yùn)行結(jié)果:
經(jīng)過上述例子我們可以大概得知標(biāo)簽函數(shù)的形實(shí)參匹配規(guī)則:
- 模板中字面量數(shù)組的形實(shí)參匹配:模板字符串以類似/${[^}]+}/g 的正則規(guī)則進(jìn)行split 得到其內(nèi)所有字面量組成的數(shù)組,而后作為實(shí)參匹配標(biāo)簽函數(shù)的第一個(gè)形參literals
- 模板中所有變量的形實(shí)參匹配:模板字符串以 /${[^}]+}/g 的正則規(guī)則進(jìn)行match找到所有的JS變量數(shù)組,解析得到其值后,按順序作為實(shí)參匹配標(biāo)簽函數(shù)剩下的形參,上例代碼中用rest剩余參數(shù)作為形參接收所有實(shí)參。
通過上面的例子和解析,我們認(rèn)識(shí)了標(biāo)簽函數(shù)調(diào)用的執(zhí)行規(guī)則。根據(jù)標(biāo)簽函數(shù)和模板字符串的配合機(jī)制,我們很容易就想到這種機(jī)制可以實(shí)現(xiàn)模板引擎甚至是定義內(nèi)部語言的功能。
接下來敘述在日常開發(fā)中我們可能會(huì)用到標(biāo)簽函數(shù)的場(chǎng)景:
1):把可能作為innerHtml的string中的特殊字符轉(zhuǎn)義,使它不被解析為HTML標(biāo)簽
在日常開發(fā)中,我們很可能會(huì)碰到這么一個(gè)需求:
- 一個(gè)input輸入框接收用戶的輸入
- 另一個(gè)p標(biāo)簽用來展示這個(gè)用戶的輸入
先分析一下這樣做的風(fēng)險(xiǎn):由于用戶的輸入直接作為了p標(biāo)簽的內(nèi)容,當(dāng)用戶輸入一個(gè)<script>標(biāo)簽等任意HTML標(biāo)簽時(shí),如果我們直接把它交給p標(biāo)簽,那么瀏覽器就會(huì)把它當(dāng)成inneHTML進(jìn)行解析后執(zhí)行其中的腳本或者渲染HTML,這肯定是不被期望且有風(fēng)險(xiǎn)的。所以我們?cè)诎延脩舻妮斎虢唤op標(biāo)簽展示之前,應(yīng)該對(duì)其中的一些特殊字符進(jìn)行轉(zhuǎn)義,防止被瀏覽器解析為標(biāo)簽,接下來示例中我們用標(biāo)簽函數(shù)實(shí)現(xiàn)這個(gè)轉(zhuǎn)義過程:
2):i18n 國(guó)際化
在我們的項(xiàng)目中支持國(guó)際化(i18n)的邏輯本身非常簡(jiǎn)單,只需要界面中的所有字符串變量化,而后這些變量自動(dòng)根據(jù)項(xiàng)目的當(dāng)前語音渲染出該語言下的字符串。使用函數(shù)式編程的思想來實(shí)現(xiàn)的基本思路如下:
- 輸入:需要翻譯的字符串鍵
- 映射關(guān)系:根據(jù)輸入獲得輸出,具體映射邏輯與當(dāng)前語言與語言包有關(guān)
- 輸出:翻譯后的字符串
3):定義語言,如 jsx
jsx標(biāo)簽函數(shù),實(shí)現(xiàn)了將一個(gè)含有html、css、js的模板字符串解析為一個(gè)React 對(duì)象的功能。它的模板解析功能很強(qiáng)大,以至于我們把它稱之為一門語言。思想和原理大概如此,由于博主暫未看過jsx源碼,下文對(duì)此不再贅述。
八:內(nèi)置對(duì)象Refelect
Refelect是JavaScript的一個(gè)新內(nèi)置對(duì)象(非函數(shù)類型對(duì)象),與Math對(duì)象上掛載了很多用于數(shù)學(xué)處理方面的方法一樣,Refelect對(duì)象身上掛在了一套用于操作對(duì)象的方法。
下表總結(jié)列舉了Refelect對(duì)象上的13個(gè)操作對(duì)象的靜態(tài)方法的作用,以及在Reflect出現(xiàn)之前的實(shí)現(xiàn)方案:
由上面剛剛總結(jié)出的表格內(nèi)容可以得知,Reflect在對(duì)象層面以及屬性層面的Api都有相應(yīng)的實(shí)現(xiàn),并且比單獨(dú)的Object原型更加全面。那么我們?cè)谌粘i_發(fā)中如何選擇呢,出于代碼的運(yùn)行性能、可讀性以及統(tǒng)一操作思想考慮,個(gè)人是這么選擇的,,日常簡(jiǎn)潔的屬性讀寫、函數(shù)對(duì)象調(diào)用操作不用Reflect,其它都統(tǒng)一使用Reflect對(duì)象操作(也就是不用操作符delete、in以及重疊的Object原型上的方法)。
九:內(nèi)置對(duì)象Proxy
Proxy是JavaScript的一個(gè)新內(nèi)置對(duì)象(函數(shù)類型對(duì)象),它的實(shí)例對(duì)象用于定義對(duì)象基本操作的自定義行為(如屬性查找、賦值、枚舉、函數(shù)調(diào)用等)。
在上述Reflect的介紹中,我們發(fā)現(xiàn)在日常開發(fā)中,我們可以也經(jīng)常對(duì)對(duì)象進(jìn)行對(duì)象層面和屬性層面的很多操作,既然是操作,那么我們就希望能夠具備對(duì)這些操作進(jìn)行AOP處理的能力,也即實(shí)現(xiàn)代理操作,那么應(yīng)該怎么做呢?ES5提供了存取器屬性get、set,這讓我們具備了代理一個(gè)對(duì)象的屬性讀寫操作以進(jìn)行AOP處理的能力。但是這時(shí)候?qū)τ谄渌鼘?duì)對(duì)象操作行為的代理方案仍然沒有官方的實(shí)現(xiàn)方案。直到ES6的Proxy出現(xiàn),這才讓我們具備了對(duì)這些各種類型的對(duì)象操作進(jìn)行代理以進(jìn)行AOP處理的能力(上述Reflect的13個(gè)靜態(tài)方法對(duì)應(yīng)的對(duì)象操作全部都可以AOP處理)。
既然Object.defineProperty和Reflect都可以代理對(duì)象操作,那么我們對(duì)比一下兩者的代理原理和優(yōu)缺點(diǎn)以備往后甄選方案:
- 代理原理:Object.defineProperty的原理是通過將數(shù)據(jù)屬性轉(zhuǎn)變?yōu)榇嫒∑鲗傩缘姆绞綄?shí)現(xiàn)的屬性讀寫代理。而Proxy方式的原理則是這個(gè)內(nèi)置Proxy對(duì)象內(nèi)部有一套監(jiān)聽機(jī)制,在傳入handler對(duì)象作為參數(shù)構(gòu)造代理對(duì)象后,一旦代理對(duì)象的操作觸發(fā)后,就會(huì)進(jìn)入handler中對(duì)應(yīng)注冊(cè)的處理函數(shù) 而后可以 有選擇的使用Reflect將操作轉(zhuǎn)發(fā)被代理對(duì)象上。
- 代理局限性:Object.defineProperty始終還是局限于屬性層面的讀寫代理,對(duì)于對(duì)象層面以及屬性的其它操作代理它都無法實(shí)現(xiàn)。鑒于此,由于數(shù)組對(duì)象push、pop等方法的存在,它對(duì)于數(shù)組元素的讀寫代理并不方便。而使用Proxy則可以很方便的監(jiān)視數(shù)組操作。
- 自我代理:Object.defineProperty方式可以代理到自身(代理之后使用對(duì)象本身即可),也可以代理到別的對(duì)象身上(代理之后需要使用代理對(duì)象)。Proxy方式只能代理到Proxy實(shí)例對(duì)象上。這一點(diǎn)在其它說法中是Proxy對(duì)象不需要侵入對(duì)象就可以實(shí)現(xiàn)代理,實(shí)際上Object.defineProperty方式也可以不侵入。
接下來敘述在日常開發(fā)中我們可能會(huì)見到 / 用到Proxy代理的場(chǎng)景:
1):實(shí)現(xiàn)屬性讀寫AOP
2):實(shí)現(xiàn)數(shù)組操作的監(jiān)視
本文結(jié)束,謝謝觀看。
如若認(rèn)可,一鍵三連。
原出處:CSDN
原文鏈接:ES6理解進(jìn)階【大前端高薪訓(xùn)練營(yíng)】_清心-CSDN博客
總結(jié)
以上是生活随笔為你收集整理的阮一峰es6电子书_ES6理解进阶【大前端高薪训练营】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: node开启子线程_多进程 amp; N
- 下一篇: 网络安全模型_基于数据驱动的网络安全流量