作用域指程序中定义变量的区域,它决定了当前执行代码对变量的访问权限。 作用域就是一个独立的地盘,让变量不会外泄、暴露出去,也就是说 作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
全局作用域和函数作用域
全局作用域的情况
- 最外层函数和在最外层函数外面定义的变量拥有全局作用域。
- 所有未定义直接赋值的变量拥有全局作用域。
- 所有window对象的属性拥有全局作用域
全局作用域有个弊端:如果我们写了很多行 JS 代码,变量定义都没有用函数包括,那么它们就全部都在全局作用域中。这样就会 污染全局命名空间, 容易引起命名冲突。
// 不带var的情况,相当于给window对象设置一个属性
// 1
console.log(a, b)
var a =12, b ='林一一'
function foo(){
// 2
console.log(a, b)
// 3
var a = b =13
console.log(a, b)
}
foo()
console.log(a, b)
/* 输出:
undefined undefined
undefined "林一一"
13 13
12 13
*/
函数作用域
是指声明在函数内部的变量,和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部。
值得注意的是:块语句(大括号“{}”中间的语句),如 if 和 switch 条件语句或 for 和 while 循环语句,不像函数,它们不会创建一个新的作用域。
块级作用域
块级作用域可通过新增命令let
和const
声明,所声明的变量在指定块的作用域外无法被访问。在大括号中使用let
和const
声明的变量存在于块级作用域中。在大括号之外不能访问这些变量。
- 声明变量不会提升到代码块顶部
- 禁止重复声明
- 循环中的绑定块作用域的妙用
for (let i = 0; i < 10; i++) {
// ...
}
console.log(i);
// ReferenceError: i is not defined
作用域链
当前作用域没有定义的变量,这称为 自由变量 。
Javascript
的作用域也可以嵌套,Javascript
引擎会层层遍历作用域来寻找用到的变量,这种一层一层的关系就是 作用域链。
取自由变量x
的值时,要到哪个作用域中取?——要到创建fn
函数的那个作用域中取,无论**fn**
函数将在哪里调用。
var x = 10
function fn() {
console.log(x)
}
function show(f) {
var x = 20
(function() {
f() //10,而不是20
})()
}
show(fn)
var a = 10
function fn() {
var b = 20
function bar() {
console.log(a + b) //30
}
return bar
}
var x = fn(),
b = 200
x() //bar()
//fn()返回的是bar函数,赋值给x。执行x(),即执行bar函数代码。取b的值时,直接在fn作用域取出。取a的值时,试图在fn作用域取,但是取不到,只能转向创建fn的那个作用域中去查找,结果找到了,所以最后的结果是30