JavaScript引用数据类型

144 阅读4分钟

JavaScript引用数据类型

mountain-7011121_1280.webp

引用数据类型与基本数据类型不同,它们在内存中的存储方式更为复杂。在栈中存放的是数据的地址,而具体的值则存储在堆中JavaScript中引用数据类型主要就是对象(Object) ,所有引用类型的原型链最终都指向 Object.prototype

一、引用数据类型的特点

  1. 存放位置

    基本数据类型值在内存中占据固定大小,直接存储在栈内存中,而引用数据类型的数据存储在堆内存中其变量绑定存储的是对堆内存位置的引用。而这个地址存放在栈内存中。

    不是所有引用都存储在栈内存

    • 只有当前执行上下文中的局部变量的引用会存储在栈内存
    • 闭包变量、全局变量的引用实际存储在堆内存中的变量环境中

    这是由于堆内存适合存储大小不固定、可能动态增长的数据结构,引用数据类型符合这一特征

v2-cb9bf4612af0fa67e5e64d255aa741ba_r.png

  1. 值可变性

    引用数据类型的值是可以修改的(与基本数据类型的不可变性相对),而基本数据类型修改值时实际上是创建了一个新值并赋给变量。

    由于变量存储的是引用(内存地址),所以在修改数据时不会影响引用。并且引用可以存放相同地址,所以多个变量可以共享同一个对象。

    // 可变
    const obj = {
        name: '张三',
        age: 18
    }
    obj.name = '李四'
    console.log(obj.name) // 李四
    
    // 多个变量可以共享同一个对象
    const pers = obj // 浅拷贝 拷贝的是对象的地址
    pers.age = 30
    console.log(obj.age) // 30
    

    引用共享带来的问题

    多个变量共享同一个对象容易造成对象被意外修改的问题,在不改变原对象的基础上修改对象属性可以通拷贝来实现。

    拓展运算符浅拷贝{ ...obj } 表示创建一个新对象,并将 obj 的所有可枚举属性展开到新对象中

    const person = {
        name: '张三',
        age: 18,
        sex: '男',
        friends: ['李四', '王五', '赵六']
    }
    const cp = {...person} // 浅拷贝
    cp.name = 'LiSi'
    console.log(person.name) // 张三
    console.log(cp.name) // LiSi
    
  2. 引用数据类型之间的比较

    基本数据类型之间是值的比较,而引用数据类型之间是比较的是引用比较(地址比较)。看其的引用是否指向同一个对象

    let a = 0
    let b = 0
    console.log(a === b) // true
    
    const arr1 = [1,2,3]
    const arr2 = [1,2,3]
    console.log(arr1 === arr2) //false 
    

    arr1arr2虽然是内容相同的数组,但是他们在内存中的地址是不同的,他们所指向的对象不相同

二、主要引用数据类型

  1. 对象 (Object)

    最基本的引用类型,用于存储键值对集合。这里的值可以可以是任何类型的数据(基本数据类型和引用数据类型都行),但是键只能是字符串或Symbol,其他类型自动转为字符串

    const obj = {
      name: "张三",
      age: 18,
      sex: "男",
      friends: ["", "", ""],
      86 : "Do not",
      [1]: 'one',
      // 匿名函数
      sayHi: function () {
        console.log("hi");
      },
    };
    console.log([1].toString()) // 1
    console.log(obj[1])
    
  2. 函数 (Function)

    JavaScript中函数不仅是可执行的代码块,还可以作为值进行传递、赋值给变量,或者作为参数传递给其他函数。函数也是对象并且所有JavaScript 中的函数实际上都是 Function 对象的实例

    // 创建函数
    function eat() {}
    
    // 函数表达式 将函数赋值给变量 也-可以省略函数名
    const fn = function() {}
    
    // 箭头函数
    const fn2 = () => {}
    
    console.log(fn instanceof Object) // true
    console.log(fn instanceof Function) // true
    
  3. 数组 (Array)

    JavaScript中的数组是一种有序的数据集合,它可以存储不同类型的数据本质是对象。其大小是动态的,不像其他语言有固定的长度。

    可以通过索引来访问或修改数组元素,数组中含有多种可以对数组进行操作的方法

    // 字面量创建数组
    const arr = [1,'sy',{name:'kk',age:18}]
    // 构造方法创建数组
    const numbers = new Array(1, 2, 3);
    
    // es6新增
    Array.of(1, 2, 3); // [1, 2, 3]
    Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']
    

    数组存储数据的方案

    • 存储相同数据类型

      当存储 31 位有符号整数(-2³⁰ 到 2³⁰-1)时,每个元素的大小相同,为4字节(4 * 8 = 32位)

      const arr = [15,68,3,1468,461,8] // 所有元素所占空间大小相同
      

      当存储双精度浮点数时,每个元素大小相同,为8 字节(64 位)

      const arr = [1.1, 2.2, 3.3]; // 所有元素大小相同
      
    • 存储不同数据类型

      当存储不同数据类型时,数组中存储的不是元素的值,而是指向实际值的指针,这时候数组的每个元素大小相同(即指针大小,通常 4 或 8 字节),实际上所占用的堆内存大小是不一样的

      const arr = [86,'name',{id:'lei'}]