何如理解js的作用域

我们对js的日常认知是否是因为自己眼睛所看见的代码从而执行呢?例如:下面这段简单代码,大家肯定都知道答案。那么大家知道这是为什么吗?下面我就给大家做一个详细的解答,输出10的原理到底是什么!那就是我们所要了解的作用域了!

var aa = 5;
function a (){
	var aa = 10;
	console.log(aa);
}
a()//10

1.作用域 [[scope]]

每个javascript函数都是一个对象, 对象中有些属性我们可以访问,但有些不可以,这些属性仅供javascript引擎存取,[scope]]就是其中一 个。[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合。

作用域链: [[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链

上面就是作用域的解释,但我知道大家看不懂,下面我给大家重新讲解一下。我们所说的作用域。
当一个函数,它被定义的时候,记住!当被定义时候,那么它的作用域就生成了!叫做[[scope]],例如:

var aa = 5;
function a (){
	var aa = 10;
	console.log(aa);
}
a.[[scope]]  那么此时,a的作用域形成了,那他里面有什么呢,让我给大家来说明:
[[scope]指的就是我们所说的作用域,其中存储了运行期上下文的集合(GO,AO)。函数的作用域取决于函数所处的位置,
此时a函数在window中,所以在a的作用域就链着GO,也就是全局作用域。a.[[scope]]里面是键值对形式,一开始的键值对是0GO
a.[[scope]] ———> 0GO{ aa : 5, a : function a (){}}

如果此时,我们来执行 a 函数,那么它的作用域就会发生变化!

var aa = 5;
function a (){
	var aa = 10;
	console.log(aa);
}
a()// 10

因为在函数执行的前一刻会生成函数的 运行期上下文,简称AO对象,所以此时,我们的作用域中就会多出
一个AO对象(下面所写为函数执行时的AO),然后将GO往下挤,所以第0位就变成了a的AO
a.[[scope]] ———> 0: AO{ aa : 10}
			———> 1: GO{ aa : 5, a : function a (){}}
所以我们输出的答案aa是10,因为我们优先再我们自身作用域中寻找aa,如果没有再向下一层(上一级)寻找aa。(也就是GO对象中)

这才是我们真正输出10的原理。

这就是最最基本的函数作用域!(如果有不知道GO对象 和 AO对象的是什么 或者不知道 如何生成的,可以参考我上篇博客,预编译!)

2.作用域链

上面我们就简单了解了什么是函数作用域,和作用域叫什么,它里面存放的是什么。下面我就给大家讲解一下,什么叫做作用域链:

        var aa = 55;
        function a() {
            var aa = 100;
            function b() {
                aa++
                console.log(aa)
            }
            b()
        }
        a() // 101

根据我们上方对作用域的了解,我来给大家画一张作用域链的图,只要可以有助于大家更好的理解:
首先是我的a函数定义:

此时a函数在window中,所以在a的作用域中有着GO,也就是全局作用域。所以:
a.[[scope]] ———> 0: GO{ aa : 55, a : function a (){}}
紧接着就是a函数的执行:自己生成AO会将GO往下挤
a.[[scope]] ———> 0: aAO{ aa : 100, b :function (){} }
			———> 1: GO{ aa : 55, a : function a (){} }
当a函数执行时,那么b函数就被定义了!当b函数定义时,它是站在a函数中,所以b函数的作用域在生成的时候,是站在a函数的肩膀上,所以他就有着a函数的AOGO
b.[[scope]] ———> 0: aAO{ aa : 100, b :function (){} }
			———> 1: GO{ aa : 55, a : function a (){} }
当随着代码的执行,b函数也开始执行:b函数就会生成一个属于自己的AO对象:自己生成AO会将a函数的aAO 和 GO 往下挤
b.[[scope]] ———> 0: bAO{}
			———> 1: aAO{ aa : 100, b :function (){} }
			———> 2: GO{ aa : 55, a : function a (){} }

然后执行我们的b函数代码,a++,我们先在我们的b函数自身的AO对象中寻找a变量,但是没有找到,所有就往上层查找,就在aAO中找到了aa,然后使用修改了这个aa的值,并且输出。

当我们的b函数输出完毕后,就代表了b函数执行完毕,当函数执行完毕后它就是放弃自己生成的bAO对象,随着a函数执行完毕,a函数也执行完毕,它也会放弃自己这次生成的aAO对象,随着aAO对象消失,b函数就不见了,那么b函数的作用域也就会消失,最后只剩下a函数的作用域。

这便是最最简单的作用域链形成和运用!
谢谢大家的浏览~~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值