js 冷门知识 - 标签

607 阅读2分钟

本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

前言

本系列将分多篇文章介绍 js 相关的“冷门知识”,这里的“冷门知识”是指大部分开发者都不曾留意过的知识点,亦或者是意料不到的知识点。这些知识点对现实中的面试、开发也许没有很大的帮助,甚至压根没任何用处,但希望以此博得大家一乐,并额外拓展下知识面。

本系列文章的大部分知识参考于阮一峰写的“网道 - 互联网开发文档 (wangdoc.com)”,强烈建议 web 前端开发者都看下这份文档,既是入门的好帮手,也是拓展知识面的利器。

本系列文章的任何参考,均会在文末标出。

文章示例均是经过本人验证,如有错漏,请在评论区指正。

跳出循环

我们都知道 js 的“跳出循环”都是使用关键字 breakcontinue,单独的 break 用来跳出当前循环,单独的 continue 用来跳出一次循环(这里强调“单独”是有原因的,往下看即可明白)。

假设我们现在有两个循环体,如下:

for (var i=0; i<2; i++) {
  for (var j=0; j<2; j++) {
    console.log(i, j)
  }
}

现有要求在第二个循环体里判断,当 j===1 时,不允许输出 ij 的值并直接跳出所有循环体,注意是所有循环体。

你也许会这样写,添加一个变量标识是否需要跳转出循环,再在顶层循环里做一次判断。

var flag = false
for (var i=0; i<2; i++) {
  for (var j=0; j<2; j++) {
    if (j === 1) {
        flag = true
        break
    }
    console.log(i, j)
  }
  if (flag) {
      break
  }
}

控制台正常输出的结果是

0 0

这种方法是没问题的,但是如果这里不单止有一个内嵌循环体,而是有一百个内嵌循环体且带有参数j的循环体是最里面一个,是不是就要写一百次个判断?那岂不是很麻烦。

当然,事实上如果代码是放在函数体里面的,可以用 return 来解决,但这里不考虑这种情况。

break + 标签

其实 es5 里面有一种更简便的跳出指定循环体的写法,那就是使用 es5 的标签(label),如下:

top:for (var i = 0; i < 2; i++) {
  for (var j = 0; j < 2; j++) {
    if (j === 1) {
      break top
    }
    console.log(i, j)
  }
}

上面的代码在原来的代码里有两个变化:

  1. 一个变化是在第一个 for 前面添加了代码 top:,这个冒号前面的 top 就是 es5 的标签,标签名可以自定义(topmyTop等等),但不能是 js 的关键字。这里的意思是将第一个循环体外的环境标识为 top 标签。

  2. 另一个变化是当 j === 1 时,关键字 break 不再是单独使用,而是配合标签 top 使用,break top 意思是指直接跳出中间的循环体到标签 top 所在的环境,也就是说,程序会直接跳出第一个循环体和第二个循环体。

image.png

这样,不管里面内嵌了多少个循环体,都可以用简单的 break top 解决。

我们也可以将标签 top 放到 for 上面的代码行

top:
for (var i = 0; i < 2; i++) {
  ...
}

也可以加一个代码块,这样可能更加好理解一点。

top: {
  for (var i = 0; i < 2; i++) {
    ...
  }
}

continue + 标签

当然,continue 也是可以配合标签使用,比如:

top2:
for (var i = 0; i < 2; i++) {
  console.log('i:', i)
  for (var j = 0; j < 2; j++) {
      if (j == 0) {
        continue top2
      }
      console.log('i, j:', i, j)
  }
}

控制台输出:

i: 0
i: 1

当代码执行到 continue top2,内层循环体直接跳出(并非跳出一次)到外层循环,因此 console.log('i, j:', i, j) 的代码根本没有执行,continue top2 这里的作用是不是很像单独的 break 的作用?这完全可以使用 break 来代替,因此 continue + 标签 的用法没什么使用价值。

标签的错误理解

在“网道”文档里,是这样介绍“标签”:

JavaScript 语言允许,语句的前面有标签(label),相当于定位符,用于跳转到程序的任意位置...

我当时看到这句话,就产生了一个错觉,“可以通过标签跳转到程序的任意位置”,这么逆天......

image.png

然后,我试了一下这样写。

top:console.log(123)
for (var i = 0; i < 2; i++) {
  for (var j = 0; j < 2; j++) {
    if (j == 1) {
      break top
    }
    console.log(i, j)
  }
}

按照逻辑来说,这里应该死循环,当 j===1 时,跳转到 toptop 标记于 console.log(123),因此再次打印了 123,并且继续再次进行下面的循环......

但这个代码运行是直接报错的。

image.png

这说明标签可能只允许标记在最近的循环体上,标记在其他代码上会报错,并且并非我想象中的“可以通过标签跳转到程序的任意位置”。

然后我又换了一个写法。

top: {
  console.log(123)
  for (var i = 0; i < 2; i++) {
    for (var j = 0; j < 2; j++) {
      if (j == 1) {
        break top
      }
      console.log(i, j)
    }
  }
}

这次不会报错了,但并没有预期出现死循环,这也很符合预期,因为 top 是标记在代码块上的。

标签的正确理解

image.png

经过上一章节的试验,我们并不可以通过“标签”跳转到程序的任意位置,我们只可以通过“标签”跳出循环体或代码块,跳出后,继续往下面执行代码。

标签的正确用法如下:

标签: for (...) {
    ...
    break 标签
    ...
}

标签:
for (...) {
    ...
    break 标签
    ...
}

标签: {
    ...
    break 标签
    ...
}

参考

  1. JavaScript 的基本语法 - JavaScript 教程 - 网道 (wangdoc.com)