JS - 堆栈内存及闭包作用域

数据类型

  1. undefinednull 区别与联系
    undefined 表示某个表达式的原始状态。null 表示一个对象被认为重置,切断栈中对象指针与堆中对象的关系,因此,用于释放对象

  2. js中的 string 也属于基本类型,因此数据也是直接存储在栈中。js中也存在包装类,与基本类型最主要的区别就是对象的生存周期。

// 引用类型自定义属性在定义后失效
let s = "hello";
s.color = "red";

alert(s.color); // undefined

// 包装类型会在作用域失效后才会被销毁
let s = new String("hello");
s.color = "red";
alert(s.color); // red

变量提升

定义: JS的引擎工作方式为,先解析代码,获取所有被声明的变量,再进行一行行执行。因此,就出现了后面声明的变量可以被前面的代码访问的情况,也就是所谓的变量提升。

  1. var 关键字定义的变量声明会被提升,同时会被初始化为 undefined 。
  2. let 关键字定义的变量声明同样会被提升,但是不会被进行初始化,执行到代码语句处才会被初始化。因此在代码声明前访问时会出现 Uncaught ReferenceError: x is not defined 错误。
// 报错说明内部的console输出的是块级作用域中的x,表示该变量已经声明,只是没有初始化
let x = 'global'; // 全局作用域
{
	console.log(x); // Uncaught ReferenceError: x is not defined
	let x = 1;
}
  1. function 关键字则会在代码执行前将 声明,初始化和赋值 都完成,因此可以在代码语句之前调用。
  2. const关键字与 let相似,只是没有赋值的操作。

参考博客:

https://www.jianshu.com/p/0f49c88cf169

执行上下文

实质: 执行环境栈中的一块内存,用于区分函数的作用域。因此每次遇到函数调用,就会创建一个新的执行上下文并压入栈中,用于保护私有变量。

注意:

  1. 执行上下文只与调用有关,因此同一个函数被调用多次会创建多个上下文。
  2. 只要当前上下文中的某些内容被其它上下文中的变量占用,那么当前上下文是不能被释放的,直到占用的指针置null后才能释放。这也是闭包出现的必要条件。

闭包

定义:有权访问另一个函数作用域中变量的函数

闭包案例1:(等待队列中放入的是字符)

for(var i=0;i<5;i++){
	setTimeout(function(){
		console.log(i++)
}, 4000);
}
console.log(i) // 5 5 6 7 8 9
// 由于setTimeout需要等待主体代码完成四秒后才会执行,因此,先执行最后一条输出 i 的语句,此时i=5,
// 由于 i 还会在 setTimeout里面使用,因此四秒后其内部的匿名函数继续使用 i=5 来完成后续的操作,来得到后续的结果。

案例2:使用立即执行函数暂存每轮执行的结果,即创建闭包(等待队列中放的是执行完成后的数值)

for(var i=0;i<5;i++){
	// 立即执行函数会在完成后单独创建OV来保存当前的i值
	(function(x){
		setTimeout(function(){
			console.log(x++)
		}, 4000);
	})(i);
}
console.log(i) // 5 0 1 2 3 4

闭包的应用

  1. 创建访问私有变量的公有方法

    • 函数内部定义的变量都可以称为私有变量,函数外部无法访问。创建闭包可以使这些变量暴露出来。
  2. 模拟块级作用域

编译机制(VO,AO和GO)

VO(变量对象)

VO(G)

定义:全局变量对象,用于保存全局上下文中的所有变量的对象

AO

定义:活动对象,是函数执行上下文中VO的具体表现。用于保存函数形参、局部变量、自身函数对象引用遍历、argument和this等内容。

GO

定义:全局对象,是预定义对象,表示 window 变量指向的堆内存地址,用于存储内置的属性和方法。

注意:

  1. 在全局上下文中,基于 var/function 创建的变量本质是给window设置属性(作用于GO)。基于let/const 创建的变量则是存在 VO(G)中的,与window没有关系。
  2. VO(G)中包含了window变量和自定义的全局变量。

作用域

  1. 定义:表示一个变量的可访问性与可见性。
  2. 分类:
    1. 全局作用域
    2. 函数作用域
    3. 块级作用域:声明与大括号内,并且由非 var 关键字声明的变量。
  3. 作用域链:从自身作用域向上寻找某个变量的过程。在全局作用域中找不到则直接报错。

作用域链的具体体现: 内层函数执行上下文的VO -> 外层函数执行上下文的VO -> 全局执行上下文的VO。通过 [[Scope]] 内部属性来拼接。

参考博客

https://www.cnblogs.com/dasusu/p/10071326.html
https://juejin.cn/post/6961716331297112094(里面有张图很好地解释了VOG与GO的关系)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值