在平時的開發中,咱們常常會遇到多種運算符在同一個表達式中出現的狀況,尤爲是在三元條件判斷運算符中。javascript
三元條件判斷運算符雖然可讓咱們避免寫過多的if...else條件判斷,但多層三元運算符嵌套,其中又包含其餘不一樣優先級的運算符時,對於閱讀咱們代碼的人來講,簡直就是噩夢。java
今天咱們就結合一個現實中常常用到的工具函數 isEmpty() 的實現,來說解一下如何解讀複雜的運算符嵌套jquery
isEmpty 是 著名的 loadsh 庫提供的一個工具方法,被應用於斷定一個javascript 對象是否爲空對象。segmentfault
對於空對象,loadsh 是這麼解釋的:數組
若是【對象沒有本身的可枚舉字符串鍵控屬性】,則認爲它們是空的, 若是參數、對象、緩衝區、字符串或相似於jquery的集合等【相似數組的值的長度爲0】,則認爲它們爲空。 相似地,若是【映射和集合的大小爲0】,則認爲它們是空的
isEmpty = function (val) { return !(!!val ? typeof val === 'object' ? Array.isArray(val) ? !!val.length : !!Object.keys(val).length : true : false); }
javascript 的運算符優先級能夠參考MDN上的說明,以下圖:框架
咱們再看內部實現代碼,其中val
爲要判斷是否爲空對象的值:函數
return !(!!val ? typeof val === 'object' ? Array.isArray(val) ? !!val.length : !!Object.keys(val).length : true : false);
如今根據運算符優先級一步一步解讀運算過程工具
return
後面應該是一個表達式的值,咱們假定這個值爲X,則整個表達式能夠看作:var X = !(...); return X;
!(...)
X = !Y
Y = !!val ? typeof val === 'object' ? Array.isArray(val) ? !!val.length : !!Object.keys(val).length :true :false
Y = !!val ? typeof val === 'object' ? (true/false) ? !!(0/1/2/.../N) : !!(0/1/2/.../N) :true :false
由於咱們這裏對val
的值不必定,因此這裏對 Array.isArray(val)
和 Object.keys(val).length
最終的計算結果有多種可能,我用/
號隔開了各類可能值,而且將他們放入同一個括號內,若是是正式的計算,咱們傳入的val
是一個肯定的值,那麼這些運算結果也會是一個肯定值,而且也不會有括號。spa
typeof
運算符的優先級都是16,是剩餘運算符中最高的,因此對這兩種進行運算,結果以下:Y = (true/false) ? (string/object/boolean/null/undefined)==='object' ? (true/false) ? (true/false) : (true/false) : true :false
這個地方比較繞,由於!!
會將後面的值強制轉換爲布爾值,因此最後的結果幾乎都是由 true
或false
組成的了。code
Y = (true/false) ?(true/false) ? (true/false) ? (true/false) : (true/false) : true :false
結合性
了,咱們發現條件運算符的結合性是從右至左,那麼咱們的表達式就變成了:Y = (true/false) ? ... : false
咱們回溯如下這裏面的 (true/false)
其實就是原始表達式中 !!val
的運算結果,然而這裏還沒法運算出整個表達式的結果,由於 ...
所表明的那部分還不是一個最終值,還須要運算,記得最開始的作作法嗎?對於!(...)
這個表達式,咱們將括號內的表達式用Y
來代替了,一樣地,咱們把這裏 ...
所表明的表達式部分用一個字母M
來表明,即:
M = (true/false) ? (true/false) ? (true/false) : (true/false) : true; Y = (true/false) ? M : false;
到這裏,計算機就開始判斷了:
!!val
的值爲false
,則直接返回 false
(即括號後面的值),後面的M中的表達式就再也不運算了。那麼此時 Y=false
, 而 !Y
至關於取反,X = !Y
的值就等於true
。咱們這個方法是用來判斷是否爲空對象的,返回結果爲true
,就說明這個val
是空對象。!!val === false
的 val
都有哪些呢? 0
,""
,false
,null
,undefined
符合這個特徵,咱們發發現,它們都是javascript中的‘假值’。!!val
的值爲 true
呢,則須要返回M表達式的結果,咱們就須要繼續計算M表達式的值了。M
表達式的運算過程,依葫蘆畫瓢,咱們能夠獲得:M = (true/fasle) ? ... : true
經過回溯,咱們能夠知道,這裏的(true/false)
其實就是原始表達式中的typeof val === 'object'
的最終運算結果。
一樣的,咱們將 ...
內的內容使用字母 N
代替,結果以下:
N = (true/fasle) ? (true/fasle) : (true/false) M = (true/false) ? N : true;
到這裏,計算機又開始判斷:
typeof val === 'object'
的值爲false
, 即說明val
不是對象類型,則直接返回true
(冒號後面的值),不須要再運算N表達式的結果。此時 Y = true, 則 X= !Y=false, 最終值爲false
,說明val
不是空對象。typeof val === 'object'
的值爲 true
則須要返回N表達式的值做爲結果,計算機須要計算運算N表達式的值。N
表達式,其中有三個布爾值,經過回溯,咱們也能夠知道他們的原始表達式分別是:Array.isArray(val)
!!val.length
!!Object.keys(val).length
那麼咱們知道,這一步當val
爲對象類型時,則須要判斷它是數組仍是非數組:
若是是數組,則拿到數組的長度值,對長度值作!!
操做
0
,則操做結果爲false
, 返回後,Y=false,X=!Y=true,說明 長度爲0的數組爲空對象true
,將結果返回後,Y=true, X=!Y=false,說明長度大於0的數組不屬於空對象若是不是數組,則取它的可枚舉屬性的長度(Object.keys(val).length
),並對長度作!!
操做
0
,則操做結果爲false
, 返回後,Y=false,X=!Y=true,說明 可枚舉屬性長度(個數)爲0的對象爲空對象true
,將結果返回後,Y=true, X=!Y=false,說明可枚舉屬性長度大於0的對象不屬於空對象至此,咱們按照程序執行的順序步進似的完成了整個運算過程的模擬,咱們學到了如下幾點:
理解運算過程對咱們理解整個程序的實現邏輯和做者的思惟方式相當重要,但願以上分析過程能夠在你們閱讀知名框架中大神級代碼時對你們有所幫助。
本文由博客一文多發平臺 OpenWrite 發佈!