第四章 变量,作用域和内存问题

本文深入解析JavaScript中的变量类型、作用域和内存管理机制。涵盖了基本与引用类型的特性,执行环境的作用域链,以及垃圾收集原理。通过实例演示变量复制、参数传递和类型检测的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. 变量类型

1.1 基本类型与引用类型

  • 基本类型:
    指简单的数据段。按值访问,可操作保存在变量中的实际值。包括Undefined,Null,Boolean,Number,String。
  • 引用类型:
    指可能由多个值构成的对象。按引用访问,Js不允许直接访问内存中的位置,实际操作的使对象的引用。

1.2 动态属性

对于引用类型,可为其添加,删除和修改属性和方法。

var person = new Object();
person.name = 'aa';
alert(person.name);

对于基本类型,可以进行赋值操作

var person = 'aa', people = 1234;

1.3 复制变量值

一个变量向另一个变量复制基本类型值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。

var num1 = 2;
var num2 = num1;

复制前变量对象复制后变量对象

一个变量向另一个变量复制引用类型值,会将存储在变量对象中的值复制一份放到为新变量分配的空间中,这个值的副本实际上是一个指针,指向存储在堆中的一个对象,复制后,两个变量将引用同一个对象。改变一个变量会影响另一个变量。

var obj1 = new Object();
var obj2 = obj1;
obj1.name = 'aaa';
alert(obj2.name);   // 'aaa'

对象复制

1.4 传递参数

ECMAScript 中所有函数的参数对后世按值传递的。就是说函数传参过程中,形参实际使复制了实参,作为一个变量存在。不论要传递的参数是基本类型还是引用类型,形参进行的是变量复制的操作。(函数的参数可以想象为局部变量)

// 基本类型
function addTen(num) {
	num += 10;
	return num;
}
var count = 20;
var result = addTen(count);
alert(count); // 20,没变化
alert(result); // 30

// 引用类型 第一种
function setName(obj) {
	obj.name = 'aaa';
}
var person = new Object();
setName(person);
alert(person.name); // 'aaa'

// 引用类型 第二种
function setName(obj) {
	obj.name = 'aaa';
	obj = new Object();
	obj.name = 'bbb';
}
var person = new Object();
setName(person);
alert(person.name); // 'aaa'

1.5 检测类型

检测基本数据类型时,用typeof很合适;检测引用类型时可以使用instanceof

二. 执行环境及作用域

  • 执行环境,定义了变量或函数有权访问的其他数据,决定它们各自的行为。每个执行环境都有与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。
  • 全局执行环境,是最外围的一个执行环境。根据ECMAScript实现所在的宿主环境不同,表示执行环境的对象也不一样。web浏览器中,全局执行环境被认为是window对象,所有全局变量和函数都是作为window对象的属性和方法创建的。某个执行环境代码执行完毕,该环境被销毁,保存的变量和函数定义也会被销毁。全局执行环境直到程序退出才被销毁。
  • 函数执行环境,当执行流进入一个函数,函数环境会被推入一个环境栈。执行之后,栈将其环境弹出,控制权交给之前的执行环境。这就是ECMAScript的执行流机制。
  • 作用域链,当代码在一个环境中执行时,会创建变量对象的一个作用域链,保证对执行环境有权访问的所有变量和函数的有序访问。作用域链开端是当前执行代码所在环境的变量对象。如果环境是函数,则将活动对象作为变量对象。作用域链中的下一个变量对象来自包含环境,再下一个的变量对象来自下一个包含环境,直到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。

2.1 延长作用域链

执行环境有两种,全局和局部(函数)。
可以通过try-catch的catch 和 with 语句延长作用域链。

function buildUrl() {
	var qs = '?a=1';
	with(location) {
		var url = href + qs;
	}
	return url;
}

2.2 没有块级作用域

由非函数的花括号封闭的代码块中,没有块级作用域。未用var定义的变量使用后,会使变量作用域提升。

function a() {
	if (true) {
		c = 3;
		var b = 2;
	}
	return b;
}
a(); // 2
console.log(c); // 3

变量搜索过程从作用域链的开端开始,向上逐级查询与给定名字匹配的标识符。如果在局部环境中找到,则搜索过程停止,变量就绪;如果没有找到,直到全局的环境变量。如果还没有,就意味变量未声明。

三. 垃圾收集

JS有自动垃圾收集机制。执行环境负责管理代码执行过程中使用的内存。不再继续使用的变量释放其占用的内存。
JS常用的方式使标记清除。当变量进入和离开环境时都会打上相应标志。垃圾收集器进行内存清楚工作。
另一种方法是引用计数,跟踪每个值的引用次数。赋值+1,包含这个值的变量取得另一个值,则-1。数量为0时被销毁。会存在未置成0的情况,所以标记清楚更好。

3.1 性能问题

垃圾收集器时周期性运行的。
有手动调用方法,不推荐 window.CollectGarbage()

3.2 管理内存

一旦数据不再有用,最好通过将其值设为null来释放其引用——解除引用法。适用于大多数全局变量和全局对象的属性。局部变量会在离开执行环境时自动被解除引用。解除引用不是指自动回收该值所占用的内存,而是让值脱离执行环境,便于垃圾收集器下次运行时回收。

参考:

  1. JS红宝书 第四章 变量,作用域和内存问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值