函数作用域
函数内部的全部变量都可以在整个函数范围内使用和复用, 函数外部无法访问到这些变量
function bar() {
var a = 1
function foo(b) {
console.log(a + b)
}
foo(3)
}
bar() // 4
// 外部访问这些变量, 会抛出异常
> console.log(a)
< ReferenceError: a is not defined
> foo(3)
< ReferenceError: b is not defined
对函数的传统认知就是先声明一个函数,然后再向里面添加代码。但反过来想也可以带来 一些启示:从所写的代码中挑选出一个任意的片段,然后用函数声明对它进行包装,实际上就是把这些代码“隐藏”起来了。换句话说,可以把变量和函数包裹在一个函数的作用域中,然后用这个作用域 来“隐藏”它们。
用途
1. 避免暴露过多变量或函数,阻止对内部变量访问,减少破坏可能性。
2. 规避变量冲突,当程序中加载了多个第三方库时,如果它 们没有妥善地将内部私有的函数或变量隐藏起来,就会很容易引发冲突。
3. 用于模块管理,利用作用域的规则强制所有标识符都不能注入到共享作用域中,而是保持在私有、无冲突的作用域中。
块作用域
ES6 以前, Javascript 并不存在块作用域
for (var i = 0; i < 10; i++) {
console.log(i) // 0,1,2,...,9
}
console.log('window', i) // window 10
在循环中使用的i
变量,会被声明为全局变量
if (true) {
var k = 20
console.log(k) // 20
k++
}
console.log('window', k) // window 21
if
代码块相同
try {
throw undefined
} catch (a) {
a = 2
console.log(a) // 2
}
console.log(a) // ReferenceError: a is not defined
ES3 的 try/catch
的 catch
语句中会形成一个天然的 块作用域,可丑陋且难以理解
let/const
let/const 关键字可以将变量绑定到所在的任意作用域中(通常是 { .. }
内部)。换句话说,let/const 为其声明的变量隐式地了所在的块作用域。
// for 循环头部的 let 不仅将 i 绑定到了 for 循环中, 事实上它将其重新绑定到了循环的每一个迭代中, 确保使用上一个循环迭代结束时的值重新进行赋值
for (let i = 0; i < 10; i++) {
console.log(i) // 0,1,2,...,9
}
console.log('window', i) // ReferenceError: i is not defined
{
const a = 1
const b = 2
}
let c = a + b // ReferenceError: a is not defined