温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么解决JavaScript的深浅拷贝

发布时间:2022-01-26 15:29:49 来源:亿速云 阅读:115 作者:iii 栏目:开发技术

这篇文章主要讲解了“怎么解决JavaScript的深浅拷贝”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么解决JavaScript的深浅拷贝”吧!

正文

从一则故事讲起,昨天因为医院开不出药,我拿上药取小区药店去买药,进门之后我问老板有没有这个药,老板转身进去一个小屋子拿了一盒药,果不其然确实有,药的名字和毫克一摸一样,但是盒子的样子和厂商不一样,我问老板:“这两个药是一种药吗,盒子不一样啊,药的成分是一样的吗?”老板说当然一样啊,这个就和你去买猪肉一样,同样是猪身上的肉,只不过是你去这个超市和去其他超市买场地一样而已。最后为了安全起见,我还是没有买那个药。

"拷贝"分为浅拷贝和深拷贝。它是针对对象来说的,如果不是对象一切免谈。这里的对象可以理解为我拿的那盒药,浅拷贝可以理解为老板拿出来的那盒药,虽然药的名字和毫克一样,然后里面的我们不知道是否真的一样,可能一样可能不一样。深拷贝可以理解为我买到了一摸一样的药,一层一层的药名,毫克,厂商,成分都一样。

总结:

  • 浅拷贝就是针对对象的属性依次进行复制,只复制一层,不会递归到个属性复制,会产生引用问题即内存地址是指的同一地址。简单来说就是拷贝之后和原对象有关

  • 深拷贝就是针对对象的各属性递归复制到新的对象上,内存地址不会指向同一地址。简单来说就是拷贝之后和元对象无关

下面看一个浅拷贝的例子:

let school={'name':"W3Cschool"};
let my = {age:{count:18},name:"W3Cschool亿速云"};
let all = {...school,...my};
my.age.count=100;
console.log(all);
console.log(my);

结果:

{ age: { count: 100 }, name: 'W3Cschool亿速云' }
{ age: { count: 100 }, name: 'W3Cschool亿速云' }

结论是:浅拷贝修改拷贝之后的对象上的属性会把原对象身上的属性同时修改掉。

下面再看一个深拷贝的例子:

const _ = require("loadsh")
let my = {age:{count:18},name:"W3Cschool亿速云"};
let all = _.cloneDeep(my);
all.age.count =100;
console.log(my);
console.log(all);

结果:

{ age: { count: 18 }, name: 'W3Cschool亿速云' }
{ age: { count: 100 }, name: 'W3Cschool亿速云' }

结论是:深拷贝修改拷贝之后的对象上的属性不会把原对象身上的属性同时修改掉。

拷贝的方法

1.数组方法:slice和concat

  • slice

let arr = [1,2,3,4];
let arr2 = arr.slice(0)
arr2[2]=5;


console.log(arr);  //[ 1, 2, 3, 4 ]
console.log(arr2); //[ 1, 2, 5, 4 ]

当数组里是不是对象的时候从结果上看是深拷贝,在看下面例子

let arr = [{1:1,2:2}];
let arr2 = arr.slice(0)
arr2[2]=5;


console.log(arr);  //[ { '1': 1 }, { '2': 5 } ]
console.log(arr2); //[ { '1': 1 }, { '2': 5 } ]

当数组里是对象的时候就变成了浅拷贝

  • concat

let arr = [1,2,3,4];
let arr2 = [].concat(arr);
arr2[2]=5;
console.log(arr); //[ 1, 2, 3, 4 ]  ✔
console.log(arr2); //[ 1, 2, 5, 4 ]

当数组里不是对象的时候从结果上看是深拷贝,在看下面例子

let arr = [{1:1},{2:2}];
let arr2 = arr.cancat(0)
arr2[1][2]=5;


console.log(arr);  //[ { '1': 1 }, { '2': 5 } ]  ❌变成了引用
console.log(arr2); //[ { '1': 1 }, { '2': 5 } ]

当数组里是对象的时候就变成了浅拷贝

总结:只有当数组是一维数组而且不包含对象的时候才是深拷贝

