精华内容
下载资源
问答
  • JS深拷贝和浅拷贝

    千次阅读 2021-01-21 23:01:40
    浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用。 浅拷贝是拷贝的内存地址,使新对象指向拷贝对象的内存地址。深拷贝是重新开辟一块内存空间,用来存放sources对象的值。 浅拷贝可以用for in 来实现,也可用es6...

     

    1. 浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用。
    2. 浅拷贝是拷贝的内存地址,使新对象指向拷贝对象的内存地址。深拷贝是重新开辟一块内存空间,用来存放sources对象的值。
    3. 浅拷贝可以用for in 来实现,也可用es6新增方法Object.assign(target,...sources) 来实现,target为目标对象,sources为原对象(要进行拷贝的对象)
    4. 浅拷贝后改变target中的值,sources也会进行改变。深拷贝不会这样
    5. 深拷贝可以基于函数封装的方法来进行实现。
    <body>
        <script>
            var obj = {
                id: 1,
                name: 'andy',
                msg: {
                    age: 18
                }
            };
            var o = {};
            var j = {};
            function shallowCopy(newobj, oldobj) {
                for(var k in oldobj){
                    newobj[k] = old[k];
                }
            }
            shallowCopy(o, obj);
            console.log('o',o)
            o.id = 2;
            console.log('obj',obj)
            //封装深拷贝函数
            function deepCopy(newobj, oldobj) {
                for (var k in oldobj) {
                    //判断属性值属于那种数据类型
                    //1.获取属性值 old[k]
                    var item = oldobj[k];
                    //2. 判断这个值是否是数组
                    //必须先判断是否是Array 因为Array 也是Object
                    if(item instanceof Array){
                        newobj[k] = [];
                        deepCopy(newobj[k], item);
                    }else if(item instanceof Object){
                        //3.判断这个值是否是对象
                        newobj[k] = {};
                        deepCopy(newobj[k], item);
                    } else {
                        //4.属于简单数据类型
                        newobj[k] = item;
                    }
                }
            }
            deepCopy(j,obj);
            console.log('j',j);
            j.id = 4;
            console.log('obj',obj);
        </script>
    </body>

    存在不足之处可随时补充。

    学习地址

    展开全文
  • js 深拷贝和浅拷贝

    2021-03-18 15:12:29
    JS中数据类型 基本数据类型: undefined、null、Boolean、Number、StringSymbol(ES6) 引用数据类型: Object(Array, Date, RegExp, Function) ...浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象,如果

    JS中数据类型

    • 基本数据类型: undefined、null、Boolean、Number、String和Symbol(ES6)
    • 引用数据类型: Object(Array, Date, RegExp, Function)

    深浅拷贝

    深浅拷贝只是针对引用类型的,因为引用类型是存放在堆内存中,在栈地址有一个或者多个地址来指向推内存的某一数据

    浅拷贝:

    被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。

    浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象,如果你修改了“副本”的值,那么原来的对象也会被修改

    深拷贝:

    深拷贝是一个整个独立的对象拷贝,深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。

    深拷贝把要复制的对象所引用的对象都复制了一遍。如果你修改了“副本”的值,那么原来的对象不会被修改,两者是相互独立的。

    深拷贝实现方式可拷贝function 和 symbol 以及undefined:

    // 深拷贝
    function deepCopy(obj) {
      if (!obj && typeof obj !== 'object') {
        throw new Error('error arguments');
      }
      // const targetObj = obj.constructor === Array ? [] : {};
      const targetObj = Array.isArray(obj) ? [] : {};
      for (let key in obj) {
        
        //只对对象自有属性进行拷贝
        if (obj.hasOwnProperty(key)) {
          if (obj[key] && typeof obj[key] === 'object') {
            targetObj[key] = deepCopy(obj[key]);
          } else {
            targetObj[key] = obj[key];
          }
        }
      }
      return targetObj;
    } 
    
    //测试
    
     let a = {
        age: undefined,
        sex: Symbol('male'),
        jobs: function() {
            console.log('kkkk')
        },
        name: 'yck'
    }
    
    var cloneA = deepCopy(a);
    console.log(cloneA.age);
    console.log(cloneA.sex);
    cloneA.jobs();

     

    展开全文
  • 主要介绍了JavaScript深拷贝和浅拷贝概念与用法,结合实例形式较为详细的分析了javascript深拷贝浅拷贝的概念、原理、用法及相关操作技巧,需要的朋友可以参考下
  • 换成js代码就变成了基本数据类型引用数据类型的拷贝。 在JavaScript中我们定义的简单数据类型会存到栈(stack)内存中,包括引用类型的指针,而这个指针指向的地方是在堆(heap)内存中。也通常理解为,简单数据类型...

    目录

    一、理解拷贝

    二、基本数据类型拷贝

    三、浅拷贝(shallow  clone)

    对象浅拷贝

    (1)依次赋值

    (2)for..in 遍历

    (3)Object.assign(目标对象,要拷贝的对象)

    (4)展开运算符

    缺陷:只能拷贝外层不能拷贝内层

     数组浅拷贝

    (1)依次赋值

    (2)展开运算符

    (3)slice

    (4)map

    四、深拷贝

    对象数组深拷贝

    (1)递归

    (2)JSON.parse(JSON.stringify())


    一、理解拷贝

    拷贝就像我们平常cv一些文件、代码 复制了一份新的就叫拷贝。 换成js代码就变成了基本数据类型和引用数据类型的拷贝。

    在JavaScript中我们定义的简单数据类型会存到栈(stack)内存中,包括引用类型的指针,而这个指针指向的地方是在堆(heap)内存中。也通常理解为,简单数据类型存在栈中,引用数据类型存在堆中

    二、基本数据类型拷贝

    基本数据类型没什么好说的,通过一个变量赋值给一个变量就已经拷贝完成了

            let a = 1
            let b = a

     把a赋值给b之后 再去操作a并不会影响b   你可以理解为 a 和b 是两个不同的区域,但都是存在栈内存里。

            let a = 1
            let b = a
            a=5
            console.log(b); //1
            console.log(a); //5

    三、浅拷贝(shallow  clone)

    浅拷贝只能拷贝复杂数据类型的指针,并不能改变复杂数据类型的地址,只能拷贝外层,并不能彻底拷贝,例如数组中还有数组(对象),(准确来说是外层引用数据类型)

    对象浅拷贝

    (1)依次赋值

    优点:数量较少的时候使用方便、简单,缺点:遇到对象或数组键比较多时,操作不方便

            let obj = {
                a: {name: 'abc'},
                b: 2
            }
            let newObj = {}
            newObj.a=obj.a
            newObj.b=obj.b

    (2)for..in 遍历

            let obj = {
                a: {name: 'abc'},
                b: 2
            }
           let newObj = {} 
           for (const key in obj) {
              newObj[key]=obj[key]
           }

    (3)Object.assign(目标对象,要拷贝的对象)

            let obj = {
                a:{name:'奥特曼'},
                b:2
            }
            let newObj= {}
            Object.assign(newObj,obj)

    (4)展开运算符

             let obj = {
                a: {name: 'abc'},
                b: 2
            }
            let newObj = {}
            newObj = {...obj}

    缺陷:只能拷贝外层不能拷贝内层

    浅拷贝只能拷贝最外层的引用地址,并不能拷贝内层的引用地址  

    修改最内层的数据 另一个也会改变,因为指针指向的的都是同一个内存地址

            newObj.a.name='bcd'
            console.log(obj);    //a: {name: "bcd"}, b: 2
            console.log(newObj); //a: {name: "bcd"}, b: 2

     数组浅拷贝

    (1)依次赋值

            let arr  =  [1,{name:'abc'}]
            let newArr = []
            newArr[0]=arr[0] 
            newArr[1]=arr[1] 

    (2)展开运算符

            let arr  =  [1,{name:'abc'}]
            let newArr = [...arr]

    (3)slice

           let arr  =  [1,{name:'abc'}]
            let newArr = arr.slice(0)

    (4)map

            let arr  =  [1,{name:'abc'}]
            let newArr = arr.map(it=>it)

    同样修改数组中内存的数据 另一个数组的内存数据也会改变

            arr[1].name='bcd' 
            console.log(arr);// 1, {name: "bcd"}
            console.log(newArr);// 1, {name: "bcd"}

    四、深拷贝

    深拷贝:不光外层的引用地址该变了 内层的引用数据类型也发生改变

    对象数组深拷贝

    (1)递归

       obj = { 
                a: {name: 'abc'},
                b: 2 
             }
            function fn(obj) {
                let newObj = {}
                // 如果不是对象直接返回 
                if(typeof obj !=='object'){
                    return '不是一个对象'
                }else {
                    // 是对象就对每一项进行遍历 
                    for (const key in obj) {
                        // 判断内部是否为对象  如果不是对象就进行递归 
                        if(typeof obj[key] ==='object'){
                            newObj[key]=fn(obj[key])
                        }else{
                            newObj[key]=obj[key]
                        }
                    }
                }
                return newObj
            }

    优化 

      obj = {
                a: { name: 'abc'  },
                b: 2
            }
            function fn(obj) {
                let newObj = {}
                if(typeof obj !=='object') return '不是一个对象'
                    for (const key in obj) {
                        typeof obj[key] ==='object'? newObj[key]=fn(obj[key]): newObj[key]=obj[key]
                        }
                return newObj
            }
             let newObj = fn(obj)

     这时候在修改对象里面的引用类型时 就不会影响另一个对象

            newObj.a.name='bcd'
            console.log(obj);
            console.log(newObj);

    (2)JSON.parse(JSON.stringify())

         let newObj = JSON.parse(JSON.stringify(obj))

    这个深拷贝我们经常会在网上看到,但也不是没有缺陷 

      obj = {
                a:NaN,
                b: undefined,
                c:new Date(),
                d:new RegExp(/\d/),
                d:new Error(),
                e:Infinity
            }
            console.log(obj);
            let newObj = JSON.parse(JSON.stringify(obj))
            console.log(newObj);

    对比图

    JSON.parse(JSON.stringify())拷贝后的缺陷:

    • NaN          ===》null
    • undefined ===》 空
    • 时间戳      ===》字符串时间
    • 错误信息  ===》 空对象
    • Infinity      ===》null

    展开全文
  • 深拷贝 JSON.parse(JSON.stringify(obj))深拷贝已有对象 JSON.stingify(obj)将js中的对象转换成JSON字符串 let jack = { name: 'jack' } console.log(jack) console.log(JSON.stringify(jack)) 它们在格式上有...

    1、概念

    深拷贝与浅拷贝在其它语言中也经常被提及到,因为它们分别对应着值拷贝与引用拷贝。
    深拷贝:从字面上的意思理解,是指很深的拷贝,到底有多深呢?深到不仅拷贝值,而且还独立开辟了一个空间。我的理解是:拷贝的过程中,独立地开辟了一个空间,这个对象指向这个地址,与原来的对象互不干扰。深拷贝也被称为值拷贝。
    浅拷贝:从字面上的意思理解,是指比较浅的拷贝,它与原来的变量仍然指向同一个地址,两者之间相互影响,即其中一个改变会影响另一个的改变。浅拷贝也被称为引用拷贝,引用的意思就是取了个别名,例如张三是大名,狗蛋是他的引用,即为小名,张三变了,狗蛋自然也变了,因为他们本质上就是指同一个人

    2、js中的深拷贝(值拷贝)

    js中的基本数据类型:String Number Boolean Null Undefined,在赋值的过程中都是值拷贝.
    例如,let a = 10 ; b = a , 修改其中一个变量的值,不会影响到另一个变量的值

    3、js中的浅拷贝(引用拷贝)

    js中的对象数据类型:Object Array Function Map Set,在赋值过程中都是引用拷贝

    let obj = {
         name: '静如秋叶',
         age: 3,
         height: 100
     }
     let obj2 = obj
     obj2.name = '小花'
     console.log(obj)    // {name: '小花‘, age: 3, height: 100}
     console.log(obj2)   // {name: '小花‘, age: 3, height: 100}
    

    当修改obj2的name属性时,也会修改obj的name,因为它们指向同一块地址。

    4、将浅拷贝转换成深拷贝

    在实际的项目开发过程中,我们在多数情况下不希望将对象进行浅拷贝,因为值会相互影响,容易出错。这里主要讲js中的Array和Object类型从浅拷贝转换成深拷贝。

    4.1 Array的深拷贝

    4.1.1 通过slice方法

    slice()操作数组时,不会对原数组有影响,会产出一个新的数组。

     let arr1 = [1, 42, 5, 6]
     let arr2 = arr1.slice()
     arr2[0] = 100
     console.log(arr1) // [1, 42, 5, 6]
     console.log(arr2) // [100, 42, 5, 6]
    

    数组arr2的改变未引起arr1的变化

    4.1.2 通过concat方法

    数组的concat()方法,能够连接两个数组,同样不会改变原来的数组。用一个空数组连接另一个数组,即可实现深拷贝。

    let arr3 = ['cat', 'dog', 'pig']
    let arr4 = [].concat(arr3)
    arr3[2] = 'big pig'
    console.log(arr3) // ['cat', 'dog', 'big pig']
    console.log(arr4) // ['cat', 'dog', 'pig']
    

    4.1.3 通过ES6语法中 …

    ES6语法中的 …, 我经常在数组的深拷贝中用到。

    let arr5 = [0, 0, 1]
    let arr6 = [...arr5]
    arr5[0] = 10000
    console.log(arr5) // [10000, 0, 1]
    console.log(arr6) // [0, 0, 1]
    

    4.1.4 通过Array.from方法

    Array.from()方法能从一个类似数组或可迭代对象中返回一个新的数组实例。通过Array.from()方法能获取到一个数组的深拷贝。

    let arr7 = [1, 2, 3]
    let arr8 = Array.from(arr7)
    arr7[1] = 1000
    console.log(arr7) // [1, 1000, 3]
    console.log(arr8) // [1, 2, 3]
    

    4.2 Object的深拷贝

    4.2.1 通过Object.assign()方法

    ES6的Object.assign() Object.assign(target, …sources)用于对象的合并,将源对象中的所有可枚举属性,复制到目标对象中,并返回合并后的目标对象。后来的源对象的属性值,将会覆盖它之前的对象的属性。

     let person = {
         name: 'xia',
         age: 25,
         height: 160
     }
     let otherPerson = Object.assign({}, person)
     person.age = 30
    
     console.log(person)
     console.log(otherPerson)
    

    5、万能转换器(对Array和Object等都适用)

    前面讲解了 Array和Object的深拷贝方法,但是对于有更深层次的结构关系(数组套数组 数组套对象 对象套对象等),上面的方法就失灵了,可以看下面的例子。

    let personArr = [{name: 'xia'}, {name: 'zhang'}]
    let otherPersonArr2 = [...personArr]
    personArr[0].name = 'xia xia'
    console.log(personArr)
    console.log(otherPersonArr2)
    

    在这里插入图片描述

    万能转换器 JSON.parse(JSON.stringify(obj))深拷贝已有对象,它可以深拷贝多层级的,不用担心嵌套问题。

    • JSON.stringfy() 将对象序列化成json对象
    • JSON.parse() 反序列化——将json对象反序列化成js对象

    JSON.stingify(obj)将js中的对象转换成JSON字符串

     let jack = {
         name: 'jack'
     }
     console.log(jack)
     console.log(JSON.stringify(jack))
    

    它们在格式上有区别。下图中的第一个是对象,name没有双引号括起来。第二个是json字符串,其中,name用双引号括起来了
    在这里插入图片描述

    JSON.parse()将json字符串解析成对象

     let obj = {
         name: '静茹秋叶'
     }
     console.log('obj: ', obj)
     console.log('json string: ', JSON.stringify(obj))
    
     let str = JSON.stringify(obj)
     console.log('--------------')
     console.log(str)
     console.log('str to obj: ', JSON.parse(str))
    

    在这里插入图片描述

    6、Vue中的浅拷贝与深拷贝

    两个button-counter共用同一个jack对象,用同一块地址,当其中一个实例改变时,会影响另一个实例的值。(浅拷贝)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vue的data选项</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">
            <button-counter></button-counter>
            <button-counter></button-counter>
        </div>
    
        <script>
            let jack = {
                counter: 0
            }
            // 子组件
            Vue.component('button-counter', {
                data() {
                    // 函数类型
                    return jack
                },
                template: `<button @click="counter++">click {{counter}} times</button>`
            })
            let vm = new Vue({
                el: '#app' // mount到DOM上
            })
        </script>
    </body>
    </html>
    

    采用深拷贝,重新创建一块内存。这样,vue的button-counter组件中的counter值互不影响。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vue的data选项</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">
            <button-counter></button-counter>
            <button-counter></button-counter>
        </div>
    
        <script>
            let jack = {
                counter: 0
            }
            // 子组件
            Vue.component('button-counter', {
                data() {
                    // 函数类型
                    return JSON.parse(JSON.stringify(jack))
                },
                template: `<button @click="counter++">click {{counter}} times</button>`
            })
            let vm = new Vue({
                el: '#app' // mount到DOM上
            })
        </script>
    </body>
    </html>
    

    (例子来源于《Vue.js从入门到项目实战》书籍)


    郑重感谢wesbos(仓库地址:https://github.com/wesbos/JavaScript30),本文的浅拷贝与深拷贝的方法来源于此仓库,谢谢他的无私!

    展开全文
  • 文章目录1、深拷贝浅拷贝概览2、赋值、深拷贝浅拷贝区别3、浅拷贝实现方式3.1 Object.assign()3.2 Array.prototype.concat()3.3 Array.prototype.slice()4、深拷贝实现方式4.1 JSON.parse(JSON.stringify(arr))...
  • 结合实际工作场景深入理解Javascript深拷贝和浅拷贝的特性,Javascript深拷贝浅拷贝理解,数组、对象实现设深拷贝的不同方式
  • 浅拷贝和深拷贝都是对于JS中的引用类型而言的,浅拷贝就只是复制对象的引用,如果拷贝后的对象发生变化,原对象也会发生变化。只有深拷贝才是真正地对对象的拷贝
  • js深拷贝和浅拷贝

    2021-03-23 14:01:56
    一、按值操作(深拷贝) 以下javascript的基本类型, 复制后,修改一个变量的值时,不会影响其他变量的值。 string number boolean null undefined 例如: let age1 = 100; //number类型 let age2 = age1; //值的...
  • 浅拷贝 ```对象复制 Object.assign() const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); // 返回 {a:1, b:2, c:3} target // {a:1, b:2, c...
  • 拷贝和浅拷贝最根本的区别在于是否是真正获取了一个对象的复制实体,而不是引用,深拷贝在计算机中开辟了一块内存地址用于存放复制的对象,而浅拷贝仅仅是指向被拷贝的内存地址,如果原地址中对象被改变了,那么...
  • javascript深拷贝和浅拷贝以及实现方法(推荐)

    千次阅读 多人点赞 2021-07-08 23:06:05
    拷贝和浅拷贝的区别? 浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用。 深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来...
  • 如何区分深拷贝浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。1. 如果是基本数据...
  • 浅拷贝的实现
  • JavaScript的变量中包含两种类型的值:基本类型值 和 引用类型值,这篇文章主要介绍了JS中实现浅拷贝和深拷贝,需要的朋友可以参考下
  • js深拷贝和浅拷贝的区别 如何来区分深拷贝和浅拷贝,其实简单,例如: 就是我声明一个obj对象,如何让var a直接等于obj,然后有在obj新增个fun,此时的a也会随着新增个fun,相同a新增数据,obj也会改变,这就是浅拷贝...
  • 二 说到深浅拷贝的时候就不得不说一下JS中的变量类型了: 基本类型: undefined、null、boolean、number、string, 按值存放在栈内存中的简单数据段, 可以直接访问. 引用类型: 存放在堆内存中的对象,
  • 深拷贝和浅拷贝

    2021-01-23 23:17:17
    使用深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同一个内存的错误。 浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。 深复制:在计算机中开辟一块新...
  • 老生常谈js的拷贝问题,今天就简单来聊聊js深拷贝和浅拷贝的问题,故事要从js对数据的存储开始说起。话说很久很久之前。。。。。。,js的存储分为堆(heap)和栈(stack)两种存储类型。 一、数据的存储方式,基本...
  • 深拷贝和浅拷贝 浅拷贝和赋值 深拷贝 1. 递归实现 2. 通过JSON对象实现深拷贝 3. 通过jQuery的extend方法实现深拷贝 4. Object.assign()拷贝 5. lodash函数库实现深拷贝
  • 面试题目:如何实现对一个数组或对象的浅拷贝和深拷贝?WTF,复制还分两种,第一次遇到这种问题的时候很是无语呢,先来看看一般的答案的理解。浅拷贝是只拷贝一层,深层次的对象级别就只拷贝引用。 深拷贝是拷贝多层...
  • JS 深拷贝和浅拷贝

    2021-11-18 19:10:44
    浅拷贝 基本类型赋值,引用类型赋值堆地址 function shallowCopy(variable){ var result ={}; for(var i in variable){ if(variable.hasOwnProperty(i)){ result[i] = variable[i]; } } return result; }...
  • 文章目录一、理解拷贝二、浅拷贝(shallow clone)对象浅拷贝数组浅拷贝三、深拷贝对象数组深拷贝 一、理解拷贝 拷贝分为:基本数据类型引用数据类型的拷贝。 浅拷贝:拷贝了基本数据类型,对象数据的引用; 深拷贝:...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 24,385
精华内容 9,754
关键字:

js深拷贝和浅拷贝