预编译和作用域

预编译

JavaScript的执行可以看做三步:
	1. 检查语法错误,这一步通常可以通过IDE看出来。
	2. 预编译的过程
	3.从上往下,解释一行,执行一行
console.log(a);
console.log(a)// 这里是中文逗号,一般编辑器都会在这飘红报错

执行代码,报错 SyntaxError: Invalid or unexpected token,这个错误表示语法错误,而不是没有声明变量的referenceError。

GO和AO

GO: global object,全局对象,这个对象会存在全局声明的变量和函数。
比如: var a; => GO={a: undefined}
AO: active object,和GO类似,不过AO是函数执行时,函数作用域中存在的对象。保存了这个函数作用域里面的变量和函数表达式。

预编译过程

预编译可以分为五步:

  1. 全局执行存在GO,函数执行会创建AO,这里以AO为例
  2. 寻找这个函数的形参和 变量声明,放在AO对象里面。
  3. 将传入的实参赋值给实参
  4. 寻找这个作用域内的函数声明,并且保存在实参里面
  5. 函数执行
    在这里插入图片描述
    通过这个例子可以看出, a 后声明 为变量,但是结果为function a。如果预编译从上往下执行,a 的结果会是 undefined,那么只能是先提升 var a ,然后再是 function a ,所以结果为 function a。

特例
在 ES6之前,可以直接 a = 1, ES3和ES5会在window上面增加属性,使windwo.a = 1。在ES6这种方式则会报错。
在实际开发中,经常存在函数中执行函数的情况,这时获取变量的值就设计到作用域和作用域链

作用域和作用域链

在JavaScript中,函数也是一种对象,存在一个JS内部固有的隐式属性[[scope]]。
[[scope]]是函数存储作用域链的容器 。这个容器会存储函数的AO,GO。
函数执行完成,如果没有外部变量引用函数内部变量,函数的AO是会被销毁的。

function a () {
  function b () {

  }
}

b();
  1. 在代码执行前,全局检查语法错误,没有错误则进行预编译。在预编译过程中,全局函数a被定义,js引擎生成[[Scope]]属性,保存着函数的作用域链,该作用域链的第0位存储当前环境的全局执行上下文GO
  2. 在全局函数被执行前一刻,作用域顶端(第0位)存储函数生成的执行上下文AO,第一位是GO。查找变量是从函数存储的作用域从上往下找
  3. b函数在a函数里面,b函数在a函数执行是被定义,b函数此时的作用域链就是a函数的作用域链。
  4. b 函数执行前一刻,生成b函数的[[scope]],存储b函数的作用域链。顶层是b函数的AO,a函数的AO和 全局的GO,从上往下依次排序
  5. b函数执行完毕,如果没有外部变量访问函数的AO,那么AO就将被销毁 。

这种函数执行形成的链式作用域就叫做作用域链。可以看出,函数的作用域同函数在哪执行没有关系,而是与函数在哪被定义有关。函数被定义时,[[scope]]保存了定义当前函数的作用域,执行时,将自己的AO插入到[[Scope]]的第0位。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值