js 三种数据结构 栈:栈是一种后进先出的数据结构 队列:队列是一种先进先出的数据结构 堆:堆是一种树状结构,类似于书架,只需要知道书的名字就可以直接取出书,也类似于 JSON,每一个 key 都对应一个 value 数据类型 基本数据类型:Undefined,Null,Boolean,Number,String 和 Symbol 引用数据类型:Object,Array,Function 变量的存…

js 三种数据结构

  1. 栈:栈是一种后进先出的数据结构
  2. 队列:队列是一种先进先出的数据结构
  3. 堆:堆是一种树状结构,类似于书架,只需要知道书的名字就可以直接取出书,也类似于 JSON,每一个 key 都对应一个 value

数据类型

  1. 基本数据类型:Undefined,Null,Boolean,Number,String 和 Symbol
  2. 引用数据类型:Object,Array,Function

变量的存储

  1. 基本数据类型是保存在栈中的,栈是一种后进先出的数据结构
  2. 引用数据类型是保存在堆中的,但栈内保存了堆内存中引用的地址,通过这个地址可以找到对应的堆内保存的引用类型数据

六道题理解 js 的变量引用关系

  1. 基本数据类型
var a = '前端开发';
var b = a;
b = '前端进阶';
console.log(a);
console.log(b);
// 输出
// 20
// 30

a,b 都是基本类型,数据都存在栈中,a,b 有各自的栈空间,所以修改了 b 的值后,a 的值不受影响

  1. 引用数据类型
var a2 = { name: '前端开发' };
var b2 = a2;
b2.name = '前端进阶';
console.log(a2);
console.log(b2);
// 输出
// {name: "前端进阶"}
// {name: "前端进阶"}

a2,b2 都是引用类型,数据都存在堆中,栈中保存了数据的引用地址,a2 和 b2 指向的地址相同,所以修改了 b2,a2 就发生变化

  1. 引用数据类型
var a3 = { name: '前端开发' };
var b3 = a3;
a3 = null;
console.log(a3);
console.log(b3);
// 输出
// null
// {name: "前端进阶"}

null 是基本类型,a3=null,只是把 a3 存储在栈中的地址变成了基本类型 null,不影响堆中的对象,所以 b3 的值不受影响

  1. 引用类型数据

    var a4 = { name: '前端开发' };
    var b4 = a4;
    a4.x = a4 = { name: '前端进阶' };
    console.log(a4);
    console.log(b4);
    setTimeout(function() {
      a4.name = '前端深入';
      console.log(a4);
      console.log(b4);
    }, 1000);
    // 输出
    // {name: "前端进阶"}
    // {name: "前端开发", x:{name: "前端进阶"}}
    // {name: "前端深入"}
    // {name: "前端开发", x:{name: "前端深入"}}
    
    1. js 中取属性运算符的优先级最高(.运算符)
    2. 赋值运算符是从右向左,看到了点运算符,先执行点运算符,所以执行步骤: (1)a4.x,(2)a4={ name: '前端进阶' },(3)a4.x = a4
    3. 第一步 a.x 是 undefined,b.x 也是 undefined
    4. 第二步直接给 a4 重新开了一块地址,a4 的指向发生变化,所以 a4={name: "前端进阶"}
    5. 第三步,因为第一步已经操作了 a4.x,所以就不会再次操作 a4.x,此时 a4 还保留对 b4 的引用,所以 a4.x = a4 实际是 b4.x = a4
    6. 开了一个定时器,在 1s 后重新对 a4.name 修改,因为是引用关系,所以 b4 的 x 也会修改
  2. Null 和 Undefined 的区别

    1. Null:给一个全局变量赋值为 null,代表这个变量的地址和值为 null,给一个对象的属性或者局部变量赋值为 null,只是分配一块新的地址并且值为 null
    2. Undefined:给一个全局变量赋值 undefined,代表把这个变量的值清空,但是这个变量依旧存在,如果给对象的属性赋值 undefined,说明这个值为空
  3. const 修饰一个对象

const foo = {};
foo.prop = '前端深入';
foo.prop;
console.log(foo);
// 输出
// {prop: 123}

const 修饰一个变量,并不是这个变量不能改动,是变量地址保存的数据不能改动,回想之前的基本数据类型,普通数据类型是直接保存在栈中,引用数据类型,对象是保存在堆中,栈中只保存了堆内存引用的地址,const 只能保证这个地址不变,指数地址指向的数据有没有变,就无法控制了

垃圾回收

js 是自动垃圾回收机制的,通常用标记清除的方法去找到哪些对象不可用,标记清除会定义哪些对象是从根部出发定时扫描内存中的对象,凡是能够从根部出发的无法触及的对象就保留,否则就不再保留

使用 a3=null 是做了一个释放引用的操作,这个变量会在下一次垃圾回收时被释放

局部变量是在一个局部作用域中,当函数执行完毕,局部变量就会释放引用,但是全局变量的引用只能在 window/global 环境卸载的时候的才能释放全局变量的引用

  • 闭包
function aa() {
  var a = 1;
  function bb() {
    var b = a;
  }
  return bb;
}

a 属于局部变量,aa 函数执行完毕后,a 变量的引用关系没有释放,因为存在一个闭包(内部函数引用外部函数的变量与属性)导致了局部变量 a 一直在被引用,无法释放 a 变量的引用关系

内存泄漏

内存泄漏就是对不再用到的内存,没有及时释放,导致了内存越用越少

  • 导致内存泄露的方式
  1. 一些全局变量
  2. 没有及时 clear 的定时器
  3. 保存 dom 的引用
  4. 闭包

暂无评论