第 4 章 变量、作用域与内存

这篇文章讨论了JavaScript中的原始值和引用值的概念,包括变量按值或引用的访问方式。它还介绍了如何使用typeof和instanceof操作符判断变量类型。文章深入讲解了执行上下文、作用域链,特别是let和const在块级作用域中的行为。此外,还涉及了垃圾回收机制对性能的影响以及如何避免内存泄漏,包括通过解除引用来管理内存。最后,提到了JavaScript中的内存管理和可能导致内存泄漏的问题,如闭包和意外的全局变量。
摘要由CSDN通过智能技术生成
原始值与引用值

原始值(primitive value)就是 最简单的数据,引用值(reference value)则是由多个值构成的对象。保存原始值的变量是按值(by value)访问的。在操作对象时,实际上操作的是对该对象的引用(reference)而非 实际的对象本身。

确定类型

typeof 操作符最适合用来判断一个变量是否为原始类型。更确切地说,它是判断一 个变量是否为字符串、数值、布尔值或 undefined 的最好方式。

instanceof 操作符检测任何引用值和 Object 构造函数都会返回 true。类似地,如果用 instanceof 检测原始值,则始终会返回 false

执行上下文与作用域

根据 ECMAScript 实现的宿主环境,表示全局上下文的对象可能不一 样。在浏览器中,全局上下文就是我们常说的 window 对象,因此所有通过 var 定 义的全局变量和函数都会成为 window 对象的属性和方法。

上下文在其所有代码都执行完毕后会被销毁,包括定义 在它上面的所有变量和函数(全局上下文在应用程序退出前才会被销毁,比如关闭网页或退出浏览器)

上下文中的代码在执行的时候,会创建变量对象的一个作用域链(scope chain)。这个作用域链决定 了各级上下文中的代码在访问变量和函数时的顺序。代

使用 let 的块级作用域声明

ES6 新增的 let 关键字跟 var 很相似,但它的作用域是块级的,这也是 JavaScript 中的新概念。块 级作用域由最近的一对包含花括号{}界定。

if (true) { let a; } console.log(a); // ReferenceError: a 没有定义

let 与 var 的另一个不同之处是在同一作用域内不能声明两次。重复的 var 声明会被忽略,而重 复的 let 声明会抛出 SyntaxError。

var a; var a; // 不会报错 { let b; let b; } // SyntaxError: 标识符 b 已经声明过了

使用 const 的常量声明

使用 const 声明的变量必须同时初始化为某个值。 一经声明,在其生命周期的任何时候都不能再重新赋予新值。

const a; // SyntaxError: 常量声明时没有初始化 const b = 3; console.log(b); // 3 b = 4; // TypeError: 给常量赋值

var color = 'blue'; function getColor() { let color = 'red'; { let color = 'green'; return color; } } console.log(getColor()); // 'green'

垃圾回收

确定哪个变量不会再 使用,然后释放它占用的内存。这个过程是周期性的,即垃圾回收程序每隔一定时间(或者说在代码执 行过程中某个预定的收集时间)就会自动运行。

举例

函数中的局部变量会在函数执行时存在。此时,栈(或 堆)内存会分配空间以保存相应的值。

函数在内部使用了变量,然后退出。此时,就不再需要那个局部 变量了,它占用的内存可以释放,供后面使用。这种情况下显然不再需要局部变量了,但并不是所有时 候都会这么明显。

标记清理(mark-and-sweep)

性能

垃圾回收程序会周期性运行,如果内存中分配了很多变量,则可能造成性能损失,因此垃圾回收的 时间调度很重要。

内存管理

分配给浏览器的内存通常比分配给桌面软件的要少很多,分配给移动 浏览器的就更少了。这更多出于安全考虑而不是别的,就是为了避免运行大量 JavaScript 的网页耗尽系 统内存而导致操作系统崩溃。

将内存占用量保持在一个较小的值可以让页面性能更好。优化内存占用的最佳手段就是保证在执行 代码时只保存必要的数据。如果数据不再必要,那么把它设置为 null,从而释放其引用。

function createPerson(name){ let localPerson = new Object(); localPerson.name = name; return localPerson; } let globalPerson = createPerson("Nicholas"); // 解除 globalPerson 对值的引用 globalPerson = null;

globalPerson 是一个全局变量,应该在不再需要时手动解除其 引用,最后一行就是这么做的

内存泄漏

意外声明全局变量是最常见但也最容易修复的内存泄漏问题。下面的代码没有使用任何关键字声明 变量: function setName() { name = ‘Jake’; }

解释器会把变量 name 当作 window 的属性来创建(相当于 window.name = ‘Jake’)。

使用 JavaScript 闭包很容易在不知不觉间造成内存泄漏。

请看下面的例子

let outer = function() {  let name = 'Jake';  return function() {  return name;  };  }; 

以上代码执行后创建了一个内部闭包,只要返回 的函数存在就不能清理 name,因为闭包一直在引用着它。假如 name 的内容很大(不止是一个小字符 串),那可能就是个大问题了。

小结

JavaScript 变量可以保存两种类型的值:原始值和引用值。

原始值可能是以下 6 种原始数据类型之 一:Undefined、Null、Boolean、Number、String 和 Symbol。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值