【JS】闭包与作用域

作用域

作用域是根据名称查找变量的一套规则。如果查找的目的是对变量进行赋值,那么就会使用LHS查询,如果是为了获取变量的值,就会使用RHS查询。
例如:var a=2在JS引擎进行编译时,会执行下面两个操作:

  • 第一步在其作用域中声明新变量
  • 接下来a=2会查询变量a(LHS查询)并对其赋值

在作用域中查找变量的操作LHS和RHS查询会根据下面作用域链查找顺序进行查找,不成功的RHS引用会抛出ReferenceError异常,而非严格模式下不成功的LHS引用会导致自动隐式地创建一个全局变量,严格模式下的不成功LHS引用会抛出ReferenceError异常

作用域链:当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用(就近原则)。如果没有则向上一级作用域中寻找,直到找到全局作用域;如果全局作用域中依然没有找到,则会报错 ReferenceError。

let a=1;
function fn1(){
	function fn3(){
		function fn2(){
			console.log(a);//undefined
		}
		let a;
		fn2();
		a=4
	}
	let a=2;
	return fn3;
}
let fn = fn1()
fn() //undefined

作用域的预处理:浏览器在解析JS代码之前,会进行“预处理”,将当前JS代码中所有变量定义函数定义放到代码的最前面.
注意:

  • 如果没有用var关键字声明变量(直接写a=1),则变量不会被声明提前
  • 使用函数表达式创建的函数不会被声明提前
  • 使用let声明的变量不会在块作用域中进行提升

作用域主要可以分为以下三种

  • 全局作用域:作用于整个script标签内部或作用于一个独立的JS文件
  • 函数作用域:作用于函数内的代码环境
  • 块级作用域:{}包裹起来的代码块,外部也可以访问块级作用域内var声明的变量,而letconst声明的变量是不能访问的

作用域的访问关系:在内部作用域中可以访问到外部作用域的变量,在外部作用域中无法访问到内部作用域的变量

函数作用域

函数作用域的预处理: 在函数作用域中也有声明提前的特性

  • 函数中,使用var关键字声明的变量会在函数中所有的代码执行之前被声明
  • 函数中,没有var声明的变量都是全局变量,而且不会提前声明
fun();//保错
var fun = function(){
 console.log('hhh')
}

函数预编译的步骤:

  • 创建AO对象(Activation Object,执行期上下文)
  • 将形参名和变量作为AO的属性名,值为undefined
  • 将实参值和形参统一并赋值
  • 查找函数声明,将函数名作为AO的预编译,值为整个函数体

词法作用域

词法作用域就是定义在词法阶段的作用域,是在写代码时将变量和作用域写在哪里来决定的,都只由函数被声明时所处的位置决定的。JS中有eval(...)with这个两个机制来欺骗词法作用域,但是会导致引擎在编译时无法对作用域查找进行优化,导致代码运行变慢,不能使用它们。

闭包

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域哇执行
一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的。闭包在处理速度和内存消耗方面对脚本性能有负面影响,一般不要使用闭包。

在这里插入图片描述
参考链接:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值