動機:平時寫js程式碼時經常遇到要使用 lodash 中 _.get 和 _.set 的情況,每次使用都要引用 lodash,總感覺很煩,能不能自己實現一個簡單的方法來實現一樣的功能呢?
get 方法實現
- get 方法接受三個引數,第一個是目標物件或者陣列,第二個是獲取值的路徑,第三個是獲取失敗時的預設值
function get(object, path, defaultValue) {
// 判斷 object 是否是陣列或者物件,否則直接返回預設值 defaultValue
if (typeof object !== 'object') return defaultValue
// 沿著路徑尋找到對應的值,未找到則返回預設值 defaultValue
return _basePath(path).reduce((o, k) => (o || {})[k], object) || defaultValue
}
// 處理 path, path有三種形式:'a[0].b.c'、'a.0.b.c' 和 ['a','0','b','c'],需要統一處理成陣列,便於後續使用
function _basePath(path) {
// 若是陣列,則直接返回
if (Array.isArray(path)) return path
// 若有 '[',']',則替換成將 '[' 替換成 '.',去掉 ']'
return path.replace(/\[/g, '.').replace(/\]/g, '').split('.')
}
set 方法實現
- set 方法同樣接受三個引數,第一個是源物件或者源陣列,第二個是設定值的路徑,第三個是value
function set(object, path, value) {
if (typeof object !== 'object') return object;
_basePath(path).reduce((o, k, i, _) => {
if (i === _.length - 1) { // 若遍歷結束直接賦值
o[k] = value
return null
} else if (k in o) { // 若存在對應路徑,則返回找到的物件,進行下一次遍歷
return o[k]
} else { // 若不存在對應路徑,則建立對應物件,若下一路徑是數字,新物件賦值為空陣列,否則賦值為空物件
o[k] = /^[0-9]{1,}$/.test(_[i + 1]) ? [] : {}
return o[k]
}
}, object)
// 返回object
return object;
}
測試
let obj = { a: [{ b: { c: 6 } }] }
console.log(get(obj, 'a[0].b.c', '預設值')) // 6
console.log(get(obj, 'a.5.b.c', '預設值')) // '預設值'
console.log(get(obj, ['a', '0', 'b', 'c'], '預設值')) // 6
let obj1 = { a: [{ b: { c: 6 } }] }
let obj2 = { }
let obj3 = { }
set(obj1, 'a[0].b.c', '預設值')
set(obj2, 'a.0.b.5.c', '預設值')
set(obj3, ['1', '2', 'b', 'c'], '預設值')
console.log(JSON.stringify(obj1)) // {"a":[{"b":{"c":"預設值"}}]}
console.log(JSON.stringify(obj2)) // {"a":[{"b":[null,null,null,null,null,{"c":"預設值"}]}]}
console.log(JSON.stringify(obj3)) // {"1":[null,null,{"b":{"c":"預設值"}}]}