浅谈JavaScript作用域,作用域链,预编译

之前写过一篇关于预编译和作用域的博客,最近更深入的去了解了一下,发现写的真是屎,这次算上作用域链从新纪录一下我自己的理解。(如果这篇文章有什么问题请及时联系我)!

预编译

js是一种解释型语言,解释一句执行一句。
js运行有三步
一.语法检测:是否有语法问题?
二.预编译
变量和函数的提前声明
全局预编译
1. 创建一个GO对象 Global Object
2. 将var关键字声明的变量当作GO对象的属性,赋值为undefined,有重名的直接覆盖
3. 将function关键字声明函数 当作GO对象的属性,值为函数体,重名直接覆盖
函数预编译
函数执行的前一刻开始
4. 创建一个AO对象 Activation Object 执行期上下文对象
5. 函数的形参,成为AO对象的属性,值为实参的值,若未传值,值为undefined
6. 将var关键字声明的变量,成为AO对象的属性,值为undefined,遇到已经存在的,不做任何变化
7. 将function声明的函数 成为AO对象的属性 值为函数体,重名直接覆盖

三.代码执行
预编译的例图:

在这里插入图片描述

作用域

作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性
在es6之前只有全局作用域以及函数作用域,今天我们不考虑es6的let和const。

  1. 全局作用域
    写脚本块中的代码
    全局作用于中声明的变量,会被提前到代码块的顶部进行定义,成为全局对象的属性
  2. 函数作用域
    函数内部定义的变量,会被提升到函数代码块中的顶部,并且不会成为全局对象的属性

作用域链

在js代码进行预编译的时候生成的GO以及AO对象,形成了一种链式结构。
提到作用域链那就要说一下函数的[[scope]]属性。
[[scope]] :执行期上下文对象集合,
也就是说你生成的GO和AO对象被保存在每个函数的[[scope]]里(但是我觉得指向这个对象的地址更准确些

function a(){
            function b(){
                var bb = 234
            }
            var a = 123;
            b();
        }
        var glob = 100;
        a();

像上面的这段代码,在进行预编译时首先生成了全局的GO对象保存了处于全局对象的变量以及函数,

函数a()进行定义时,a.[[scope]]的集合里保存了GO对象(第0项),在函数执行时创建了a的Ao对象并保
存a里定义的变量和函数,然后将AO对象存入a.[[scope]]里,此时第0项为a的Ao对象,第1项为GO对象。

函数b()进行定义时,b.[[scope]]的集合里保存了a的Ao对象(第0项)和GO对象(第1项),在函数执行时创建了b的Ao对象并保
存b里定义的变量和函数,然后将b的AO对象存入b.[[scope]]里,此时第0项为b的Ao对象,第1项为a的Ao对象,第2项为GO对象。

那么这个是怎么用的呢?
如果我在b函数里想使用一个变量,而b()函数没有这个变量,那么他就会从自己的第0项开始找,一直向后找,直到找到全局的G0对象。
这些G0和AO对象形成了一种链式结构,这就是作用域链。

具体如下图:

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值