1. 作用域
作用域指的是变量存在的范围,有如下三种:
- 全局作用域(变量在所有地方都可以读取)
- 函数作用域(变量只在函数内部存在)
- 块级作用域(ES6新增,需结合
let
和const
关键字使用)
函数本身作为一个值,也有其自身的作用域。函数的作用域就是函数声明时所在的作用域,而与函数调用时的作用域无关。这一特点就导致了“闭包”现象。
2. 闭包
函数内部形成一个函数作用域,函数内部可以读取函数本身所处的作用域及上级作用域的变量,但函数外部不能访问定义在函数内部的变量:
let a = 123
function f1() {
console.log(a)
let b = 456
}
f1() // 123
console.log(b) // Uncaught ReferenceError: b is not defined
而闭包则提供了一种函数外部访问函数内部变量的方式,主要有两种形式:
- 函数作为参数被传递
- 函数作为返回值被返回
// 函数作为参数被传递
function print(func) {
let a = 123
func()
}
let a = 456
function f1() {
console.log(a)
}
print(f1) // 456
// 函数作为返回值被返回
function create() {
let b = 123
return function() {
console.log(b)
}
}
let f2 = create()
let b = 456
f2() // 123
在第一个例子中,f1
作为参数传递给print
,在print
内部调用f1
并打印变量a
。f1
声明时所处的作用域是全局作用域,因此会在全局作用域中寻找变量a
,故而控制台打印结果就是456
。
在第二个例子中,create
返回一个函数,并将该函数赋值给f2
并调用以打印变量b
。打印变量b
的函数是在create
的函数作用域中声明的,因此会首先在这个函数作用域中寻找变量b
,故而控制台打印结果是123
。
总结起来,函数内部的自由变量(变量在当前作用域未声明但却被使用,如上面例子中的变量a
和b
)的查找,要从函数声明时所处的作用域开始,而与函数被调用时所处的作用域无关。
网友评论