前言
本文章源自《JavaScript知识小册》专栏,感兴趣的话还请关注点赞收藏.
上一篇文章:《JavaScript一文让你搞清什么是原型和原型链》
下一篇文章:《JavaScript令人心烦的this》
作用域
JavaScript中作用域
即表示一个变量的合法使用范围
,也就是变量在什么范围内可以被使用,超出了这个范围,变量将不能被读取到,会抛出异常
全局作用域
全局作用域
跟当前JavaScript
的运行环境关联,在全局作用域
中定义的变量可以在js
文件中随意访问
let a = 100
console.log('a is ', a)
输出a is 100
函数作用域
函数作用域
则限制了在函数中定义的变量,只能在该函数体内被访问到
function printB(){
let b = 200
console.log(`b is ${b}`)
}
printB() // 输出 b is 200
console.log(b) // 会报错Uncaught ReferenceError: b is not defined
块级作用域
块级作用域
是ES6
后的新增特性,比函数作用域
更加细粒度
function printB(){
let b = 200
console.log(`b is ${b}`) // 输出 b is 200
if (true){
let c = 300
console.log(`c is ${c}`) // 输出 c is 300
}
console.log(c) // 报错,Uncaught ReferenceError: c is not defined
}
printB() // 执行方法
自由变量
自由变量
即一个变量在当前作用域中没有定义,但是却要使用,那么就只好向上级作用域开始,一层层寻找,直到找到为止,如果一直到全局作用域都没找到,则会报错xxx is not defined
let a = 100 // 全局作用域
function printB() { // 函数作用域
let b = 200
if (true) { // 块级作用域
let c = 300
let result = a + b + c
console.log(result)
}
}
printB() // 输出600
像以上例子,let result = a + b + c
,在当前块级作用域
中仅有变量c
,并没有变量a
和变量b
,那么会往上一级作用域进行查找
,接着在函数作用域
中找到了变量b
,但是还是找不到变量a
,那么就再往上一级查询,最后顺利查询到了变量a b c
并累加得出结果。如果从当前函数作用域查询,直到查询到全局作用域
还是没找到变量,那么就会抛出异常xxx is not defined
。
这也解释了为什么前面的在函数作用域
访问变量c
会报错的原因,因为在当前函数作用域
找不到变量c
,只会再往上一级全局作用域
进行查找,但变量c
只存在于块级作用域
中,所以最终会报错。
闭包
闭包
算是作用域
的一种特殊情况,跟上边的写得相对固定的作用域嵌套的代码不同,闭包
特殊在函数作为参数被传递,同时函数也可以作为返回值被返回
函数作为返回值
function printA() {
let a = 100 // 2.查询到变量a
return function () {
console.log(`a is ${a}`) // 1.当前作用域不存在a,向上级作用域查询
}
}
let fun = printA()
let a = 200
fun() // 3.输出 a is 100
函数作为参数
function printA() {
console.log(`a is ${a}`) // 当前没有变量a,向上查询,这里的上级作用域则是全局作用域
}
let a = 200 // 全局作用域
function print(fn) {
let a = 100 // 函数作用域
fn() // 实际调用printA()
}
print(printA) // 输出 a is 200
这里需要注意的是向上查询的作用域在编写代码时就已经决定了,不会因为函数在哪里被调用的从而影响到向上查询的作用域发生变化
。记住这个原则就能搞明白为什么a is 200
。
let a = 100; fn();
那里的变量a
只是混淆视听罢了。