JS 属性不可修改属性,不可循环时如何深拷贝对象

242 阅读1分钟
  • Object.create({}, { p: { value: 10 })创建一个对象,默认情况下已下三个数据为false
  • configurable: false, //能否使用delete、能否需改属性特性、或能否修改访问器属性、,false为不可重新定义,默认值为true
  • enumerable: false, //对象属性是否可通过for-in循环,false为不可循环,默认值为true
  • writable: false, //对象属性是否可修改,false为不可修改,默认值为true

所有在进行深拷贝的情况下需要使用Object.getOwnPropertyDescriptors() 方法获取对象属性增加到拷贝对象中

代码展示


//  深拷贝
function deepCopy(obj, parent = null) {
  let result
  let _parent = parent
  // 该字段有父级则需要追溯该字段的父级
  while (_parent) {
    // 如果该字段引用了它的父级,则为循环引用
    if (_parent.originalParent === obj) {
      // 循环引用返回同级的新对象
      return _parent.currentParent
    }
    _parent = _parent.parent
  }
  if (obj && typeof (obj) === 'object') {
    if (obj instanceof RegExp) {
      result = new RegExp(obj.source, obj.flags)  
    // source 属性返回一个值为当前正则表达式对象的模式文本的字符串,该字符串不会包含正则字面量两边的斜杠以及任何的标志字符。
    //   flags 属性返回一个字符串,由当前正则表达式对象的标志组成
    } else if (obj instanceof Date) {
      result = new Date(obj.getTime())
    } else {
      if (obj instanceof Array) {
        result = []
      } else { 
        // 返回指定对象的原型 
        result = Object.create(
          Object.getPrototypeOf(obj),
          Object.getOwnPropertyDescriptors(obj)
        )
      }
      for (let i in obj) {
          if (obj[i] && typeof (obj[i]) === 'object') {
            // 递归执行深拷,将同级的待拷贝对象传递给parent,方便追溯循环引用
          result[i] = deepCopy(obj[i], {
            originalParent: obj,
            currentParent: result,
            parent: parent
          })
        } else {
          result[i] = obj[i]
        }
      }
    }
  } else {
    return obj
  }
  return result
}

const obj = Object.create({}, { p: { value: 10 , configurable: true, writable: false, enumerable: false} })
console.log(Object.getOwnPropertyDescriptors(obj), 8)
const obj2 = deepCopy(obj)
console.log(Object.getOwnPropertyDescriptors(obj2))

打印如下

image.png