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 需要了解的
- 函数上下文: JS中每一个函数在执行的时候都会创建一个执行上下文
- 堆内存: 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的值并未改变.这引出了闭包的第二个作用,保护全局变量.
javascript --- 堆栈内存与闭包的作用相关推荐
- 前端面试题讲解(THIS、构造函数、面向对象、堆栈内存以及闭包)
视频地址:https://www.bilibili.com/video/av24383268/?p=13 02. JS中的严格模式和ARG映射机制 EXP1 EXP2 映射机制 严格模式 03. 逻辑 ...
- 夯实基础,彻底掌握js的核心技术(三):堆栈内存及闭包详解
数据渲染机制及堆栈内存 1. 数据值操作机制 /* * 1. 先声明一个变量a,没有赋值(默认值谁undefined) * 2. 在当前作用域中开辟一个位置存储12这个值 * 3. 让变量a和12关联 ...
- JavaScript的内存作用域闭包
1. 执行上下文与作用域 执行上下文简称 " 上下文 ",变量和函数的上下文决定了它们可以访问哪些数据.以及它们的行为.每个上下文都有一个变量对象 VO(variable obje ...
- 【金三银四】 一文弄懂 js 数据类型、堆栈内存、作用域(链)、闭包知识拓展 (一)
引言 对答如流系列篇,关于基本数据类型.堆栈内存.作用域作用域链.闭包 大家好,这里是lionLoveVue,基础知识决定了编程思维,学如逆水行舟,不进则退.金三银四,为了面试也还在慢慢积累知识,Gi ...
- javascript基础系列:堆栈内存(stackamp;heap)(二)
忙了一段时间,很容易忘记更新博客文章,拖延症很严重,今天晚上趁着有时间,继续系统温习,希望对大家有所帮助.本文章仅代表前端岚枫的个人观点,有不正确还望指出. 浏览器运行机制及基本类型与引用类型的区别 ...
- javascript深入理解js闭包[转]
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...
- javascript深入理解js闭包
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...
- 面试官:谈谈对JS闭包的理解及常见应用场景(闭包的作用)
文章目录 对JS闭包的理解及常见应用场景(闭包的作用) 1.变量作用域 2.如何从外部读取函数内部的变量? 3.闭包概念 4.闭包用途 5.闭包的理解 6.闭包应用场景 setTimeout传参 回调 ...
- [javascript] 深入理解js闭包
闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域 ...
最新文章
- HiCar基本功能介绍
- 张晓帆:一个决定将47万奖金全部投入科研的博士生
- 利用STM32 的串口来发送和接收数据实验
- python五十一:动态导入模块,通过字符串导入模块
- 中國批准英特爾在東北投建晶片廠
- 开源 | 如何实现一个iOS AOP框架?
- 优化大数据分析的五个小技巧
- Asp.net web api 知多少
- c语言n天前是星期几,新手做的日历表及查找日期是星期几
- learning opencv3: 一:overview 打开自己的视频文件加上暂停快进按钮
- 持续改进----白狼族的故事(完结)
- rar压缩文件密码破解
- matlab程序阻尼牛顿法,matlab阻尼牛顿法
- 关于jmstudio 调用本地摄像头的问题
- c语言.jpg图片转成数组_AWTK——基于C语言开发的GUI框架,功能强大,支持跨平台同步开发...
- Android 版本简介
- 手把手教你开发IOT设备
- 第一代计算机硬件逻辑主要采用电子管,云南省计算机一级考试题库4
- C语言汇编查看笔记(一)
- Lomboz的安装与下载(转)
热门文章
- mysql 中文字段名_MySQL全文索引怎么做?| 教程分享
- js封装函数_JavaScript基础-如何封装函数来改变元素的位置
- mysql第四项_mysql数据库的基本介绍与操作(第四篇-mysql索引篇)
- GPU Gems1 - 9 有效的阴影体渲染
- ASP.NET Core Web 应用程序系列(三)- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)...
- [webrtc] rtcp模块中rtt时间计算
- Android开发学习---使用Intelij idea 13.1 进行android 开发
- 考研数学:【以错补错】 降低做题出错率
- GooglePR说明
- Node — 第九天 (ES6降级 and 发布属于自己的[第三方模块]包)