JavaScript的作用域(四)块作用域

1.块作用域

尽管函数作用域是最长用的作用域单元,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀、简介的代码。

分析下面代码:

js 复制代码
for(var i = 0; i < 10; i++){
	console.log(i);
}

for循环的头部直接定义了变量i,通常只想在for循环内部的上下文中使用i,但忽略了i会被绑定在外部作用域中的事实。

这就是块作用域的用处。变量的声明应该距离使用的地方越近越好,并最大限度本地化。

js 复制代码
var foo = true;
if(foo){
	var bar = foo * 2;
	console.log(bar); // 2
}
console.log(bar); // 这里也是 2

bar变量仅在if声明的上下文中使用,因此如果能将它声明在if块内部中会很有意义。但是,当使用var声明的时候,它写在哪里都是一样的,因为它们最终都会属于外部作用域。这段代码是为了风格更易读而伪装出的形式上的块作用域,如果使用这种形式,要确保没在作用域其他地方意外的使用bar,这只能依靠自觉性。

2 with

with关键字在前面介绍过,它不仅是一个难于理解的结构,同时也是块作用域的一个例子,用with从对象中创建出的作用域仅在它内部声明中而非外部作用域有效。

3 try/catch

JavaScript在ES3中规定try/catchcatch分句会创建一个块作用域,其中声明的变量仅在catch内部生效。

js 复制代码
try{
	undefined(); // 制造错误
}catch (err) {
	console.log(err);
}
console.log(err); // 这里就会报错

4 let

ES6中引入了新的let关键字,提供了另一种变量声明方式,let关键字可以将变量绑定到所在的任意作用域中(通常是{...}内部)。

js 复制代码
var foo = true;
if(foo){
	let bar = foo * 2;
	bar = 3;
	console.log(bar);
}
console.log(bar); // 这里会报错

let将变量附加在一个已经存在的块作用域上的行为是隐式的。

4.1 let 循环

js 复制代码
for(let i = 0; i < 10; i++) {
	console.log(i);
}

for循环头部的let不仅将i绑定到了for循环的块中,事实上它将其重新绑定到了循环的每个迭代中,确保使用上一个循环迭代结束时的值进行重新赋值。

js 复制代码
{
let j;
for(j = 0; j < 10; j++){
		let i = j; // 每个迭代重新绑定!
		console.log(i);
	}
}

由于let声明附属于一个新的作用域而不是当前作用域,当代码中存在对于函数作用域中var声明的隐式依赖时,就会有很多隐式陷阱,如果用let代替var则需要在代码重构的过程中付出额外的精力。

思考一下:

js 复制代码
var foo = true;
var baz = 10;
if(foo){
	var bar = 3;
	if(baz > bar){
		console.log(baz);
	}
}

这段代码可以简单的被重构为下面代码

js 复制代码
var foo = true;
var baz = 10;
if(foo) {
	var bar = 3;
}
if(baz > bar) {
	console.log(baz);
}

但是在使用块级作用域的变量时要注意

js 复制代码
var foo = true;
var baz = 10;
if(foo) {
	let bar = 3;
	if(baz > bar) {
		console.log(baz);
	}
}

如果这时候直接将内部的if提取出来,就会报错找不到bar

5 const

除了let以外,ES6中还引入了const,同样可以用来创建块级作用域,但const主要用来声明常量。之后的对const声明的值进行任何修改都会报错。

js 复制代码
let a = 3;
const b = 5;
a = 4;
b = 6; // 错误
console.log(a); // 4
console.log(b); // 报错

6 小结

函数是JavaScript中最常见的作用域单元,本质上声明一个在函数内部的变量或函数会在所处的作用域中隐藏起来,但是函数不是唯一的作用域单元。块作用域指的是变量和函数不仅可以属于所处的作用域,也可以属于某个代码块。

相关推荐
Zevalin爱灰灰12 分钟前
Matlab simulink建模与仿真 第十六章(用户定义函数库)
开发语言·matlab
Zevalin爱灰灰18 分钟前
Matlab simulink建模与仿真 第十四章(信号输出库)
开发语言·matlab
汇匠源42 分钟前
小程序服务零工市场
java·大数据·开发语言·小程序·团队开发·零工市场·零工市场小程序
王俊山IT1 小时前
C++学习笔记----7、使用类与对象获得高性能(二)---- 理解对象生命周期(7)
开发语言·c++·笔记·学习
luthane2 小时前
python 实现bailey borwein plouffe算法
开发语言·python·算法
大侠之运维2 小时前
在excel中使用python?
开发语言·python·excel
感谢地心引力2 小时前
【matlab】将程序打包为exe文件(matlab r2023a为例)
开发语言·matlab
QGC二次开发2 小时前
Vue3:mitt实现组件通信
前端·javascript·vue.js·vue
蓝色洛特2 小时前
【Matlab 肌电信号分析】
开发语言·matlab·信号处理·肌电信号
ljp_nan2 小时前
Qt --- 常用控件的介绍 --- 其他控件
开发语言·qt