关于闭包,作用域,作用域链
用域有以下几种
- 全局作用域 (声明在任何函数之外的顶层作用域的变量就是全局变量,这样的变量具有全局作用域)
- 函数作用域(在函数内部定义的变量)
- 块作用域(在大括号里用let和const定义的变量)
作用域链
在查找变量的过程中,层层递进的作用域,就形成一条作用域链
闭包
下面的例子中,函数add下没有该作用域下的变量,add的上一级addAbc下有两个,addAbc的上一级有一个。作用域链就是add->addAbc->global。像add这样引用了不属于自己作用域的自由变量的函数,就叫做闭包。
function addAbc(){
var a =1,b=2;
return function add(){
return a+b+c;
}
}
var c = 3;
var myAdd = addAbc();
myAdd();
闭包真题
for (var i=0; i<5; i++){
setTimeout(function(){console.log(i)},1000)
}
我们先看函数执行的地方function(){console.log(i)},这里的i不存在于当前函数作用域,这里就形成一个闭包,那我们根据作用域链向上去找。因为这里有个setTimeout,所以我们在1000ms后才会去执行这个函数,此时去找i已经变成了5,所以最终会输出5个5。注意是同时输出5个5而不是间隔1秒后输出,因为for循环会在瞬间产生5个定时器,5个定时器同时到期,同时执行。
解决方法如下
- 用一个函数把setTimeout包起来,这样每次循环的时候都能拿到变量i并且存起来
var output = function(j){
setTimeout(function(){
console.log(j)
},1000)
}
for(var i=0; i<5; i++){
output(i)
}
- setTimeout外面套一个立即执行函数
for (var i=0;i<5;i++){
(function(j){
setTimeout(function(){
console.log(j)
}, 1000)
})(i)
}
- var 改成es6的let
for (let i=0; i<5; i++){
setTimeout(function(){
console.log(i)
}, 1000)
}
闭包在实际开发中的作用
- 模拟私有变量,保护敏感数据如password
const User = (function(){
let _password; //定义私有变量
class User{
constructor(username, password){
_password = password;
this.username = username;
}
login(){
console.log(this.username, _password)
}
}
return User;
})()
const user = new User('lizzy','yang')
user.username;
这里有问题,如果创建2个实例,那后面实例的password会覆盖之前的password
- 偏函数与柯里化
还不是很理解,待续

浙公网安备 33010602011771号