关于闭包,作用域,作用域链

用域有以下几种

  1. 全局作用域 (声明在任何函数之外的顶层作用域的变量就是全局变量,这样的变量具有全局作用域)
  2. 函数作用域(在函数内部定义的变量)
  3. 块作用域(在大括号里用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个定时器同时到期,同时执行。

解决方法如下

  1. 用一个函数把setTimeout包起来,这样每次循环的时候都能拿到变量i并且存起来
var output = function(j){
  setTimeout(function(){
     console.log(j)
	 },1000)
}
for(var i=0; i<5; i++){
  output(i)
}
  1. setTimeout外面套一个立即执行函数
for (var i=0;i<5;i++){
	(function(j){
		setTimeout(function(){
			console.log(j)
		}, 1000)
	})(i)
}
  1. var 改成es6的let
for (let i=0; i<5; i++){
	setTimeout(function(){
		console.log(i)
	}, 1000)
}

闭包在实际开发中的作用

  1. 模拟私有变量,保护敏感数据如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

  1. 偏函数与柯里化
    还不是很理解,待续
posted @ 2021-07-05 17:16  小白yang  阅读(103)  评论(0)    收藏  举报