• js 中的 堆栈


    1.含义及对比

    堆和栈都是运行时内存中分配的一个数据区,因此也被称为堆区和栈区;

    二者存储的数据类型和处理速度不同;

    (heap)用于复杂数据类型(引用类型)分配空间,例如数组对象、object对象;它是运行时动态分配内存的,因此存取速度较慢。

    (stack)中主要存放一些基本类型的变量和对象的引用,(包含池,池存放常量),其优势是存取速度比堆要快,并且栈内的数据可以共享,但缺点是存在栈中的数据大小与生存期必须是确定的,缺乏灵活性,

    先进后出,后进先出原则,所以 push 优于 unshift

    1.1 扩展: 队列(先进先出(FIFO)的数据结构,这是事件循环(Event Loop)的基础结构)

    1.2 经典面试题

    var a = 20;
    var b = a; // b 为栈类型,相当于新开一块空间然后赋值为 20,不影响原来的a
    b = 30;
    console.log(a)
    console.log(b)
    //20 30

    var a = { name: '前端开发' }
    var b = a;
    b.name = '进阶';
    console.log(a)
    console.log(b)
    // { name: '进阶' }  name: '进阶' }

    var a = { name: '前端开发' }
    var b = a;
    a = null;    //释放引用
    console.log(a)
    console.log(b)
    // null { name: '前端开发' }

    var a = {n: 1};
    var b = a;
    a.x = a = {n: 2};   //   等价于  b.x = a = {n: 2};            先是预编译ab同时指向的对象增加x属性,该对象也就是后来都没变的b指向的对象,这里  a= {n: 2};改变了a的指向。

    另外扩展下连等算法:  var a=b=1,b为全局变量了      function t(){ var var a=b=1}    t()      b // 1    a  // undefined
    console.log(a.x);
    console.log(b.x);
    // undefined {n:2}

    1.3  闭包中的变量并不保存中栈内存中,而是保存在堆内存中,这也就解释了函数之后之后为什么闭包还能引用到函数内的变量。

    function A() { let a = 1 function B() { console.log(a) } return B }

    1.4 垃圾回收算法  ( 常见内存泄漏:全局变量、定时器、闭包、dom引用 )

    • 引用计数(现代浏览器不再使用)     循环引用 问题  function cycle() { var o1 = {}; var o2 = {}; o1.a = o2; o2.a = o1; return "cycle reference!" } cycle();
    • 标记清除(常用)  从根部(在JS中就是全局对象)出发定时扫描内存中的对象,凡是能从根部到达的对象,保留。那些从根部出发无法触及到的对象被标记为不再使用,稍后进行回收。

    2.例子

    var a=3;
    var b=3;
    先处理 var a=3;,首先会在栈中创建一个变量为a引用,然后查找栈中是否有3这个值,如果没有找到,就将3存放进来,然后将a指向3。
    接着处理 var b=3;,在创建为b的引用变量后,查找栈中是否有3这个值,因为此时栈中已经存在了3,便将b直接指向3。这样,就出现了a与b同时指向3的情况。
    此时,如果再令a=4,那么JavaScript解释引擎会重新搜查栈中是否有4这个值,如果已经有了,则直接将a指向这个地址。没有的话直接压入并指向它。


    var fruit_1="apple";
    var fruit_2="orange";
    var fruit_3="banana";
    var oArray=[fruit_1,fruit_2,fruit_3];  (此时相当于新建一个包含三个值的数组,与 fruit等不再相关)
    var newArray=oArray;
    当创建数组时,就会在堆内存创建一个数组对象,并且在栈内存中创建一个对数组的引用
    变量fruit_1、fruit_2、fruit_3为基本数据类型,它们的值直接存放在栈中
    newArray、oArray为复合数据类型(引用类型),他们的引用变量存放在栈中, 指向于存放在堆中的实际对象。

    比较
    var str=new String('abc');
    var str='abc';
    第一种是用new关键字来新建String对象,对象会存放在堆中,每调用一次就会创建一个新的对象,而不管其字符串值是否相等及是否有必要创建新对象,从而加重了程序的负担。并且堆的访问速度慢。
    第二种是在栈中,栈中存放值‘abc’和对值的引用;这种写法在内存中只存在一个值,有利于节省内存空间。同时它可以在一定程度上提高程序的运行速度,因为存储在栈中,其值可以共享,并且由于栈访问更快;
    var str1='abc';
    var str2='abc';
    alert(str1==str2); // true
    alert(str1===str2); // true

    var str1=new String('abc');
    var str2=new String('abc');
    alert(str1==str2); // false
    alert(str1===str2); // false


    3.细节

    JavaScript堆不需要程序代码来显示地释放,因为堆是由自动的垃圾回收来负责的,每种浏览器中的JavaScript解释引擎有不同的自动回收方式

    一个最基本的原则是:如果栈中不存在对堆中某个对象的引用,那么就认为该对象已经不再需要,在垃圾回收时就会清除该对象占用的内存空间。

    因此,在不需要时应该将对对象的引用释放掉(newArray=null;),以利于垃圾回收,这样就可以提高程序的性能。

    4. 相关文章

    JavaScript是如何工作的:引擎,运行时和调用堆栈的概述!

    js 堆栈

  • 相关阅读:
    json转实体,json转List实体,json转泛型实体
    java使用google开源工具实现图片压缩
    SpringBoot的文件下载
    SpringBoot(三):文件下载
    java transient关键字作用,使用场景。
    ApplicationContextAware接口的作用
    JAVA中STATIC{}语句块详解
    RGB转灰度图的几种算法
    JavaScript系列文章:谈谈let和const
    mybatis中的#{}和${}区别
  • 原文地址:https://www.cnblogs.com/justSmile2/p/9778498.html
Copyright © 2020-2023  润新知