(推荐教程:JavaScript教程)

2.Object.assgin()

let a= {a:1,b:2};
let b= Object.assign({},a);
a.a=3;
console.log(a)  //{a: 3, b: 2}
console.log(b)  //{a: 1, b: 2}  ✔
let a= {a:1,b:{c:2}};
let b= Object.assign({},a);
a.b.c=3;
console.log(a)  //{a: 1, b: {c:3}}
console.log(b)  //{a: 1, b: {c:3}}   ❌变成了引用

总结:Object.assgin如果涉及到嵌套多个对象的话就变成了引用 解决方法:使用JSON.stringify()先转化成字符串,再通过JSON.parse()转化成对象

  • 3.JSON.parse(JSON.stringify())

let a= {a:1,b:{c:2}};
let b= JSON.parse(JSON.stringify(a))
a.b.c=3;
console.log(a)  //{a: 1, b: {c:3}}
console.log(b)  //{a: 1, b: {c:2}}   ✔
let school={'name':"W3Cschool亿速云",fn:function(){}};
let my = {age:{count:18},name:"W3Cschool亿速云"};
let all=JSON.parse(JSON.stringify({...school,...my}))
console.log(all);  //{'name':"W3Cschool亿速云",age:{count:18}}; //❌把fn给丢了

总结: JSON.parse(JSON.stringify()) 这个方法有一定的局限性,会丢失 fn 。

  • 4.手写深拷贝

let deepClone=(obj)=>{
    if(obj==undefined) return obj;  //undefined == null
    if(obj instanceof RegExp) return new RegExp(obj);
    if(obj instanceof Date) return new Date(obj);
    if(typeof obj!=="object") return obj;
    let newObj = new obj.constructor;
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            newObj[key] = deepClone(obj[key])
        }
    }
    return newObj;
}
let obj1 = {name:{age:"10"}}
let n = deepClone(obj1)
obj1.name.age = "231"
console.log(n);  //{name:{age:"10"}}  ✔
let obj = { name:"W3Cschool亿速云" }
obj.aaa=obj
let n = deepClone(obj1)
console.log(n);  //死循环了  ❌

解决这个问题可以使用WeakMap

let deepClone=(obj,hash=new WeakMap())=>{
    if(obj==undefined) return obj;  //undefined == null
    if(obj instanceof RegExp) return new RegExp(obj);
    if(obj instanceof Date) return new Date(obj);
    if(typeof obj!=="object") return obj;
    if(hash.has(obj)) return hash.get(obj);
    let newObj = new obj.constructor;
    hash.set(obj,newObj);


    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            newObj[key] = deepClone(obj[key],hash)
        }
    }
    return newObj;
}
  • 5.lodash的cloneDeep

<br> 源码地址:https://github.com/lodash/lodash/blob/86a852fe763935bb64c12589df5391fd7d3bb14d/.internal/baseClone.js
<br> ```
  • 6.vue-router源码中的克隆方法

function clone (value) {
  if (Array.isArray(value)) {
    return value.map(clone)
  } else if (value && typeof value === 'object') {
    const res = {}
    for (const key in value) {
      res[key] = clone(value[key])
    }
    return res
  } else {
    return value
  }
}
let arr = [{1:1},{2:2},function(){}];
let arr2 = clone(arr)
arr2[1][2]=5;
console.log(arr)  //[ { '1': 1 }, { '2': 2 }, [Function (anonymous)] ]   ✔ 深拷贝
console.log(arr2); //[ { '1': 1 }, { '2': 5 }, [Function (anonymous)] ]
function extend (a, b) {
  for (const key in b) {
    a[key] = b[key]
  }
  return a
}
let b={a:1,b:{c:2}};
let a= extend({},b);
a.b.c=5;
console.log(a);  //{ a: 1, b: { c: 5 } }
console.log(b);  //{ a: 1, b: { c: 5 } }   浅拷贝

感谢各位的阅读,以上就是“怎么解决JavaScript的深浅拷贝”的内容了,经过本文的学习后,相信大家对怎么解决JavaScript的深浅拷贝这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI