变量声明 - 《JavaScript 高级程序设计》笔记

本文是《JavaScript 高级程序设计》笔记,详细阐述了 var、let 和 const 的声明与作用域。var 声明具有函数作用域,存在变量提升现象;let 声明在块级作用域内,重复声明会报错,有暂时性死区;const 用于声明不可变常量,其对象属性仍可修改。建议在开发中尽可能多使用 const 声明。
摘要由CSDN通过智能技术生成

变量声明

使用 var 的函数作用域声明

使用 var 声明变量,该变量会被自动添加到最接近的上下文中。

在函数和 with 语句中,最接近的上下文就是函数的局部的上下文。

若变量初始化未经声明,将被自动添加到全局上下文中。

function add(num1, num2) {
	var sum = num1 + num2;
	return sum;
}
let result = add(10, 20);	// 30
console.log(sum);	// 报错:sum 在这里不是有效变量

在上述代码中,函数 add() 定义了一个局部变量 sum,用于保存加法操作的结果。该值作为函数值被返回,但变量 sum 在函数外部无法访问。

省略上述代码中函数内部声明变量 sum 使用的关键字 var,那么变量 sum 在函数 add() 被调用后,将变为可访问变量。

function add(num1, num2) {
	sum = num1 + num2;
	return sum;
}
let result = add(10, 20);	// 30
console.log(sum);	// 30

上述代码中,变量 sum 被用加法操作的结果初始化时并没有使用关键字 var 声明。在调用 add() 之后,变量被添加到全局上下文中,在函数退出执行上下文栈后依然存在。

:未经声明而初始化变量是 JavaScript 编程一个常见错误,在严格模式下,未经声明就初始化变量会报错。

提升(hoisting)

提升:var 声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前

提升使在同一作用域使用变量时,不必考虑其是否已经声明。

示例代码:

var name = "huaqi";

// 等价于

var name;
name = "huaqi"

// ================

function fn1() {
	var name = "huaqi"
}

// 等价于
function fn2() {
	var name;
	name = "huaqi";
}

通过在变量声明之前打印该变量,可以验证变量会被提升。声明的提升意味着会输出 undefined 而不是 Reference Error

console.log(name);	// undefined
var name = "huaqi";

function() {
	console.log(name);	// undefined
	var name = "huaqi";
}

使用 let 的块级作用域声明

关键字 let 对应块级作用域

块级作用域由最近的一对包含花括号 { } 界定。所以,if 语句块、while 语句块、function 语句块、单独块都是 let 声明变量的作用域。

if (true) {
	let a;
}
console.log(a);	// Reference Error: a 未定义

while(true) {
	let b;
}
console.log(b);	// Reference Error: b 未定义

function foo() {
	let c;
}
console.log(c);	// Reference Error: c 未定义

// 不是对象字面量,而是一个独立的块
// JavaScript 解释器会根据其中内容进行识别
{
	let d;
}
console.log(d);	// Reference Error: d 未定义

let 重复声明报错

重复的 var 声明会被忽略

重复的 let 声明会抛出 Syntax Error

循环中使用 let 声明迭代变量

使用 var 声明的迭代变量会泄露到循环外部,这种情况应该避免,而使用 let 声明迭代变量则没有这个问题。

for (var i = 0; i < 10; ++i) {}
console.log(i);	// 10;

for (let j = 0; j < 10; ++j) {}
console.log(j);	// Reference Error: j 未定义

暂时性死区(temporal dead zone)

严格来说,let 在 JavaScript 运行时也会被提升,但由于暂时性死区(temporal dead zone)的缘故,实际上不能在声明之前使用以关键字 let 声明的变量。


使用 const 的常量声明

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

const a;	// Syntax Error: 常量声明没有初始化

const b = 3;
console.log(b); // 3
b = 4; // Type Error: 给常量赋值

const 除了要遵循以上规则,其他方面与 let 声明一样。

const 声明只应用于顶级原语或者对象。即赋值为对象的 const 变量不能再被重新赋值为其他引用值,但对象的键则不受限制。

const o1 = {};
o1 = {};	// Type Error: 给常量赋值

const o2 = {};
o2.name = "huaqi";
console.log(o2.name);	// "huaqi"

Object.freeze() 整个对象不被修改

可以使用 Obejct.freeze() 确保对象的属性不再被重新赋值,但会静默失败。

const o3 = Obejct.freeze({});
o3.name = "name";
console.log(o3.name);	// undefined

尽可能多的使用 const 声明

由于 const 声明暗示变量的值是单一类型且不可修改,JavaScript 运行时编译器可以将其所有实例都替换为实际的值,而不会通过查询表进行变量查询。Chrome 的 V8 引擎执行上述优化

开发实践表明,如果开发流程并不会因此而受很大影响,就应该尽可能多的使用 const 声明。


标识符查找

当在特定上下文中为读取或写入而引用一个标识符时,必须通过搜索确定这个标识符表示什么。搜索开始于作用域链前端,以给定的名称搜索对应的标识符。

若在局部上下文中寻找到该标识符,则搜索停止,变量确定;若没有寻找该变量名,则继续沿作用域链搜索。(作用域链中的对象也有一个原型链,因此搜索可能涉及每个对象的原型链)。

上述过程会一直持续到搜索至全局上下文的变量对象。如果仍然没有找到标识符,则说明其未声明。

var color = "blue";

function getColor() {
	return color;
}

console.log(getColor());	// "blue"

上述代码中,调用函数 getColor() 时会引用变量 color。为确定 color 的值会进行两步搜索。

  1. 搜索 getColor() 的变量对象,查找名为 color 的标识符。
    • 未找到
  2. 继续搜索作用域链中下一个作用域的变量对象(即全局上下文的全局对象)
    • 找到名为 color 的标识符
    • 搜索结束

使用块级作用域声明并不会改变搜索流程 ,但可以给词法层级添加额外的层次

var color = "blue";

function getColor() {
	let color = "red";
	{
		let color = "green";
		return color;
	}
}

console.log(getColor());	// "green"

在局部变量 color 声明之后的任何代码都无法全局访问变量 color,除非使用完全的限定的写法 window.color。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值