• 深拷贝-浅拷贝-引用赋值的写法


    对象相互赋值的一些关系,分别包括:
    • 引入的赋值:指向同一个对象,相互之间会影响;
    • 对象的浅拷贝:只是浅层的拷贝,内部引入对象时,依然会相互影响;
    • 对象的深拷贝:两个对象不再有任何关系,不会相互影响;

    如果有一个对象info,想要拷贝里面的内容,有三种方式。

    1. const info ={
    2. name: "zzz",
    3. age: 18,
    4. friend: {
    5. name: "www"
    6. }
    7. }

    方式一:使用引用赋值

    info和obj1是相同的引用,修改obj1的name也会影响到info的name。

    1. //引用赋值
    2. const obj1 = info
    3. console.log(obj1)

    方式二:浅拷贝

    1. //浅拷贝
    2. const obj2 = {...info}
    3. obj2.name = "jx"
    4. console.log(obj2.name) //jx

    使用展开运算符,拷贝了一个新的对象obj2,修改里面的name,info不会跟着改变。

    1. const obj2 = {...info}
    2. obj2.friend.name = "jx"
    3. console.log(obj2.friend.name) //jx
    4. console.log(info.friend.name) //jx

    但是如果修改的是对象,info的对象也会跟着发生变化。

    浅拷贝可以拷贝原始类型,不能拷贝复杂类型比如对象等。

    还有一种浅拷贝的方式。

    const obj3 = Object.assign({}, info)

    Object.assign方法,将后面的info拷贝到前面的{}对象中,并且返回给obj3。

    方式三:深拷贝

    深拷贝实现方式有两种:使用JSON方法,自己实现

    使用JSON方法

    const obj4 = JSON.parse(JSON.stringify(info))

    这个obj4完全是一个新的对象,修改对象的内容,info的对象内容也不会跟着改变。

    但是使用JSON方法有很大的缺陷就是当info里面有其他的值时。

    1. const info ={
    2. name: "zzz",
    3. age: 18,
    4. friend: {
    5. name: "www"
    6. },
    7. running: function() {},
    8. [Symbol()]: "abc"
    9. }

    深拷贝下来的内容是没有函数和Symbol的。

    我们可以自己手写深拷贝函数

    深拷贝函数的基本类型和对象的实现

    首先需要创建一个函数用来判断一个value是否为对象。

    注意不能用typeof 来判断value是否为null,因为null用typeof判断,出来的是object。

    1. function isObject(value){
    2. const valueType = typeof value
    3. return (value !== null) && (valueType === "function" || valueType === "function")
    4. }
    1. function deepCopy(originValue){
    2. //如果是原始类型就直接返回
    3. if(!isObject(originValue)){
    4. return originValue
    5. }
    6. //创建一个新的对象
    7. const newObj = {}
    8. //遍历要拷贝的对象,取出它的key
    9. //递归 重新判断要拷贝的对象里面是否还有对象
    10. for(const key in originValue){
    11. newObj[key] = deepCopy(originValue[key])
    12. }
    13. //返回新对象
    14. return newObj
    15. }

    关键的代码是,使用递归不断判断要拷贝的对象里面是否还有对象。

    用一个对象来实验一下深拷贝的效果吧。这个对象暂时还没有函数和Symbol类型的判断,后面会做优化的。

    1. const info ={
    2. name: "zzz",
    3. age: 18,
    4. friend: {
    5. name: "www",
    6. address: {
    7. name: "sz",
    8. detail: "lky"
    9. }
    10. },
    11. }
    12. const newObj = deepCopy(info)
    13. console.log(newObj)

    深拷贝成功了!

    深拷贝函数的数组拷贝

    有时候我们需要拷贝数组,在JavaScript中,数组也是一个对象,上面的代码中创建的是一个新的对象,但不一定要创建的是新对象,也有可能是新数组,所以需要先区分对象和数组,再创建对象或者数组。

    1. function isObject(value) {
    2. const valueType = typeof value
    3. return (value !== null) &&(valueType === "object" || valueType ==="function")
    4. }
    5. function deepCopy(originValue) {
    6. //如果是原始类型就直接返回
    7. if(!isObject(originValue)) {
    8. return originValue
    9. }
    10. //判断是数组还是对象
    11. const newObj = Array.isArray(originValue)? [] :{}
    12. for(const key in originValue){
    13. newObj[key] = deepCopy(originValue[key])
    14. }
    15. return newObj
    16. }

     关键的一步是通过Array的isArray判断传入的是对象还是数组。

     我们创建一个books数组来验证一下是否可以判断对象还是数组来拷贝。

    1. const books = [
    2. { name:"book1", price: 1 },
    3. { name:"book2", price: 2 },
    4. { name:"book3", price: 3 },
    5. ]
    6. const newArray = deepCopy(books)
    7. console.log(newArray)

    拷贝的是一个数组。

    深拷贝函数的Set拷贝

    有的时候,深拷贝的内容有Set,如果不知道Set是什么的话,可以看这篇JavaScript中Set的使用,Set和数组类似,但是Set的元素是不能重复的,所以它常用于去重。

    创建一个set,把它放进info对象里面。

    1. const set = new Set(["zzz", "wjx", "lky"])
    2. const info = {
    3. name: "zzz",
    4. age: 18,
    5. friend: {
    6. name: "www",
    7. address: {
    8. name: "sz",
    9. detail: "lky"
    10. }
    11. },
    12. set: set
    13. }
    1. function isObject(value) {
    2. const valueType = typeof value
    3. return (value !== null) &&(valueType === "object" || valueType ==="function")
    4. }
    5. function deepCopy(originValue) {
    6. //如果是原始类型就直接返回
    7. if(!isObject(originValue)) {
    8. return originValue
    9. }
    10. //判断是否是set
    11. if(originValue instanceof Set) {
    12. const newSet = new Set()
    13. for(const setItem of originValue) {
    14. newSet.add(deepCopy(setItem))
    15. }
    16. return newSet
    17. }
    18. //判断是数组还是对象
    19. const newObj = Array.isArray(originValue)? [] :{}
    20. for(const key in originValue){
    21. newObj[key] = deepCopy(originValue[key])
    22. }
    23. return newObj
    24. }

     先判断传入的值是不是Set,创建新的Set,遍历Set,把遍历的元素一个个放到新的Set里面。

    可以拷贝Set了。

    深拷贝函数的函数返回

    函数是不需要深拷贝的,因为函数是用来执行的,如果再拷贝一个函数,会消耗性能。 

    1. if(typeof originValue === "function") {
    2. return originValue
    3. }

    所以遇到函数的时候直接返回了。

  • 相关阅读:
    【管理运筹学】第 10 章 | 排队论(1,排队论的基本概念)
    【PAT甲级】1022 Digital Library
    自幂数的统计
    每日刷题记录 (二十)
    在虚拟机上在线安装mysql
    HashMap在JDK1.7中多线程并发会出现死循环,超详细图解
    Mysql:事务
    Libgdx游戏开发(4)——显示中文文字
    MySQL 数据库 定义参数【连接查询】
    手机app开发可选技术——React Native
  • 原文地址:https://blog.csdn.net/m0_51636525/article/details/126519416