谈一谈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新语法