JS基础系列之赋值及深拷贝、浅拷贝

338 阅读3分钟

放在开头

了解深浅拷贝及赋值,需要的前置知识:js的数据类型、js中的堆栈概念

js的数据类型 :基本数据类型、引用数据类型

  • 基本数据类型包含:String Number Boolean Undefined null(其中null是一个历史遗留问题,typeof null //object,null类型被当做一个空对象引用。这里不做延伸)
  • 引用数据类型 : Function Object Array

js中的堆栈概念

  • 栈:会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间,同时存放引用数据类型的的指针。其数据结构是线性的,后进先出
  • 堆:动态分配的内存,大小不定也不会自动释放,存放引用类型,指那些可能由多个值构成的对象,保存在堆内存中,包含引用类型的变量,实际上保存的不是变量本身,而是指向该对象的指针。其数据结构是混乱的

定义及区别

  • 赋值:赋值运算符向 JavaScript 变量赋值。基本数据类型将值直接赋值给变量,且互不影响;引用数据类型将指针赋值给变量,相互影响
    • 例子
      // 基本数据类型赋值
      var a = 1
      var b = a
      //当 a = 2  输出a -> 2  b -> 1
      // 引用数据类型赋值
      var c = [1,2,3,4]
      var d = c
      //当 c[0] = 2  输出c -> [2,2,3,4] d -> [2,2,3,4]
      
  • 浅拷贝:在堆中创建一个新对象,这个新对象的属性值从源对象对应属性中直接赋值。基本数据类型的属性直接赋值给对应属性引用数据类型的属性将指针赋值给对应属性,因此,基本数据类型的属性互不影响,引用数据类型的属性将会受到影响
    • 例子
      var obj1 = {
         a:123,
         b:[[1,2],3]
      }
      function clone(obj){
         var cloneobj={}
         for (var key in obj) {
              if (Object.hasOwnProperty.call(obj, key)) {
                  cloneobj[key] = obj[key];
              }
          }
          return cloneobj
      }
      var obj2 = clone(obj1)
      /**
      * var obj2 = {
      *    a:123,
      *    b:[[1,2],3]
      * }
      */
      
      //  当obj1.a = 234 输出 obj1.a -> 234 obj2.a -> 123
      //  当obj1.b[0][0] = 2 输出 obj1.b -> [[2,2],3] obj2.b -> [[2,2],3]
      //  当obj1.b[1] = 4 输出 obj1.b -> [[1,2],4] obj2.b -> [[1,2],4]
      
  • 深拷贝:在堆中创建一个新对象,这个新对象是根据源对象复制出来的,是两个不同指针的对象,相互不影响。
    • 例子
      var obj1 = {
         a:123,
         b:[[1,2],3]
      }
      function deepclone(obj){
         var cloneobj = new obj.constructor() // obj.constructor 通过构造函数创建这个值,不做延伸
         if (obj === null) return obj
         if (obj instanceof Date) return new Date(obj)
         if (obj instanceof RegExp) return new RegExp(obj)
         if (typeof obj !== 'object') return obj
         for (var key in obj) {
              if (Object.hasOwnProperty.call(obj, key)) {
                  cloneobj[key] =deepclone(obj[key]);
              }
          }
          return cloneobj
      }
      var obj2 = deepclone(obj1)
      /**
      * var obj2 = {
      *    a:123,
      *    b:[[1,1,],1]
      * }
      */
      //  当obj1.a = 234 输出 obj1.a -> 234 obj2.a -> 123
      //  当obj1.b[0][0] = 2 输出 obj1.b -> [[2,2],3] obj2.b -> [[1,2],3]
      //  当obj1.b[1] = 4 输出 obj1.b -> [[1,2],4] obj2.b -> [[1,2],3]
      

总结

  • 赋值不是浅拷贝,就只是赋值 简单数据类型的值,引用数据类型的指针(索引)
  • 浅拷贝只能获得源对象第一层的原始数据(简单数据类型的值,引用数据类型的指针(索引)),当源对象中的引用数据类型值发生变化,拷贝对象也会受到影响
  • 深拷贝的两个对象互不影响
第一篇文章,如果有不对的地方欢迎大家指正,共同学习,共同进步。

ps:喜欢点个赞吧,后续不定期总结