美文网首页前端面试基础
JS 基本数据类型和引用数据类型的区别及浅拷贝和深拷贝

JS 基本数据类型和引用数据类型的区别及浅拷贝和深拷贝

作者: alokka | 来源:发表于2020-03-18 18:28 被阅读0次

    JS基本数据类型和引用数据类型

    再讲 js 的基本数据类型和引用数据类型之前,我们先说一下栈和堆的概念

    1、栈(stack)和堆(heap)

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

    2、基本数据类型和引用数据类型

    基本数据类型NumberStringBooleanNullUndefinedSymbol(ES6),这些类型可以直接操作保存在变量中的实际值

    基本数据类型特点:

    1. 占用空间固定,保存在栈中
      (当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,
      这个方法的内存栈也将自然销毁了。因此,所有在方法中定义的变量都是放在栈内存中的;栈中存储的是基础变量以及一些对象的引用变量,
      基础变量的值是存储在栈中,而引用变量存储在栈中的是指向堆中的数组或者对象的地址,这就是为何修改引用类型总会影响到其他指向这个地址
      的引用变量)

    2. 保存与复制的是值本身

    3. 使用typeof检测数据的类型

    4. 基本类型数据是值类型

    引用数据类型Object(在JS中除了基本数据类型以外的都是对象,数据是对象,函数是对象,正则表达式是对象)

    引用数据类型特点:

    1. 占用空间不固定,保存在堆中
      (当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大)
      ,这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),
      则这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。)

    2. 保存与复制的是指向对象的一个指针

    3. 使用instanceof检测数据类型

    4. 使用new()方法构造出的对象是引用型

    3、基本数据类型(NumberStringBooleanNullUndefinedSymbol(ES6))存放在

    • 基本数据类型是指存放在栈中的简单数据段,数据大小确定,内存空间大小可以分配,它们是直接按值存放的,所以可以直接按值访问
    var a = 1;
    var b = a;
    b = 2;
    console.log(a); // 1
    console.log(b); // 2
    

    栈内存

    在这里插入图片描述

    4、引用数据类型(Object)存放在

    • 引用类型是存放在堆内存中的对象,变量其实是保存的在栈内存中的一个指针(保存的是堆内存中的引用地址),这个指针指向堆内存
    • 引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址。通过这个引用地址可以快速查找到保存中堆内存中的对象
      var a = {
        name: 'lily',
        age: '16'
      }
    
      var b = a;
      b.name = 'lokka';
    
      console.log(a); // {name: "lokka", age: "16"}
    

    把 a 赋值给 b ,就相当于把 a 的内存地址指向 b ,即 a 和 b 指向同一内存地址, 改变了 b 就相当于改变了 a

    在这里插入图片描述

    浅拷贝和深拷贝

    1、概念

    浅拷贝:只拷贝一层,深层次的对象级别只拷贝引用。
    深拷贝:拷贝多层,每一级别的数据都会被拷贝出来。

    2、浅拷贝的实现方式

    1. 方法一:通用循环
    function shallowCopy(obj) {
      if (typeof obj !== 'object') return;
    
      const newObj = obj instanceof Array ? [] : {};
    
      for(let key in obj) {
        if (obj.hasOwnProperty(key)) {
          newObj[key] = obj[key];
        }
      }
    
      return newObj;
    }
    
    1. 方法二:Object.assign
    const newObj = Object.assign({}, oldObj);
    
    1. 方法三:Array.slice
    const newArray = oldArray.slice();
    
    1. 方法四:Array.concat
    const newArray = oldArray.concat();
    
    1. 方法五:es6
    const { ...newObj } = oldObj;
    const [ ...newArray ] = oldArray;
    

    3、深拷贝的实现方式

    1. 方法一:通用循环
    function deepCopy(obj) {
      if (typeof obj !== 'object') return;
    
      const newObj = obj instanceof Array ? [] : {};
    
      for(let key in obj) {
        if (obj.hasOwnProperty(key)) {
          newObj[key] = typeof obj === 'object' ? deepCopy(obj[key]) : obj[key];
        }
      }
    
      return newObj;
    }
    
    1. 方法二:JSON.parse、JSON.stringify
    const newObj = JSON.parse(JSON.stringify(oldObj));
    

    相关文章

      网友评论

        本文标题:JS 基本数据类型和引用数据类型的区别及浅拷贝和深拷贝

        本文链接:https://www.haomeiwen.com/subject/abmcyhtx.html