js中 给一个多层嵌套的object对象赋值需要十分小心, 一不小心就很容易出现undefined错误, 因为给一个object里深层对象赋值时, 需要确保整个object链路能够到达, 否则就会报undefined错误, 例如以下代码:
let a = {}
a.b.c.d = {} // 会报错 因为链路无法到达d
常见的解决方法有
- 逐层判断赋值
let a = {}
if (!Object.prototype.hasOwnProperty.call(a, 'b')) {
a.b = {}
}
if (!Object.prototype.hasOwnProperty.call(a.b, 'c')) {
a.b.c = {}
}
...
缺点: 层数比较多的时候 代码会非常啰嗦
- 以key值链路数组递归赋值
let a = {}
let keys = ['b', 'c', 'd', 'e']
let temp = a
keys.forEach(key => {
if (!Object.prototype.hasOwnProperty.call(temp, key)) {
temp[key] = {}
}
temp = temp[key]})
})
缺点: 需要把key链路变成数组 写起来会比较麻烦 因为常用的object用法是 a.b.c.d... 或者 a['b']['c']['d']... 转成数组 会额外增加心智开销
那么有没有一种方案, 可以实现
深层递归赋值
不影响原有的object的书写方式 原来的a.b.c.d... 或者 a['b']['c']['d']... 不需要修改
结合javascript的Proxy方法 形成如下方案:
class ObjectUtil {
constructor (keys = []) {
let obj = {}
const fix = this.fix.bind(this)
const value = this.value.bind(this)
obj.fix = fix
obj.value = value
obj = new Proxy(
obj,
{
get (target, p, receiver) {
if (target[p] !== fix && target[p] !== value) {
if (!Object.prototype.hasOwnProperty.call(target, p)) {
const k = JSON.parse(JSON.stringify(keys))
k.push(p)
target[p] = new ObjectUtil(k)
}
}
return Reflect.get(...arguments)
}
}
)
this._keys = keys
return obj
}
fix (obj) {
let a = obj
for (const k of this._keys) {
if (!Object.prototype.hasOwnProperty.call(a, k)) {
a[k] = {}
}
a = a[k]
}
return a
}
value (obj) {
let a = obj
let value
const keys = this._keys.reverse()
for (let k = keys.pop(); k !== undefined; k = keys.pop()) {
if (!Object.prototype.hasOwnProperty.call(a, k)) {
break
}
if (keys.length === 0) {
value = a[k]
}
a = a[k]
}
return value
}
}
使用:
const a = {
a: {},
aa: {}
}
const temp = new ObjectUtil()
let c = temp.a.b.c.fix(a)
console.log(a) // { a: { b: { c: {} } }, aa: {} }
let d = temp.a.b.d.fix(a)
console.log(a) // { a: { b: { c: {}, d: {} } }, aa: {} }
c,d = 1
let d = temp.a.b.c.d.value(a)
// d: 1
let e = temp.a.b.c.e.value(a)
// e: undefined
原理:
使用Proxy获取到object的key链路 比如obj.a.b.c.d key链路就是 a->b->c->d
new ObjectUtil() 会创建一个 Proxy对象
Proxy对象的get方法, 会获取到此对象的直属key, 然后判断目标对象在key上是否有value 如果没有 递归创建一个new ObjectUtil()
get (target, p, receiver) {
if (target[p] !== fix && target[p] !== value) {
if (!Object.prototype.hasOwnProperty.call(target, p)) {
const k = JSON.parse(JSON.stringify(keys))
k.push(p)
target[p] = new ObjectUtil(k)
}
}
return Reflect.get(...arguments)
}
然后根据链路递归赋值
以上就是处理javascript Object对象深层嵌套自动赋值的一种思路, 如果有更好的方法, 可以留言讨论