阅读 279

JavaScript块级作用域

前言

这次的问题是自己在验证块级作用域一些相关的作用偶然发现的,虽然今后代码工作中不太可能出现这种错误,但是就怕万一呢,所以还是记录一下。

块级作用域

这是ES6中明确提出的除了全局作用域和函数作用域之外的另一个作用域。关于块级作用域具体的内容我就不详细说明了,指路阮一峰老师ECMAScript6入门,里面有很详细的块级作用域相关介绍

接下来就是重头戏,块级作用域的函数声明和变量声明

变量声明

我们首先来看变量声明

{
  let a = 10;
}
console.log(a)// a is not defined

-------

{
  var a = 10;
}
console.log(a)// 10
复制代码
  • 上面的代码,块级作用域中let声明的变量只在该作用域有效,所以会报错。而var声明的变量是会发生变量提升到全局作用域var a = undefined,再经过a= 10赋值,因此打印出10,很清楚对吧。重头戏来了
console.log(a);//ReferenceError: a is not defined
{
    a = 10;
    console.log(a)//10
}
console.log(a);//10
复制代码
  • ???WHY?,默认变量a = 10不是默认为var a = 10吗,应该会提升到全局作用域的顶部,但是它报错了
{
    console.log(a);//ReferenceError: a is not defined
    a = 10;
    console.log(a)
}
console.log(a);

复制代码
  • 这次我在块级作用域中变量a赋值之前打印,发现也是报错,也就发现了,在a=10之后,变量a把默认声明的变量提升到了全局作用域

  • 小结

  1. 在块级作用域中默认声明的变量(不用var、let...),只有代码执行到声明语句之后,才可以进行访问,否则会报错。
  2. 在块级作用域中默认声明的变量会被提升到全局作用域(但是要在声明语句之后才能被访问到)

函数声明

console.log(a);//undefined
{
    function a(){}
}
复制代码
  • 上面的代码很正常对吧,参照以下的块级作用域函数声明的相关规则,函数声明类似于var,会被提升到全局作用域的头部 ,因此打印undefined·

image.png

同名变量

以为就这样结束了,怎么可能,我又作死的试试了同名变量,果不其然试出问题了

console.log(a);//undefined
{
    console.log(a);// function a(){}
    function a() {};
    a = 10;
    console.log(a); //  10
};
console.log(a); //function a(){}
复制代码
  • ???最开始的我一脸懵逼,最后一步为什么会打印函数呢?后来我又仔仔细细的把块级作用域、默认变量、函数声明的知识又看了一遍,知道自己错在哪里了
  1. 块级作用域中函数 a 类似于var变量被提升到全局作用域,var a = undefined,同时被提升到块级作用域的顶部function a(){}
  2. 默认变量a=10只有在执行之后才会能被访问到,也就是说现在不用管它
  3. 开始执行代码,首先打印a为undefined
  4. 执行块级作用域代码:打印a,由于第一步的函数声明提升,所以会打印出function a(){};之后执行function a(){},全局作用域中的变量a赋值为一个函数;接着执行a = 10,此时需要注意,JS引擎这一步会进行LHS查询(具体见《你不知道的JavaScript上》),查找变量a,此时它在块级作用域中会找到定义好的a,并且为它赋值,此时不会发生变量提升,这时块级作用域中的a=10
  5. 接着执行全局作用域中的console,自然打印出function a(){}

以为就这样结束了?我又作死的换了一下顺序,这下可好,又不一样了。。。

console.log(a);//undefined
{
    console.log(a);//function a(){}
    a = 10;
    function a() {};
    console.log(a); // 10
};
console.log(a); // 10
复制代码
  • 直接进入正题

前俩个console打印没有问题吧,直接开始执行a = 10,按照上一个讲解这时候是为块级作用域中的变量a赋值。因此这时候块级作用域中a = 10。接下来执行function a(){}此时这一行代码为函数声明语句,所以执行完这一语句之后,块级作用域中的a依然是10,而全局作用域中的a也赋值为10,因此最后打印的a都为10.

  • 小结

块级作用域中只有执行完函数声明语句之后,才会去重写对应的全局作用域上的全局变量

总结

虽然以上的一些错误可能在日常代码中不怎么会碰到,但是我还是觉得多了解了解也是好的,这对我们理解Javascript还是有很大的帮助的,希望能通过这篇文章,能更好的理解块级作用域吧

文章分类
前端
文章标签