你真的懂switch吗?聊聊switch语句中的块级作用域

LogicVoyagerPro
• 阅读 8497

  最近在代码中不小心不规范的,在switch里面定义了块级变量,导致页面在某些浏览器中出错,本文讨论以下switch语句中的块级作用域。

  • switch语句中的块级作用域
  • switch语句中的块级作用域可能存在的问题
  • 规范和检测

本文的原文在我的博客中,https://github.com/forthealll...

欢迎star

一、switch语句中的块级作用域

  ES6 或 TS 引入了块级作用域,通过let和const、class等可以定义块级作用域里的变量,块级作用域内的变量不存在变量提升,且存在暂时性死区。常见的if语句,for循环的循环体内都可以定义块级变量。那么switch语句中的块级作用域是什么呢? 先给出结论:

switch语句中的块级作用域,在整个switch语句中,而不是对于每一个case生成一个独立的块级作用域。

下面来举几个例子来说明这个问题:

let number = 1;
switch(number){
  case 1:
    let name = 'Jony';
  default:
    console.log(name)
}

上述的代码会输出jony。

再看一个例子:

let number = 1;
switch(number){
  case 1:
    let name = 'Jony';
    break;
  case 2:
    let name = 'yu';
    break;
  default:
   console.log(name);
}

这样会在重复生命的错误:

Uncaught SyntaxError: Identifier 'name' has already been declared

上述两个例子说明确实switch语句中,整个switch语句构成一个块级作用域。而与case无关,每一个case并不会构成一个独立的块级作用域。

二、switch语句中的块级作用域可能存在的问题

  我们知道了switch语句,整个switch语句的顶层是一个块级作用域,但是还要注意case的特殊性,在case中声明的变量,并不会提升到块级作用域中。

let number = 2;
switch(number){
  case 2:
    name = 'yu';
    break;
}

在这个例子中,name虽然没有声明,但是给name赋值相当于给全局的window对象复制,也就是window.name = 'yu'。不会有任何问题。

有意思的问题来了:

let number = 2;
switch(number){
  case 1:
    let name = 'jony';
    break;
  case 2:
    name = 'yu';
    break;
}

这个例子中,会报错,会报name未定义的错误。

Uncaught ReferenceError: name is not defined

原因的话,这里虽然case里面定义的块级虽然不会存在变量提升,但是会存在暂时性死区,也就是说如果let name = 'jony' 没有执行,也就是name定义的过程没有执行,那么name在整个块级作用域内都是不可用的,都是undefined。

为了证明我们的想法,接着改写上面的例子:

let number = 1;
switch(number){
  case 1:
    let name = 'jony';
    break;
  case 2:
    name = 'yu';
    break;
}

我们把number改成1,我们发现代码不会报任何的错误,因为此时let name的定义和赋值都被执行了。

三、规范和检测

一、什么时候会出现问题

  可能会说为什么在自己的项目中,在ES6或者TS代码中即使有上述的错误使用,也没有报错?

  笔者之前也有这样的问题,要明确的是是否你把ES6或者TS的代码直接转化成了es5,然后再调试或者发布的线上的,当let被编译成es5后,当然就不会存在上述switch中作用域的问题。但是现实中,编译成es5后的js文件可能太大,对于高版本浏览器我们希望直接使用ES6代码(通过type = module来判断浏览器对于ES6的支持性),那么这么上述问题就会出现。

二、如何检测和规避

  那么如何避免这种情况呢,当然最好的方式,就是不要在case中定义块级变量,但是万一不小心写了上述的问题代码如何检测呢。

首先使用typescript,静态编译是不能出现错误提示的,因为这个错误是运行时异常。最好的方式是通过编写eslint的规范来解决上述的非法使用问题。

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Dax Dax
4年前
JS核心原理理解闭包
前置概念在正式看闭包之前,我们先来学习一下前置知识,那就是JS中的作用域,我们知道,在ES5之中,作用域分为两种:全局作用域和函数作用域,随着ES6的到来,新增了块级作用域,想更好的理解闭包,那么搞清楚作用域是首要条件全局作用域我们知道,对于变量而言,我们一般会分成两类:全局变量和局部变量,一般定义在最外围环境的为全局变量,定义在函数当中的为局部变量,在we
Jacquelyn38 Jacquelyn38
4年前
你所知道的JS变量作用域
变量的作用域,指的是变量在脚本代码中的可读、可写的有效范围,也就是脚本代码中可以使用这个变量的区域。在ES6之前,变量的作用域主要分为全局作用域、局部作用域(也称函数作用域)两种;在ES6及其之后,变量的作用域主要分为全局作用域、局部作用域、块级作用域这3种。相应作用域变量分别称为全局变量、局部变量、块级变量。全局变量声明在所有函数之外;局部变量是在函数体内
Stella981 Stella981
3年前
ES6 新特性之 let, const : JavaScript在变量方面的改进。
let:块级作用域我们知道,JavaScript是没有块级作用域的,如果在块内使用var声明一个变量,它在代码块外面仍旧是可见的:if(true){varfoo3;}console.log(foo);//3for(vari0
Stella981 Stella981
3年前
ES6的let命令(二)
2.暂时性死区暂时性死区(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.51code.com%2F)是指只要块级作用域内存在let命令,它所声明的变量就绑定这个作用域,不会受到外部的影响。       varnum12;    if(true){    nu
Wesley13 Wesley13
3年前
ES6 简单整理
1.变量声明let和constlet与const都是块级作用域,letfunctionname(){letage12;//age只在name()函数中存在}constconstname'tom'name'jack'//
Stella981 Stella981
3年前
JavaScript作用域
一、JavaScript中无块级作用域在Java或C中存在块级作用域,即:大括号也是一个作用域。!(https://oscimg.oschina.net/oscnet/ea3e9460a4d20056c59315db47e2a0cbc2b.jpg)!(https://oscimg.oschina.ne
Wesley13 Wesley13
3年前
JS作用域和变量提升看这一篇就够了
作用域是JS中一个很基础但是很重要的概念,面试中也经常出现,本文会详细深入的讲解这个概念及其他相关的概念,包括声明提升,块级作用域,作用域链及作用域链延长等问题。什么是作用域第一个问题就是我们要弄清楚什么是作用域,这不是JS独有的概念,而是编程领域中通用的一个概念。我们以下面这个语句为例:letx1;这
Wesley13 Wesley13
3年前
ES6的语法
一,定义变量let(类似var)在js一直有一个bug是var:1、var声明的变量会有变量提升console.log(name);//jhonvarname'jhon';2、var没有块级作用域varname2'jjjon';{varname2'tom';
Wesley13 Wesley13
3年前
Java入门(五):控制流程
在Java中,使用条件语句和循环结构确定控制流程,在本文中,主要包括块作用域、条件语句、循环结构、中断循环这四部分。一、块作用域块,也叫复合语句,是指由一对大括号括起来的若干条Java语句。块决定了变量的作用域。一个块可以嵌套多个块。二、条件语句如果判断超过三层,建议拆分开来写,这样更加清晰。packagejav