JS预编译及作用域链

所谓预编译就是将变量声明提前,函数声明提前
其中变量声明的优先级与函数声明的优先级需要弄清楚,大多数认为函数声明的优先级大于变量声明的优先级
从浏览器的预解析说起:

  1. 搜寻关键字(即var function)
  2. 执行预解析
    a:先使var关键字声明的标识符有定义
    (标识符有定义后就不会报错,但未赋值)
    b:标识符中保存函数的引用

从小案例开始

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

在这里插入图片描述
为什么第一个控制台输出会是函数体?它没有被定义,应该会报错!
为什么第三个控制台输出会是10?它前一行的函数没有用吗?

首先,在js中所有的函数声明和变量声明都会提前,如果变量和函数在全局作用域中,js则会将其声明放在全局作用域的顶端,若是局部作用域中的变量,会将其声明放在局部作用域的顶端。
其次,若变量与函数名同名,需要注意的是函数声明的优先级大于变量声明的优先级,因此会将变量中的undefined替换。
最后,执行相应赋值等操作。

var  a; -->声明变量a 此时a的值为undefined -->函数声明,此时a为function a(){}
//此刻预编译已完成,开始执行
congsole.log(a)
//此时a为function a(){}
a = 10;-->将10赋给a,a的值此刻变为10
console.log(a); -->10
console.log(a); -->10
预编译的具体步骤

从小案例可以看出JS加载时会通篇扫描,将含有var和function关键字的声明,提到最前面,并将var声明的变量初始化为undefined,function则出示化为函数值
从而依次执行
在复杂的函数中,其预编译具体是怎么实现的呢(函数的预编译发生在函数执行的前一刻)

function test(a,b,c){
  a= 10;
  console.log(b);
  b = 7;
  function a(){}
  console.log(a)
  console.log(d)
  if(b){
    c= 20;
    function d(){}  
  }
  console.log(d)
  console.log(c)
}
test(3)

函数执行时会创建一个(将所有的变量声明提前)
AO(Activation Object 即活跃对象){
a:undefined
b:undefined
c:undefined
d:undefined
}
–>(将函数中的实参与形参统一)
AO{
a:3
b:undefined
c:undefined
d:undefined
}
–>AO(将函数声明提升){
a: function a(){}
b:undefined
c:undefined
d:undefined
}
–>(预编译结束,函数执行,从上到下依次执行,若遇到错误,立即停止,之后的代码,便不在执行)
AO{
a: 10
b:undefined
c:20 -->tips:if(){}不管能否执行,其中声明的变量或者函数都会提前
d:function d(){}
}
在这里插入图片描述
若在全局作用域中,预编译是怎么执行呢
在上一个例子中,
首先创建 GO(global object)函数作用域{
test:function test(){…}
}
其次创建函数test 的AO(其分析与函数预编译一样)
值得注意的是AO 中声明的变量是局部变量,在函数外部不能使用

作用域链

所谓作用域链,就是当声明一个函数时,局部作用域一级一级包裹起来,就是作用域链
即:执行函数时,需要某个变量,自身局部作用域中没有,向上一级寻找,直到找到为止

var a= 10;
function test(){
 var a= 3;
 function show(){
console.log(a)
}
show()
}
test()

当执行show时,创建函数show的执行环境(AO),并将其放置与链表开头,其次时test的执行环境,最后是window,即 show AO–>test AO -->window GO
在函数show中需要在控制台输出a,而自身本没有,因此需要向上一级寻找,找到了,a =3,找到之后就不在寻找,输出结果。

发布了28 篇原创文章 · 获赞 2 · 访问量 2921

猜你喜欢

转载自blog.csdn.net/weixin_45725020/article/details/103015309
今日推荐