隨着如今先後端分離的推動愈來愈快,如今的平常開發前端每每是本身不須要去數據庫操做數據了,只須要經過調用API就能夠進行數據獲取。這雖然極大的方便了咱們的開發,可是隨之而來也會伴生各類各樣的新問題,好比數據的層次嵌套過深、數據不單一等等一系列緣由,使得咱們每每須要作不少的邏輯判斷。前端
好比咱們在後端拿出了people的數據,想去直接獲取它的家庭人口,若是像下面這樣子直接獲取,可能會有時候可以拿到,有時候由於場景變化就會缺乏這個字段,得到ERROR大獎章一枚!node
const people = {} // 假設這是後端數據
console.log(people.family.numbers);
複製代碼
js中直接獲取不存在的數據是會引起異常,致使整個進程done掉,可是由於一個小小的數據沒有致使整個進程done掉很明顯不是咱們想要的結果,那麼咱們就要進行一下控制了。在這裏解決辦法大體分爲兩種,一種是藉助第三方庫,第二種就說本身手動攔截了。web
第三方庫數據庫
在這裏咱們直接拿lodash來使用,lodash咱們要獲取一個對象下的數據,每每會使用getter方法後端
_.get('people','family.numbers')
複製代碼
在lodash中若是存在咱們要獲取的key
,就會返回該key
下的value
,即咱們想要的numbers
,若是不存在,就返回空(順便咱們具體看看他背後作了哪些操做吧)數組
//get.js
function _get(data,f){
if(f.substr) f = f.split(/\.|\\|\//);
if(f.length && data){
return _get(data[f.shift()],f)
}else if(!f.length && data){
return data
}else {
return "";
}
}
export default function(target,path,defaultValue){
return _get(target,path,defaultValue);
}
複製代碼
原生本身js手寫瀏覽器
本身手寫進行攔截其思路也是極其簡單,就是逐層向下判斷有沒有就好了。markdown
console.log(people && people.family && people.family.numbers);
複製代碼
當進行逐個判斷的時候,一個不存在就會返回undefined,從而避免ERROR,可是相比之下,若是不依賴第三方庫的時候,本身寫就顯得極其複雜了。假設這數據結構的深度不是三層,是5層,10層呢?那是否是就顯得極其複雜了?數據結構
這是在這個背景之下,咱們今天的豬腳——可選操做符?.
就出來了!那麼使用可選操做符咱們又要怎麼操做呢?前後端分離
咱們只需在須要判斷的的地方使用它就行了呀!
console.log(people?.family?.numbers); // undefined
複製代碼
就是這麼的簡單!!!這是這麼粗暴!!!只要在須要判斷的地方前面,多加一個?就歐了
這麼實用的操做,肯定不學習嗎?
官方定義MDN文檔:可選鏈操做符( ?. )容許讀取位於鏈接對象鏈深處的屬性的值,而沒必要明確驗證鏈中的每一個引用是否有效。?. 操做符的功能相似於 . 鏈式操做符,不一樣之處在於,在引用爲空(nullish ) (null 或者 undefined) 的狀況下不會引發錯誤,該表達式短路返回值是 undefined。與函數調用一塊兒使用時,若是給定的函數不存在,則返回 undefined。
當嘗試訪問可能不存在的對象屬性時,可選鏈操做符將會使表達式更短、更簡明。在探索一個對象的內容時,若是不能肯定哪些屬性一定存在,可選鏈操做符也是頗有幫助的。
可選操做符的基礎使用實際上是極其簡單的,就是在可能會由於缺少字段引發error的地方加上便可。怎麼肯定從哪裏開始會引起這個error呢?
咱們仍是從那個有(jian)趣(lou)的後端數據講起吧
const people = {} // 假設這是後端數據
console.log(people); // {}
console.log(people.family); // undefined
console.log(people.family.number); // ERROR
複製代碼
由輸出能夠看到,其實js自己仍是有必定的容錯機制的,因此咱們只須要在可能會觸發容錯機制的地方,加上便可!
雖然使用可選操做符很簡單,可是仍是有不少注意事項的
可選操做符前面的變量必須聲明!若是該操做符前面的變量未聲明,那麼就會引起error
不可過分使用,咱們只須要在可能會引起error的地方使用就好,?.雖好,可不要貪多哦(官方建議,爲啥俺也不知道)
當碰見null
或者undefined
就結束(也就是短路)
可選鏈不能用於賦值,只能用於判斷是否會短路,會短路就返回undefined,不然就返回該key
的值(若是想賦默認值,就要使用它的兄弟??
)
上文說到,可選操做符是不能夠進行賦值操做的,可是它的兄弟能夠呀😎,畢竟葫蘆娃能吐水的就不能吐火呢
在可選操做符和空值合併操做符出現以前,咱們要判斷一個一個屬性是否存在,存在的時候取出它的值,,不存在的時候賦默認值,咱們可能要像下面同樣寫一長串:
console.log(people && people.family && people.family.numbers || '不存在');
複製代碼
每每是極其長而麻煩的,可是如今不同了!
咱們只須要將他們兩兄弟配合使用便可:
console.log(people.family?.number ?? '不存在');
複製代碼
只有當前面爲null或者undefined的時候,會進行空值合併操做,就是賦予後面設定的默認值。
前面講了那麼多,都是很基礎的用法,接下來讓咱們一塊兒學習一下騷操做吧!
在js中,對象裏面能夠包含的東西是不少不少的,因此?.
也不只僅使用在簡簡單單的判斷操做上。他還能夠應用到數組、函數等等一系列操做上
語法:
obj?.prop
obj?.[expr]
arr?.[index]
func?.(args)
複製代碼
開始的兩個簡單的咱們已經學習完了,接下來看看數組和函數的吧!
其實arr?.[index]
從表達式就能夠很清晰的知道,就是獲取arr[index]
元素。以下:
let arr = [1, 2, 3];
console.log(arr?.[5]); // undefined
複製代碼
或許小夥伴們會以爲這個可能很小兒科,就算不用也沒問呀,可是若是是下面這種狀況呢?
let demo = {
}
console.log(demo.a[1]); // ERROR
console.log(demo.a?.[1]); // undefined
複製代碼
若是不進行判斷不就error了嗎?判斷那麼又要像開篇同樣進行一系列枯燥繁瑣的判斷,可是使用?.
不就能夠很快速解決這個問題了?
咱們要獲取的,每每是不只僅只限於數據,有時候咱們可能獲取一些API,可是若是不存在對應的API,照樣會引起異常,在這裏,照樣有解決辦法!
const demo1 = {
func() {
console.log('欸嘿,就不報錯!');
}
}
const demo2 = {
}
demo1.func(); // 欸嘿,就不報錯!
demo2.func(); // TypeError: demo2.func is not a function
複製代碼
咱們使用可選操做符,就能夠完美的避免這個error
const demo1 = {
func() {
console.log('欸嘿,就不報錯!');
}
}
const demo2 = {
}
demo1.func?.(); // 欸嘿,就不報錯!
demo2.func?.(); //
複製代碼
可是在這裏有一個須要你們注意的點,當判斷到存在和函數同名的非函數屬性時,會引起異常
const demo1 = {
func() {
console.log('欸嘿,就不報錯!');
}
}
const demo2 = {
func = 'demo'
}
demo2.func?.(); //
複製代碼
獲取不少小夥伴會以爲在數組和函數的應用上會很彆扭,可是你們結合一下js的執行機制去理解,就會明白爲什麼要這麼寫以及爲什麼存在同名非函數會進行報錯了
其實?.
操做符並非在js獨有,目前在C#,Swift都有,並且TS也加入該新特性。在node.js須要升級到14.0以上才支持(可是通常都會使用Babel進行轉譯,因此徹底不用擔憂啦!)
我是江河,前端實習生一枚,文章若有不正之處,敬請斧正!
面對新事物,咱們要敢於擁抱,只有不斷接受新事物,將新特性爲咱們所用,才能不斷前進,不斷超越!