【三】引用類型

前言
本篇章主要介紹了引用類型的特點,諸如正則表達式、時間類型、基本包裝類、Object、數(shù)組等,至于function部分,內(nèi)容較多,將另起篇章。
面試回答
1.引用類型:引用類型有array、object、function。引用類型屬于堆內(nèi)存,占用的空間不固定,保存和復制的是指針。引用類型常用instanceof去判斷,如果本身不知道數(shù)據(jù)屬于什么類型的話,就用object.prototype.toString.call方法去判斷,不管是instanceof還是call方法,他們本質(zhì)上都是通過原型鏈判斷。
2.數(shù)組去重:最常用的是利用Set這種數(shù)據(jù)結(jié)構(gòu),搭配Array.from或者擴展運算符來實現(xiàn)。至于其他方式,不管是利用indexOf、includes、sort(sort排序后相同的元素會相鄰),首先都會有一層遍歷。
3.深淺拷貝:深淺拷貝的區(qū)別在于,淺拷貝只復制指針,新舊對象仍使用同一塊內(nèi)存。而深拷貝會創(chuàng)建一個一模一樣的對象,開辟新的內(nèi)存,因此修改新對象不會影響原對象。簡單點,就用JSON.parse包裹著JSON.stringify,這種方式算深拷貝,因為它開辟了新的內(nèi)存空間,只不過JSON.stringify會丟失一些數(shù)據(jù),比如undefined、function。準確點,就需要采取遞歸的方式去深拷貝,判斷傳入的數(shù)據(jù)是不是object,如果不是就拋出去,如果是那么就繼續(xù)遞歸。
4.new關(guān)鍵字:new關(guān)鍵字先是創(chuàng)建新的對象,然后繼承傳入的函數(shù)原型,修改this指向并且執(zhí)行構(gòu)造函數(shù),最后返回新的對象。
知識點
引用類型都是堆(heap) ,有兩個特征:1. 保存和復制都是指針。2.占用空間不固定(大小不定),也不會自動釋放,堆內(nèi)存中。
1.RegExp
基本規(guī)則
關(guān)于RegExp對象還是經(jīng)常會使用到,比如限制input輸入框(校驗郵箱是否符合)、匹配變量值做if判斷等等。RegExp類型既可以通過字面量聲明的方式創(chuàng)建,也可以通過new的方式創(chuàng)建;
字面量聲明:/pattern/attributes ,例:let re1 = /ABC/g
new聲明:new RegExp(pattern, attributes),例let regex=new RegExp('/abc/',g)
pattern既可以是正則表達式,也可以是字符串,如果是字符串,則如下:
attributes為可選的字符串 ,含屬性 "g"、"i" 和 "m",分別用于指定全局匹配、不區(qū)分大小寫的匹配和多行匹配
下面著重梳理幾條規(guī)則,用來能夠基本的識別正則表達式,具體屬性可以參考:RegExp基礎規(guī)則
1./ xxx /g ,所有的正則表達式均寫在/ /內(nèi),反斜杠代表轉(zhuǎn)義,如\d,表示數(shù)字
2.^
表示行的開頭,^\d
表示必須以數(shù)字開頭
$
表示行的結(jié)束,\d$
表示必須以數(shù)字結(jié)束
有頭有尾則必須完全符合規(guī)則才可匹配,如^\d{3}$
則表示,連續(xù)三個數(shù)字才可匹配。
3.[]表示能夠匹配的范圍,匹配的是單個字符
4.如果涉及特殊字符如'-'
,在正則表達式中,要用'\-'
轉(zhuǎn)義,如,/^\d{3}\-\d{3,8}$/
。
5.n{X,Y}表示至少出現(xiàn)X個連續(xù)n ,至多出現(xiàn)Y個連續(xù)n時,匹配。Y可不寫。閉區(qū)間,含X,Y
6.*等于{0,} 即大于等于0次 ;+代表{1,} 即大于等于1次;?代表{0,1} 即0次或1次
7.用()
表示的就是要提取的分組。比如:^(\d{3})\-(\d{3,8})$
8.取反:[^abc]
,查找任何不在方括號之間的字符。
根據(jù)上面8條規(guī)則來識別一下下述含義:
常用方法
RegExp 對象有 4 個方法:test()、exec() 、compile()、match()
。
test():test() 方法檢索字符串中的指定值。返回值是 true 或 false。
match():match()方法返回值是符合規(guī)則的值(數(shù)組)。
exec():exec() 方法檢索字符串中的指定值。返回值是被找到的值。如果沒有發(fā)現(xiàn)匹配,則返回 null
compile():compile()方法用于改變 RegExp。
2.Date
定義
Date獲取的時間為本地時間,即電腦或手機上的設備時間,如果你設備時間不準確,那么你獲取的時間同樣也會不準確;如若涉及時區(qū)問題,可以使用UTC時間?(零時區(qū)) 。
基礎API
應用場景
1.針對要求高精確性的時間,舉個例子:
假設:本地時間、服務器時間不一致,而這個假設發(fā)生的概率很大。
需求:一個案件需要點擊撥打電話后才可提交案件
操作:點擊撥打按鈕記錄的是本地時間(用來展示);提交案件記錄的是服務器的時間(后端需要記錄案件提交的時間);而這時候時間不一致會帶來許多分析上的麻煩。比如你明明12:30:00(本地時間)打了電話,提交案件的時間卻是12:00:00(服務器時間)。理論上提交案件的時間應該晚于撥打時間,卻因為時間不一致,導致數(shù)據(jù)分析有異常。
解決辦法:通過調(diào)用接口獲取服務器時間,統(tǒng)一時間上的管理,避免造成數(shù)據(jù)分析的麻煩。
經(jīng)驗總結(jié):如果涉及到時間問題,特別是對時間精確要求較高的需求時,需要考慮時間獲取來源的統(tǒng)一。
2.針對時間格式的統(tǒng)一與轉(zhuǎn)換
問題緣由:不同的瀏覽器對于new Date()的解析支持是不同的,比如ios就只支持"2021/12/12 12:21:21",而部分瀏覽器則只支持"2021-12-12 12:21:21"。而有時候需求對時間格式有著另外的要求,也需要對時間進行統(tǒng)一的處理。
經(jīng)驗總結(jié):
首先,涉及到時間問題,首先要考慮時間格式能不能被識別兼容
其次,需要與后端統(tǒng)一好時間格式,避免由于時間格式產(chǎn)生的報錯,諸如顯示、轉(zhuǎn)換等,推薦方法是前后端傳值統(tǒng)一使用時間戳,時間格式由前端進行轉(zhuǎn)換。
最后,涉及時間格式的轉(zhuǎn)換,常見的便是new Date() 、elementUI中的dateTimepicker,而時間格式的轉(zhuǎn)換我這邊推薦插件moment.js或者dayjs或者自行封裝一個簡易的時間處理函數(shù)。
3.基本包裝類型
本質(zhì)
為了便于操作基本類型值,ECMAScript 還提供了3 個特殊的引用類型:Boolean、Number和String。而boolean、number、string基本類型之所以能夠直接操作是因為在調(diào)用方法的過程中,默默進行基本包裝類型的處理,如下:
相關(guān)知識點
裝箱:基礎類型-->引用類型
拆箱:引用類型-->基礎類型
4.Object
屬性的增強寫法
JSON的理解
JSON是一種輕量級的數(shù)據(jù)交換格式,主要是為了跨平臺交流數(shù)據(jù)用的,因此他的格式要求也相對規(guī)范嚴格,比如JSON的屬性名必須有雙引號,如果值是字符串,也必須是雙引號。由于在請求接口中使用的JSON格式,所以對于前端代碼中的入?yún)⒒径际峭ㄟ^序列化的方式進行入?yún)⒌奶幚?,如?/span>
遍歷方法
對象轉(zhuǎn)數(shù)組
對象合并
5.Array
與Object的區(qū)別
1.數(shù)組有序,Object無序
2.數(shù)組的元素可以沒有屬性名(但是有索引),對象的元素必須有值
3.數(shù)組只能用整數(shù)作為數(shù)組元素的索引,而不能用字符串,且數(shù)組元素的使用只能通過方括號(arr[0])來獲取
4.數(shù)組的空元素empty表示空位, 它不是一種數(shù)據(jù)類型, 而是由于人為修改arr.length 或者寫入時多寫了逗號造成的。empty和undefined在操作數(shù)組時的主要區(qū)別在于:使用數(shù)組的forEach()方法遍歷時會自動忽略空位, 而使用for循環(huán)則會將empty轉(zhuǎn)換為undefined并遍歷。
Tip:使用對象或數(shù)組的方法前一定要先判斷其是否存在,因為數(shù)組經(jīng)常會連帶方法使用,比如arr.indexOf('123'),此時如果arr不存在,那么程序會直接報錯。
不修改原數(shù)組的方法
1、2:判斷數(shù)組中是否包含一個元素3、4:找出第一個符合條件的數(shù)組成員5:判斷數(shù)組是否為空,由于數(shù)組是對象,因此存在引用地址的問題,所以不能使用 arr === [] 來判斷數(shù)組是否為空6、7:合并數(shù)組可以使用,不過6、7都屬于淺拷貝,即僅適用于對不包含引用對象的一維數(shù)組的拷貝,就是對象不是那種多層嵌套的8:復制數(shù)組,不過8屬于淺拷貝,即僅適用于對不包含引用對象的一維數(shù)組的拷貝,就是對象不是那種多層嵌套的9:適合用于將數(shù)組元素拼接后轉(zhuǎn)換成字符串,但如果元素為undefined或null,它會被轉(zhuǎn)換為空字符串。
修改原數(shù)組的方法
遍歷方法
數(shù)組合并
數(shù)組去重
數(shù)組扁平化
應用
1.關(guān)鍵字
前端關(guān)鍵字有:delete、switch、case、default、break(跳出循環(huán),map方法中不可用)、for、in、continue(跳出本次循環(huán))、while、if、else、return(停止方法的執(zhí)行)、try、catch、this、do、with、finally、throw、let、var、function、instanceof、typeof、new 等,這邊挑選部分進行解釋。
delete關(guān)鍵字
new關(guān)鍵字
接下來描述一些new操作符的的原理、過程及實現(xiàn):
new操作符的作用是通過構(gòu)造函數(shù)來創(chuàng)建一個實例對象,那么new操作符做的事包括:
1.創(chuàng)建新的對象
2.繼承傳入函數(shù)的原型
3.修改this指向并執(zhí)行構(gòu)造函數(shù)
4.返回新對象
PS:至于為什么不能寫成let p = _new Person('Tom', 20)的形式,是因為_new是我們自定義的方法,需要以方法的形式調(diào)用;而let p = new Person(xxxx)之所以可以如此使用,是因為new是ECMA規(guī)定的內(nèi)置語法,如果你非要寫成_new Person()形式,就相當于新增了一個內(nèi)置語法,等同于ES5升級到ES6
2.解構(gòu)賦值
3.深淺拷貝
深淺拷貝的區(qū)別在于,淺拷貝只復制指向某個對象的指針,而不復制對象本身,新舊對象還是共享同一塊內(nèi)存。但深拷貝會另外創(chuàng)造一個一模一樣的對象,新對象跟原對象不共享內(nèi)存,修改新對象不會改到原對象。
具體表現(xiàn)即,深拷貝的數(shù)據(jù)與被拷貝對象完全沒有關(guān)系,不管被拷貝對象如何改動,都不會影響深拷貝的數(shù)據(jù);而淺拷貝的數(shù)據(jù)如果內(nèi)層不嵌套,則與深拷貝的表現(xiàn)一致,如果內(nèi)層嵌套,則被拷貝對象嵌套部分的數(shù)據(jù)修改會使拷貝對象同步修改。
4.類型判斷
5.intanceof操作符的原理及實現(xiàn)
最后
走過路過,不要錯過,點贊、收藏、評論三連~