美文网首页
JavaScript 之深浅拷贝

JavaScript 之深浅拷贝

作者: 临安linan | 来源:发表于2019-11-08 20:03 被阅读0次

更多个人博客:(https://github.com/zenglinan/blog)

如果对你有帮助,欢迎star。

对象拷贝是经常会遇到的场景, 本文会总结几种深浅拷贝的方法

一. 浅拷贝

1. 浅拷贝的定义

先来说说什么是浅拷贝, 首先要明确一点:

直接拷贝对象的引用这不叫浅拷贝

先来看一个案例:

拷贝引用:

var obj1 = {
  a: 1,
  b: {
    c: 1
  }
}

var obj2 = obj1  // 拷贝 obj1 的引用

obj2.a = 2
console.log(obj1.a)  // 2

浅拷贝:

var obj1 = {
  a: 1,
  b: {
    c: 1
  }
}

var obj2 = {...obj1}

obj2.a = 2
console.log(obj1.a)  // 1

上面可以看到, 直接复制引用时, 两个对象实际保存的是堆中同一个对象的引用, 而浅拷贝则不同, 浅拷贝重新生成了一个新的对象, 但是浅拷贝只会拷贝一层, 假如原对象的属性值为对象, 也只会拷贝这个对象的引用。

也就是说: 在浅拷贝的对象中, 修改基本类型的值不会影响原数据, 修改复杂类型时, 会影响原数据

2. 浅拷贝的实现

(1) ...扩展运算符

var copy = {...obj} 

ES6 中提供了扩展运算符, 可以遍历取出对象身上的属性, 分配到新的对象上

(2) Object.assign

var copy = {}
Object.assign(copy, obj)

Object.assign 可以将第二个对象里可枚举的属性复制到第一个对象里

(3) for...in

function shallowCopy(src){
  let result = {}
  for(let prop in src){
    if(src.hasOwnProperty(prop)){
      result[prop] = src[prop]
    }
  }
  return result
}

注意: for...in 循环会遍历原型链上所有的的属性, 浅拷贝只需拷贝对象身上的属性。

所以加一层 hasOwnProperty 判断

二. 深拷贝

1. 深拷贝的定义

与浅拷贝相比, 深拷贝也会对对象的子对象进行拷贝

当修改拷贝对象上的对象属性时, 不会对源对象产生影响

2. 深拷贝的实现

(1) JSON序列化与反序列化

最先说的办法当然是家喻户晓的 JSON 序列化与反序列化方法啦~

var copy = JSON.parse(JSON.stringify(src))

先序列化一下对象变成字符串, 然后再反序列化成对象

这个办法有两个缺陷:

  1. 既然是 JSON 对象上的方法, 当然不支持拷贝函数了o(╥﹏╥)o

  2. 同样的道理, JSON 里面没有 Symbol 类型, 自然也不支持 Symbol 类型的键

但是这个方法最简单了, 一行代码...

(2) for...in + 递归

function deepClone(src){
  if(typeof src !== "object") return src

  let result = Array.isArray(src) ? [] : {}

  for(let prop in src){
    if(!src.hasOwnProperty(prop)) continue
    let value = src[prop]
    result[prop] = typeof value === 'object' ? deepClone(value) : value
  }
  return result
}

这个方法比 JSON 序列化的方法更完善的一点是: 支持拷贝函数

但是依然无法拷贝键为 Symbol 类型的属性

原因是: for...in 无法遍历到 Symbol 类型的属性

(3) Reflect.ownKeys() + 递归

MDN 上是这样描述的:

Reflect.ownKeys 方法返回一个由目标对象自身的属性键组成的数组。它的返回值等同于

Object.getOwnPropertyNames(target)
.concat(Object.getOwnPropertySymbols(target))

这个方法可以取到对象自身的所有属性, 包括 Symbol 类型的属性

function deepClone(src){
  if(typeof src !== 'object') return src

  let result = Array.isArray(src) ? [] : {} 
  Reflect.ownKeys(src).forEach((key) => {
    let value = src[key]
    result[key] = typeof value === 'object' ? deepClone(value) : value
  })
  return result
}

相关文章

  • JavaScript 之深浅拷贝

    更多个人博客:(https://github.com/zenglinan/blog) 如果对你有帮助,欢迎star...

  • Javascript(五)之深浅拷贝

    进阶路线 需要知道的就是一点:JavaScript的数据类型分为基本数据类型和引用数据类型。对于基本数据类型的拷贝...

  • JavaScript专题之深浅拷贝

    一、拷贝示例 当我们在操作数据之前,可能会遇到这样的情况: 会经常改动一组数据,但可能会用到原始数据 我需要两组一...

  • 『JavaScript专题』之深浅拷贝

    前言 拷贝也是面试经典呐! 数组的浅拷贝 如果是数组,我们可以利用数组的一些方法比如:slice、concat 返...

  • js之深浅拷贝

    js之深浅拷贝 标签(空格分隔): javascript 说在前面 javascript中的变量类型分为两大类,基...

  • javascript深浅拷贝

    Javascript有六种基本数据类型(也就是简单数据类型),它们分别是:Undefined,Null,Boole...

  • javascript深浅拷贝

    underscore 的源码中,有很多地方用到了 Array.prototype.slice() 方法,但是并没有...

  • JavaScript深浅拷贝

    简单讲呢,深浅拷贝,都是进行复制,那么区别主要在于复制出来的新对象和原来的对象是否会互相影响,改一个,另一个也会变...

  • Javascript深浅拷贝

    浅拷贝 1.基本数据类型 是存在栈中的,所以=赋值,都会创建一个新的空间,例如 变量b有自己独立的空间 2.对象数...

  • JavaScript深浅拷贝

    原文链接 http://blog.poetries.top/2018/12/21/js-deep-copy/ 关注...

网友评论

      本文标题:JavaScript 之深浅拷贝

      本文链接:https://www.haomeiwen.com/subject/cliwbctx.html