谈一谈js的内存分配

因为js是一门动态语言,动态分配内存的方式让使用者运用快速便捷,却忽略了他的内存分配机制,今天我来试着理清思路。

还是那个惯例,从基础讲起,然后发散思维,由浅入深。

JavaScript有两种变量类型,原始值和引用值。原始值指的是原始数据类型,分别为undefined,null,number,string,boolean类型。引用值指的是复合数据类

型,即Object、Function、Array。

原始值和引用值存储在内存的位置分别为栈和堆。原始值是存储在栈中的简单数据段,它们的值存储在变量访问的位置。引用值是存储在堆中的对象(存储在栈

中的只是一个指针,指向存储在堆中的实际对象)。

基础都很简单,但是要活用,然后我们看一个闭包的例子:

for(var i=0,arr=[];i<=3;i++) {
  arr.push(function(){
    alert(i);
  });
}
arr[0](); // 4
arr[1](); // 4 

关于这个经典闭包的例子,看了很多的解释,但我认为还是从内存的角度来解析最好,我们来活学活用。

(1)预解析,i,arr,匿名函数

(2)从上而下解析,i=0,arr[0]=匿名函数

(3)i=1,arr[1]=匿名函数

(4)i=2,arr[2]=匿名函数

(5)i=3,arr[3]=匿名函数

(6)i=4,循环结束

(7)执行arr[0],因为存入arr内的匿名函数其实是个指针,所以现在才开始执行匿名函数,此时i为4

(8)同理,arr[1]==arr[2]==arr[3]==4

其实在(1)时,i为undefind,而arr数组和匿名函数都是个指针,后续慢慢为arr数组开辟了内存空间,里面存入了匿名函数的指针

既然你都知道了原理抓住了命门,那怎么解决是不是很简单了。

所以解决闭包问题,我们有很多思路,可以让匿名函数即刻执行保存结果,也可以把当前循环时i的值保存在函数里等等。

这里随便列几个供参考,思路可能还有很多

(1)

for(var i=0,arr=[];i<=3;i++) {
    arr.push(function(i){
        alert(i);
    })(i);
}  

这是让匿名函数即刻执行保存结果,注意这几个i的含义,传入参数i与变量i

(2)

for(var i=0,arr=[];i<=3;i++) {
  let a = i;
  arr.push(function(){
    alert(a);
  });
}   

这是把当前循环时i的值保存,let是ES6新语法

时间: 2024-08-04 17:25:27

谈一谈js的内存分配的相关文章

Node.js的内存分配和垃圾回收

简单介绍Node.js的内存分配和垃圾回收 内存分配 Node.js是一个由JavaScript V8引擎控制的C++程序V8的内存管理模式一个运行的程序通常是通过在内存中分配一部分空间来表示的.这部分空间被称为驻留集(Resident Set).V8的内存管理模式有点类似于Java虚拟机(JVM),它会将内存进行分段: 代码 Code:实际被执行的代码 栈 Stack:包括所有的携带指针引用堆上对象的值类型(原始类型,例如整型和布尔),以及定义程序控制流的指针. 堆 Heap:用于保存引用类型

浅谈java内存分配和回收策略

一.导论 java技术体系中所提到的内存自动化管理归根结底就是内存的分配与回收两个问题,之前已经和大家谈过java回收的相关知识,今天来和大家聊聊java对象的在内存中的分配.通俗的讲,对象的内存分配就是在堆上的分配,对象主要分配在新生代的Eden上(关于对象在内存上的分代在垃圾回收中会补上,想了解的也可以参考<深入理解java虚拟机>),如果启动了本地线程分配缓冲,讲按线程优先在TLAB上分配.少数情况下也是直接在老年代中分配. 二.经典的分配策略 1.对象优先在Eden上分配 一般情况下对

细谈 对象的初始化过程------内存中的实现过程?

今天对于内存的理解 又加深了一步: 对下面代码的理解: class Person { private String name="xiaohong"; private int age=23; private static String country="CN"; { System.out.println(name+" "+age); } public Person(String name,int age) { this.name = name; t

Java内存区域和内存分配

最近面试时经常会被问到JVM以及内存分配的问题,觉得有必要学习总结一下下~~~ 一.Java内存区域 Java中,虚拟机自动进行内存管理,在Java虚拟机执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,主要包含以下几个部分: 1.程序计数器: 当前线程所执行的字节码的行号指示器: 字节码解释器工作就是通过改变这个计数器的值来选取下一条需要执行的字节码指令 线程私有:为了线程切换后能够恢复到正确的执行位置,每个线程需要有一个独立的程序计数器: JAVA方法,计数器记录正在执行

深入理解JVM读书笔记二: 垃圾收集器与内存分配策略

3.2对象已死吗? 3.2.1 引用计数法 给对象添加一个引用计数器,每当有一个地方引用它的地方,计数器值+1:当引用失效,计数器值就减1;任何时候计数器为0,对象就不可能再被引用了. 它很难解决对象之间相互循环引用的问题. 3.2.2 可达性分析算法 这个算法的基本思路就是通过一系列的称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC

深入理解JAVA虚拟机 垃圾收集器和内存分配策略

引用计数算法 很多教科书判断对象是否存活的算法是这样的:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器都为0的对象就是不可能再被使用的. 客观地说,引用计数算法(Reference Counting)的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法,也有一些比较著名的应用案例,例如微软的COM(Component Object Model)技术.使用ActionScript 3的FlashPlayer.Python语

【转】java内存分配和String类型的深度解析

一.引题 在java语言的所有数据类型中,String类型是比较特殊的一种类型,同时也是面试的时候经常被问到的一个知识点,本文结合java内存分配深度分析关于String的许多令人迷惑的问题.下面是本文将要涉及到的一些问题,如果读者对这些问题都了如指掌,则可忽略此文. 1.java内存具体指哪块内存?这块内存区域为什么要进行划分?是如何划分的?划分之后每块区域的作用是什么?如何设置各个区域的大小? 2.String类型在执行连接操作时,效率为什么会比StringBuffer或者StringBui

[深入理解Java虚拟机]&lt;垃圾收集器与内存分配策略&gt;

Overview 垃圾收集考虑三件事: 哪些内存需要回收? 什么时候回收? 如何回收? 重点考虑Java堆中动态分配和回收的内存. Is Object alive? 引用计数法 给对象添加一个引用计数器. 该方法实现简单,判定效率高.但是它很难解决对象之间相互循环引用的问题,因此几乎很少有JVM选用该方法.eg: public class ReferenceCountingGC { public Object instance = null; // 占点内存,以便在GC日志中看清楚是否被回收过

Java学习之旅基础知识篇:数组及引用类型内存分配

在上一篇中,我们已经了解了数组,它是一种引用类型,本篇将详细介绍数组的内存分配等知识点.数组用来存储同一种数据类型的数据,一旦初始化完成,即所占的空间就已固定下来,即使某个元素被清空,但其所在空间仍然保留,因此数组长度将不能被改变.当仅定义一个数组变量(int[] numbers)时,该变量还未指向任何有效的内存,因此不能指定数组的长度,只有对数组进行初始化(为数组元素分配内存空间)后才可以使用.数组初始化分为静态初始化(在定义时就指定数组元素的值,此时不能指定数组长度)和动态初始化(只指定数组