0

0

0

修罗

站点介绍

只有了解事实才能获得真正的自由

js深拷贝、Object.create

修罗 2021-12-21 2948 5条评论 JS

首页 / 正文

js深拷贝

实现深拷贝

定义方法deepClone,参数为对象类型(除几个基本类型外都是对象类型)

const deepClone = function (obj, hash = new WeakMap()) {
  if (obj.constructor === Date) {
    return new Date(obj) // 日期对象直接返回一个新的日期对象
  }
  
  if (obj.constructor === RegExp){
    return new RegExp(obj) //正则对象直接返回一个新的正则对象
  }
  
  // 如果循环引用了就用 weakMap 来解决
  if (hash.has(obj)) {
    return hash.get(obj)
  }

  // 浅拷贝对象
  let allDesc = Object.getOwnPropertyDescriptors(obj)
  // 遍历传入参数所有键的特性
  let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)

  // map存当前对象,obj必须为对象类型,因为WeakMap键必须是对象类型
  hash.set(obj, cloneObj)

  for (let key of Reflect.ownKeys(obj)) { 
    cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key], hash) : obj[key]
  }
  return cloneObj
}

// 判断是不是Object类型
const isComplexDataType = obj => typeof obj === 'object' && (obj !== null)
  • 定义方法传入对象,遍历属性拷贝到另一个对象,使用 Reflect.ownKeys 方法能够遍历对象的不可枚举属性以及 Symbol 类型;
  • 当参数为 Date、RegExp 类型,则直接生成一个新的实例返回;
  • Object.create 方法创建一个新对象,并继承传入原对象的原型链;利用 ObjectgetOwnPropertyDescriptors 方法可以获得对象的所有属性描述,再传给Object.create第二个参数,拷贝原对象。
  • 利用 WeakMap 类型存储拷贝对象,如果存在循环,则引用直接返回 WeakMap 存储的值;因为 WeakMap 是弱引用类型,可以有效防止内存泄漏。

测试

let obj = {
  num: NaN,
  str: '',
  boolean: false,
  undef: undefined,
  nul: null,
  obj: { name: 'huiyani', age: 20, desc: { hobby: "打电动" } },
  arr: [1, 2, 3],
  func: function () { console.log('huiyani') },
  date: new Date(),
  reg: new RegExp('/huiyani/ig'),
  [Symbol('huiyani')]: "huiyani",
};

Object.defineProperty(obj, 'innumerable', {
  enumerable: false, value: '不可枚举属性' }
);

obj = Object.create(obj, Object.getOwnPropertyDescriptors(obj))
obj.loop = obj // 设置loop成循环引用的属性

let cloneObj = deepClone(obj)
cloneObj.arr.push(4)
cloneObj.obj.desc.hobby = "又在打电动"

console.log('obj', obj)
console.log('cloneObj', cloneObj)

我们看一下结果,cloneObjobj 的基础上进行了一次深拷贝,cloneObj 里的 arr 数组和obj对象进行了修改,并未影响到 obj.arrcloneObj.obj对象的变化,如下图所示

1640019870611.png

Object.create

1、参数传对象,返回一个对象,原型指向传入对象

let obj = Object.create({a:1})

console.log(obj)

1640016435320.png

2、传null,返回一个没有原型的对象

let obj1 = Object.create(null)

console.log(obj1)

1640016499615.png

3、传入属性描述符对象,默认属性描述配置为false

let obj2 = Object.create({}, { p: { value: 42 } })

console.log(obj2)

1640016706957.png

获取返回对象的属性描述符

console.log(Object.getOwnPropertyDescriptors(obj2))

1640016731035.png

writable:属性的值是否能够被重新赋值

configurable:是否可以删除该属性

enumerable:此属性是否可以被枚举(使用for…in或Object.keys())

4、配置属性描述符

let des = { p: { value: 42, writable: true, enumerable: true, configurable: true } }

let obj3 = Object.create({}, des)

console.log(Object.getOwnPropertyDescriptors(obj3))

1640016954767.png

5、create方法第二个参数为一个对象的属性描述符

let obj4 = { a:1, b:2 }
let obj5 = { c:3, d:4 }

let obj6 = Object.create(obj4, Object.getOwnPropertyDescriptors(obj5))

console.log(obj6)
console.log(Object.getOwnPropertyDescriptors(obj6))

1640017156299.png
1640017206825.png

6、第一个参数传入类型决定返回类型

let desc = Object.getOwnPropertyDescriptors([1,2,3])
// 传入对象返回对象
let clone = Object.create({}, desc) // clone: {0: 1, 1: 2, 2: 3, length: 3}
// 传入数组返回数组
let clone = Object.create([], desc) // clone: [1, 2, 3]

评论(5)

  1. 1 游客 2025-09-01 11:27 回复

    1

  2. 1 游客 2025-09-01 12:13 回复

    1

  3. @@rHrYe 游客 2025-09-01 12:15 回复

    1

  4. 1 游客 2025-09-01 12:17 回复

    1

  5. 1 游客 2025-09-01 12:18 回复

    1


最新评论

  • https://www.studyglobus.com/author/carroll34a5552/

    Ценники на вывоз мусора сейчас космос, любые лайфхаки по экономии в тему.

  • Richardgrold

    1xbet onlayn kazino platforması ilə vaxtınızı daha səmərəli və maraqlı keçirin. Saytın canlı kazino bölməsi istifadəçilərə fərqli bir dünya təklif edir. Burada canlı dilerli kazino oyunlarının hər bir növünü sınaqdan keçirə bilərsiniz. Krupyelərin peşəkarlığı oyunun dinamikasını və marağını artırır. Müntəzəm olaraq yenilənən oyun siyahısı cansıxıcılığa yol vermir. Hesabınızı artırmaq üçün onlarla fərqli və etibarlı üsul mövcuddur. Qazanılan pullar cəmi bir neçə dəqiqə ərzində şəxsi hesabınıza köçürülür. Aktiv fəaliyyətinizə görə fərdi bonuslar və hədiyyələr qazana bilərsiniz. Dəstək xidməti həm çat, həm də e-poçt vasitəsilə kömək göstərir. 1xbet ailəsinə qoşulun və böyük uduşlar üçün ilk addımı atın. onlayn kazino

  • 砂岩白丘

    我一直梦想, 看到你们相册那样的地方。真棒。

  • 城市地標

    我喜欢, 这里分享真实经验。你的项目 就是 属于这里的。请继续。

  • 宗教地標

    我热爱这样的想法, 去那么多国家。真的很鼓舞。

  • 觀景高地

    能感受到热爱。继续保持 感受。

  • 最佳季節

    我关注这样的资源, 写得很实在。你的网站 就是 属于这里的。加油。

  • 1

    1

  • 1

    1

  • -1' OR 2+158-158-1=0+0+0+1 or 'TKCTZnRa'='

    1

日历

2026年07月

   1234
567891011
12131415161718
19202122232425
262728293031 

文章目录

推荐关键字: Linux webpack js 算法 MongoDB laravel JAVA jquery javase redis