深入理解javascript作用域、作用域链

javascript作用域、作用域链

为了深度理解javascript作用域链的产生,本文会和预编译过程一起分析。(如果你并不知道预编译过程,请点击这里:js预编译

执行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象(AO)。
函数每次执行时对应的上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行期上下文。
当函数执行完毕,它所产生的执行期上下文被销毁。(简答说就是函数执行,创建AO,执行完,销毁AO,再执行函数,再创建新AO,执行完再销毁AO…)
[[scope]]:内部属性,指的就是我们所说的作用域,其中存储了执行期上下文的集合。(函数被创建的时候生成)
作用域链:[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式连接,我们把这种链式连接叫做作用域链。

看个小demo:

	function Father() {
		function Son() {
			var er = 234;
			console.log(ba);
		}		
		var ba = 123;
		return Son;
	}
	var global;
	var newson = Father();
	newson();
	

上面代码执行,控制台会打印123。
【问】函数执行完应该把变量销毁,为什么还能打印出变量ba呢?看完你就知道答案了。

下面开始分析代码运行过程:
首先,全局预编译生成GO(Global Object)对象

	GO{
		global : undefined,
		newson : undefined,
		Father : function Father() { ...函数体 }
	}
	

此时,Father()函数被创建,Father()作用域链中插入GO对象。
scope
程序运行,调用Father()函数(倒数第二行代码),预编译创建AO对象:

	AO{
		ba : undefined,
		Son : function Son() { ...函数体 },
	}
	

Father()函数执行,Father()作用域链中插入AO对象。
scope
同时,Son()函数创建,Son()作用域链初始化(直接将Father()作用域链复制一份
scope

然后执行语句 ba = 123;AO里的ba变量被赋值,AO{ ba : 123,… }

Father()执行完毕,return Son。
同时销毁AO对象(其实是销毁指针,找不到了而已)
socpe
程序继续执行,执行newson();(最后一行代码)。newson只是函数Son()的别名,实际是执行函数Son();
Son()函数执行,创建AO对象,并插入到Son()函数作用域链最顶端。
scope
执行语句 console.log(ba)根据作用域链,自上而下找ba变量(第一个AO没有,第二个AO有),找到后打印输出: 123。

最后newson()函数执行完,销毁AO
scope

上面程序运行过程中,虽然函数Father()执行期上下文已经被销毁,但是函数Son()被return出去了,依然可以通过作用域链访问变量ba,Son也被称为闭包。

【总结】函数创建的时候,会复制父级作用域链中已有对象。函数执行的时候,会创建AO对象,放在自己作用域链的顶端。函数执行完,会销毁自己的AO对象,从父级继承(复制)到作用域中的对象不销毁。
当内部函数在外部执行时,仍可以访问父级函数的内部变量,这就是闭包的概念。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值