javascript Object对象深层嵌套自动赋值

js中 给一个多层嵌套的object对象赋值需要十分小心, 一不小心就很容易出现undefined错误, 因为给一个object里深层对象赋值时, 需要确保整个object链路能够到达, 否则就会报undefined错误, 例如以下代码:

let a = {}
a.b.c.d = {}  // 会报错 因为链路无法到达d

常见的解决方法有

  1. 逐层判断赋值
let a = {}
if (!Object.prototype.hasOwnProperty.call(a, 'b')) {
  a.b = {}
}
if (!Object.prototype.hasOwnProperty.call(a.b, 'c')) {
  a.b.c = {}
}
...

缺点: 层数比较多的时候 代码会非常啰嗦

  1. 以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']... 转成数组 会额外增加心智开销

那么有没有一种方案, 可以实现

  1. 深层递归赋值

  2. 不影响原有的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对象深层嵌套自动赋值的一种思路, 如果有更好的方法, 可以留言讨论

你可能感兴趣的:(javascript Object对象深层嵌套自动赋值)