第4章 变量、作用域与内存
4.1 原始值与引用值
原始值是最简单的数据,引用值则是由多个值构成的对象
4.1.1 动态属性
原始值不能有属性,引用值可以随时添加、修改和删除其属性和方法
4.1.2 复制值
原始值的复制是在内存中产生了两个相等的原始值,引用值得复制是产生了两个指向相同地址的引用值。
4.1.3 传递参数
由于复制值两者的不同,因此函数使用过程中,传递参数一个是值的复制,一个是指向地址的复制。代码块外的原始值不受代码内的影响,但是引用值指向内容的变更会同步
4.1.4 确定类型
对于对象,我们想要知道它的类型,一般使用instanceof
操作符,返回类型为true和false
4.2 执行上下文与作用域
每个上下文都有一个关联的变量对象,而这个上下文中定义的所有变量和函数都存在于这个对象上。
在浏览器中,全局上下文就是window对象,因此所有通过var定义的全局变量和函数都会称为window对象的属性和方法。使用let和const的顶级声明不会定义在全局上下文中,但在作用域链解析上效果是一样的。
4.2.1 作用域链增强
try/catch语句的catch块以及with语句会导致在作用域链前端临时添加一个上下文,这个上下文在代码执行后会被删除。
4.2.2 变量提升
-
使用var的函数作用域声明
在使用var声明变量时,变量会被自动添加到最接近的上下文
-
使用let的块级作用域声明
let在同一作用域内不能声明两次
-
使用const的常量声明
想让整个对象不能修改,可以使用
Object.freeze()
-
标识符查找
访问局部变量比访问全局变量快
4.3 垃圾回收
标记未使用的变量,浏览器的发展史上,用过两种主要的标记策略:标记清理和引用计数
4.3.1 标记清理
先添加标记,然后把所有在上下文中的变量和被在上下文中变量引用的变量的标记去除。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存
4.3.2 引用计数
容易发生循环引用
4.3.3 性能
调度垃圾回收程序
4.3.4 内存管理
解除引用的关键在于确保相关的值已经不在上下文里了。
- 通过const和let声明提升性能
- 隐藏类和删除操作
- 内存泄漏
- 静态分配与对象池
4.4 小结
JS变量可以保存两种类型的值:原始值和引用值。
原始值大小固定,因此保存在栈内存上
从一个变量到另一个变量复制原始值会创建该值的第二个副本
引用值是对象,存储在堆内存
typeof操作符可以确定值的原始类型,而instanceof操作符用于确保值的引用对象