試想一下,如何在一個多層對象嵌套的對象中取某一項的值,你可能會這樣寫
deviceInfo.customerService.mobile
如果customerService
為空酪耳,那程序就崩了。那再加上安全判斷
if(deviceInfo && deviceInfo.customerService){
return deviceInfo.customerService.mobile;
}
這樣確實是安全了刹缝,但是如果Object
不止3層呢葡兑?4層5層6層甚至更多,是不是要寫一個無比長的if
判斷赞草?并且這樣寫非常不優(yōu)雅讹堤,可讀性也不好。這時候厨疙,就需要使用到 lodashjs 的get
方法洲守。
import _ from 'lodash'; // es6中的寫法,通用寫法為var _ = require('lodash');
// ...
return _.get(deviceInfo, "customerService.mobile", "nothing");
get
方法接收三個參數(shù)Object
沾凄、Path
和defaultValue
梗醇,Path
可以接收數(shù)組["customerService","mobile"]
或者字符串"customerService.mobile"
靠瞎。如果path
中有一項為undefined
贴捡,則會返回defaultValue
的值。
注意瓤鼻,如果鍵值是null
的話保屯,是不會返回defaultValue
的手负,因為null !== undefined
涤垫,在最后一個鍵值為null
的時候需要特別注意下。
可以看一下get
的源碼實現(xiàn):
function get(object, path, defaultValue) {
var result = object == null ? undefined : baseGet(object, path);
return result === undefined ? defaultValue : result;
}
get
里面的邏輯很簡單竟终,根據(jù)object == null
返回undefined
或者baseGet
函數(shù)執(zhí)行蝠猬,再根據(jù)result === undefined
返回默認值或者result
本身,這里就說明了為什么鍵值為null
不會返回defaultValue
统捶。
接下來看baseGet
做了什么:
function baseGet(object, path) {
path = castPath(path, object);
var index = 0,
length = path.length;
while (object != null && index < length) {
object = object[toKey(path[index++])];
}
return (index && index == length) ? object : undefined;
}
baseGet
調(diào)用了castPath
生成一個path
數(shù)組榆芦,然后遍歷這個數(shù)組,對object
進行取值喘鸟,直到為null
或者遍歷結(jié)束匆绣。簡單說,就是根據(jù)path
對object
一層一層的取值什黑。toKey
是將一些非字符串類型轉(zhuǎn)為字符串犬绒。
castPath
函數(shù)負責(zé)將path
轉(zhuǎn)成數(shù)組:
function castPath(value, object) {
if (isArray(value)) {
return value;
}
return isKey(value, object) ? [value] : stringToPath(toString(value));
}
如果value
是數(shù)組,則直接返回兑凿。isKey
判斷value
是否是唯一鍵名凯力,不是則返回stringToPath
。emmmm礼华,castPath
也只是做了一層過濾咐鹤,具體實現(xiàn)還在stringToPath
函數(shù)中。
var stringToPath = memoizeCapped(function(string) {
var result = [];
if (string.charCodeAt(0) === 46 /* . */) {
result.push('');
}
string.replace(rePropName, function(match, number, quote, subString) {
result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));
});
return result;
});
memoizeCapped
是一個高階函數(shù)圣絮,對參數(shù)函數(shù)包裝了一層緩存功能祈惶,具體可參考_.memoize(func, [resolver])。
if
語句中判斷首字母如果是.
扮匠,push
了一個空字符串捧请,因為js
中用""
來做鍵名是允許的,比如
{"":{b:{c:666}}}
棒搜。之后調(diào)用string的replace
方法疹蛉,利用正則表達式rePropName
:
let rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
主要匹配.
及[]
,將字符串path
轉(zhuǎn)為數(shù)組力麸,比如a.b.[1].c
可款,則會轉(zhuǎn)成數(shù)組['a', 'b', '1', 'c']
,然后baseGet
則利用這些key
進行取值克蚂。
關(guān)于數(shù)組越界的問題闺鲸,js
中數(shù)組越界會返回undefined
,而baseGet
的循環(huán)體中使用object != null
非!==
埃叭,undefined != null
為假摸恍,當(dāng)object
為undefined
時,則會跳出循環(huán)體赤屋,最終返回defaultValue
立镶。
在 lodashjs 中壁袄,還有很多很實用的方法,部分api在ES6中也有實現(xiàn)谜慌,比如:Array.indexOf
、Object. assign
莺奔。不妨多看看其具體實現(xiàn)欣范。