作为js的三座大山之一的闭包。
闭包原理:函数作用域,垃圾回收机制,作用域链
一个一个来
函数作用域是什么呢?
首先,js的作用域分为函数作用域和静态作用域
静态作用域指的是一段代码,在它执行之前就已经确定了它的作用域,简单来说就是在执行之前就确定了它可以应用哪些地方的作用域(变量)。
动态作用域–函数的作用域是在函数调用的时候才决定的
- 调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
- 每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的
- 在函数作用域中可以访问到全局作用域的变量
- 在全局作用域中无法访问到函数作用域的变量
- 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用
如果没有则向上一级作用域中寻找,直到找到全局作用域,
如果全局作用域中依然没有找到,则会报错ReferenceError - 在函数中要访问全局变量可以使用window对象
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo();
}
bar();
// 结果是 1
假设JavaScript采用静态作用域,让我们分析下执行过程:
执行 foo 函数,先从 foo 函数内部查找是否有局部变量 value,如果没有,就根据书写的位置,查找上面一层的代码,也就是 value 等于 1,所以结果会打印 1。
假设JavaScript采用动态作用域,让我们分析下执行过程:
执行 foo 函数,依然是从 foo 函数内部查找是否有局部变量 value。如果没有,就从调用函数的作用域,也就是 bar 函数内部查找 value 变量,所以结果会打印 2。
前面我们已经说了,JavaScript采用的是静态作用域,所以这个例子的结果是 1。
看到这里我们就可以看出闭包是使用动态作用域的。
为什么闭包使用动态作用域的呢
JavaScript 函数的执行用到了作用域链,这个作用域链是在函数定义的时候创建的。嵌套的函数 f() 定义在这个作用域链里,其中的变量 scope 一定是局部变量,不管何时何地执行函数 f(),这种绑定在执行 f() 时依然有效。
下面的例子是结合上了立即执行函数
function create(){
var result=new Array()
for(var i=0;i<10;i++){
result[i]=function(num){
return function (){return num}()
}(i)
}
return result
}
console.log(create()) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
插播:执行上下文是什么?
执行上下文包括了变量对象,作用域,this指针
最后再来顺一遍,js代码编译执行过程吧
一个js文件,首先编译器先进行编译,把它转化为可执行代码
这个过程编译器做了什么工作呢?(如上图)
闭包其他的原理之前已经写过啦。