注册会员
×

已有账号? 请点击

使用其他方式登录

JS中浅拷贝与深拷贝区别,对象或数组实现深拷贝几种方法

发布2021-07-14 浏览60次

详情内容

作为前端程序员,经常会遇到js页面赋值问题,JS中浅拷贝与深拷贝区别,对象或数组实现深拷贝几种方法。

浅克隆(浅拷贝)

在数据类型为引用类型的时候,当你给这个变量赋值,其实是引用这个变量在内存中的地址。如下:

var obj = {name: 'ccc', age: 18}    // 定义一个变量为对象,引用类型
var cloneObj = obj      // 创建一个新变量,并赋值
console.log(cloneObj)   // {name: 'ccc', age: 18}  
console.log(cloneObj === obj)   // true

浅克隆带来的问题:

var obj = {name: 'ccc', age: 18}    // 定义一个变量为对象,引用类型
var cloneObj = obj      // 创建一个新变量,并赋值
console.log(cloneObj)   // {name: 'ccc', age: 18}  
console.log(cloneObj === obj)   // true

obj.name = 'www'
console.log(cloneObj)   // { name: 'www', age: 18 }

我们可以发现,我们修改了obj变量的属性值的时候,cloneObj的属性值也跟着发生了变化。原因是他们虽然是两个变量,但是引用的变量是同一个变量。看下图分析:

image.png

深度克隆(深拷贝)

深度克隆,就是解决浅度克隆带来的问题的。直接上代码:

function deepClone(o) {
    // 判断如果不是引用类型,直接返回数据即可
    if (typeof o === 'string' || typeof o === 'number' || typeof o === 'boolean' || typeof o === 'undefined') {
        return o
    } else if (Array.isArray(o)) { // 如果是数组,则定义一个新数组,完成复制后返回
        // 注意,这里判断数组不能用typeof,因为typeof Array 返回的是object
        console.log(typeof [])  // --> object
        var _arr = []
        o.forEach(item => { _arr.push(item) })
        return _arr
    } else if (typeof o === 'object') {
        var _o = {}
        for (let key in o) {
            _o[key] = deepClone(o[key])
        }
        return _o
    }
}

var arr = [1, 2, 3, 5]
var cloneArr = deepClone(arr)
console.log(cloneArr)   // --> [ 1, 2, 3, 5 ]
console.log(arr === cloneArr)   // --> false

var obj = { name: 'ccc', age: 18 }
var cloneObj = deepClone(obj)
console.log(cloneObj)   // --> { name: 'ccc', age: 18 }
console.log(obj === cloneObj)   // false
obj.name = 'www'
console.log(obj)    // --> { name: 'www', age: 18 }
console.log(cloneObj)   // --> { name: 'ccc', age: 18 }

obj和cloneObj分别指向自己所存的变量地址,互不影响,代码注释挺详细了,看下图:

image.png

以下有几种深拷贝的方法:

一、对象深拷贝

1. 使用递归的方式实现深拷贝

function deepClone(obj){
  let objClone =  Array.isArray(obj) ? [] : {};
  if (obj && typeof obj === 'object') {
    for(let key in obj){
      if (obj[key] && typeof obj[key] === 'object'){
        objClone[key] = deepClone(obj[key]);
      }else{
        objClone[key] = obj[key]
      }
    }
  }
  return objClone;
}

2. 通过JSON对象实现深拷贝 

let _obj = JSON.parse(JSON.stringify(obj));

注意: 无法实现对象中方法的深拷贝

3. 通过Object.assign()拷贝

let obj = {name: 'ccc', age: 18};
let _obj = Object.assign({},obj)

注意: 当对象只有一级属性为深拷贝;

当对象中有多级属性时,二级属性后就是浅拷贝


二,数组深拷贝的几种方法

1. concat(arr1, arr2,....)

注意:当数组中的元素均为一维是深拷贝

数组中元素一维以上是值的引用



2. slice(idx1, idx2)

参数可以省略

1)没有参数是拷贝数组

2)只有一个参数是从该位置起到结束拷贝数组元素

3)两个参数,拷贝从起始位置到结束位置的元素(不包含结束位置的元素:含头不含尾)

注意:当数组中的元素均为一维是深拷贝

数组中元素一维以上是值的引用


点击QQ咨询
开通会员
返回顶部
×
  • 微信支付
  • 支付宝付款
微信扫码支付
微信扫码支付
请使用微信描二维码支付
×

提示信息