JS作用域
JS中作用域有:全局作用域、函数作用域,以及ES6中新增的块级作用域。
全局作用域
- 在全局声明的变量拥有的作用域叫做全局作用域,在页面任意位置都能访问到。
- 全局作用域在页面打开时被创建,关闭页面时才销毁。
p.s.全局作用域中有个全局对象
window
,代表一个浏览器窗口,由浏览器创建,可以直接访问。
例如:
var a = "cat";
//a的作用域就是全局,在函数内部也能使用
function myFunction(){
}
函数作用域
- 在函数内声明的变量拥有的作用域叫做函数作用域。
- 调用函数时,函数作用域才被创建,函数执行完毕时就被销毁。
- 每一次调用函数时都会创建一个新的函数作用域,它们彼此间相互独立。
var a = "cat";
//a是全局作用域,b在函数外面不能使用,因为声明在函数内部,作用域是函数作用域
function myFunction(){
//函数内部才能使用b
var b = "dog";
}
注意: 函数作用域可以访问到定义在函数外全局作用域的变量,反之不行。
块级作用域
- 块级作用域由
{ }
包括,if
语句和for
语句里面的{ }
都属于块级作用域 -
va
r定义的变量没有块级作用域概念,可以跨块级作用域访问 -
let
和const
定义的变量只能在块级作用域里访问
{
var a = 1
let b = 2
const c = 3
}
console.log(a) // 1
console.log(b) // 报错(let和const只能在块级作用域中访问)
console.log(c) // 报错
for(var a = 0; a < 3; a++) {
var d = 5
}
console.log(a) // 3
console.log(d) // 5
for(let a = 0; a < 3; a++) {
var d = 5
}
console.log(a) // 报错(for语句属于块级作用域)
console.log(d) // 5
在循环时使用var
和let
定义变量,得到的结果会完全不相同:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
因为let是块级作用域才有效,因此每一次循环的变量都是独立的,而var没有块级概念,因此每一次循环其实更改的是同一个变量。
同理:
for (var i = 0; i < 2; i++) {
setTimeout(() => {
console.log(i);
})
}
他会一直输出2,而不是0,1,这是js中的异步问题。等 i 循环完毕后再执行setTimeout
,由于 i 是由var
声明的,此时的 i 已经是2了。
而我们使用let声明时
for(let i=0;i<5;i++){
setTimeout(function(){console.log(i)})
}
就会正常输出,因为每一次循环都是独立的,因此每一次执行setTimeout
时的 i 都是不一样的。
注意:try…catch中的err不属于任何作用域,只能被catch访问