javascript --- > 堆栈内存与闭包的作用

你可能会用到的

  • 堆内存: 存储引用类型值所在的空间
  • 栈内存: 存储基本类型值和存储代码所在空间
  • 函数上下文: JS每一个函数在执行的时候都会创建一个执行上下文

1. 堆内存中的数字和字符串都是相等的

let a = {}, b='0', c=0;
a[b] = 'marron';
a[c] = 'Mar'
console.log(a[b]) // Mar
  • 第一行代码, a创建是一个对象,对象在JS中是引用类型,因此会创建一个堆内存来存储对象
// 堆: AAAFFF00
(此时里面是空的)
  • 此时a的值实际上是指向这个堆的地址,即A = AAAFFF00
  • 在执行 a[b] = 'marron'时,实际上会给堆内存中键为’0’赋上值 ‘marron’
// 堆: AAAFFF00
'0': 'marron' 
  • 在执行a[c] = 'Mar'时,由于堆中字符串和数字默认是相等的,此时堆内存中实际的操作是:
// 堆: AAAFFF00
+ '0': 'Mar'
  • 因此最后输出的回收’Mar’

2.对象作为值在堆内存中都会隐式调用toString方法,变为字符串

let a = {},
  b = {
    n: '1'
  },
  c = {
    m: '2'
  }
a[b] = 'marron'
a[c] = 'Mar'
console.log(a[b]);		// 'Mar'
// 在堆内存中都是   { '[object object]': 'Mar' }
  • 执行a= {}时,
// 堆: AAAFFF01

  • 此时 a = AAAFFF01
  • 执行a[b] = 'marron'
  • 会先隐式调用b.toString(),然后将得到的结果存放到 堆AAAFFF01中
// 堆: AAAFFF01
'[Object Object]': 'marron'
  • 执行a[c] = 'Mar',同理
// 堆: AAAFFF01
'[Object Object]': 'Mar'
  • 因此,最后会输出 ‘Mar’

3. 闭包问题

var test = (function(i){
	return function(){
		alert(i *= 2)
	}
})(2)
test(5)

3.1 需要了解的

  1. 函数上下文: JS中每一个函数在执行的时候都会创建一个执行上下文
  2. 堆内存: JS中每一个引用类型的操作,都对应一个堆内存

3.2 解析

  • var test = (function(i){...})(2),等号右边是一个自执行函数.执行函数的时候会创建一个执行上下文
// 自执行函数的执行上下文
i = 2;
return function(){}
  • 遇到return function(){}中的function是一个引用类型,故会创建一个堆内存
// 堆: AAAFFF00
"alert(i *=2)"
...
  • 然后将堆内存的地址返回,此时堆内存的上一级作用域是自执行函数的执行上下文
// 自执行函数的 执行上下文
i = 2;
return AAAFFF00
  • 此时test的值是堆的内存地址: test = AAAFFF00
  • 之后遇到了 test(5),函数执行会创建一个执行上下文
// test(5)的 执行上下文
->: AAAFFF11
  • 然后顺着地址去找到堆AAAFFF11,找到堆AAAFFF11之后,遇到函数代码字符串. alert( i *= 2),
// test(5)的 执行上下文
"alert( i*= 2)"
  • 由于当前堆中没用i的值,会顺着作用域链,往上级作用域寻找,找到了 自执行函数的上下文.然后回弹出字符串 “4”,同时堆内存中i的值被改成了4

  • 完毕之后,由于test(5)的执行上下文中没用变量被引用,会根据JS的垃圾回收机制,进行销毁.

  • 自执行函数的 执行上下文中的变量i被堆AAAFFF11引用,会一直存在,因此形成了闭包.

4. 闭包小练手

var a = 0,
    b = 0;
function A(a){
  A = function(b){
    alert(a + b++);
  };
  alert(a++)
}
A(1);
A(2);
  • 首先有个全局作用域
// global
a = 0;
b = 0;
A =: FFFAAA00
ctx:A(1)
ctx:A(2)
  • 执行到A(1)
// ctx: A(1)
a(局部) = 1
A(全局) =: FFFAAA01
alert(a++)	 // 会弹出'1',此时局部a = 2
// 由于a被堆: FFFAAA01 引用,因此结束时, ctx: A(1)不会被清除,形成了闭包哟.
  • A(1)执行完毕,此时全局作用域
// global
a = 0;
b = 0;
A =: FFFAAA01
ctx: A(2)  <-- 执行到这一行
  • A(2)开始执行
// ctx: A(2) 传入参数由b接收
a(ctx(A(1))) = 2;
b(局部) = 2;
alert(a + b++); // 弹出'4', 然后局部b = 3
// 完毕后,作用域销毁
// 注: A此时执行的是堆: AAAFFF01,堆并未消失
  • 综上所述,会弹出’1’,‘4’

说明: 上面执行了2次A函数,且分别用到了a , b变量…但是在对a,b变量操作完成后.全局变量的a和b的值并未改变.这引出了闭包的第二个作用,保护全局变量.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值