起因

在可视化数据的大环境下,前端的页面驱动基本是基于,每个函数或多或少都会做一些数据上的判断,这时候就会用到循环的跳出。

场景

由于后台反馈以及前端反馈的数据都是list格式的数据,我先用的是forEach,forEach运用的时候可以更好的便利出item,当然也是习惯性用forEach。但是在forEach中遍历的时候做的判断是不支持弹出整个函数,而for循环可以。

for循环试一下return

  1. 想当然的用return啊,结果:呵呵!
for (let i = 0; i < 3; i++) {
  console.log(110);
  if (i === 1) {
   return
  }
}
复制代码

这段代码,我想当然的认为:i===1时遇到return跳出循环,只会打印两次110,但是当我在控制台按下回车时,啪啪啪打脸啊,脸都打肿了,我还不知道为啥!直接报:Illegal return statement

return语句就是用于指定函数返回的值。return语句只能出现在函数体内,出现在代码中的其他任何地方都会造成语法错误! 地方都会造成语法错误!

竟然还有这种限制,为何我以前怎么没发觉,仔细看了下以前的代码,貌似,我的for都是写在函数内的,所以没报错。。。

当然,为了保险点,又去MDN看了下return,果不其然,MDN上抬头就是一句:return语句终止函数的执行,并返回一个指定的值给函数调用者。

更保险的可以看ECMAScript® 2015 Language Specification return。规范里面也说了返回语句使函数停止执行,并将值返回给调用方。

  1. 既然return不是为for服务的,那么该怎么去跳出for循环呢? 稍微有基础的同学们都会想到break和continute。
    在这里我先给ECMA规范里的for。
    MDN上关于break的说明:break 语句中止当前循环,switch语句或label 语句,并把程序控制流转到紧接着被中止语句后面的语句。break可不仅仅是跳出循环这么简单哦~
for (let j = 0; j < 3; j++) {
    console.log(112);
    if (j === 1) {
        break;
    }
}
复制代码
  1. continue
    结合代码看下continue的功能,其实就是break;continue。
for (let j = 0; j < 3; j++) {
      if (j === 1) {
        continue;
      }
      console.log(j);
    }
复制代码

为什么不能跳出forEach?

  1. 先用break和continue分别测试一波,看看问题是否成立。
arr.forEach(function(item){
  if (item === 2) {
    break;
  }
  console.log(item);
})
arr.forEach(function(item){
  console.log(110)
  if (item === 2) {
    continue;
  }
  console.log(item);
})
复制代码
控制台均报语法错误!!!尤其continue提示没有包含在一个迭代语句中!!!
去看看MDN上面的forEach,其中明确提到:

没有办法中止或者跳出 forEach 循环,除了抛出一个异常。如果你需要这样,使用forEach()方法是错误的,你可以用一个简单的循环作为替代。如果您正在测试一个数组里的元素是否符合某条件,且需要返回一个布尔值,那么可使用Array.everyArray.some。如果可用,新方法 find() 或者findIndex() 也可被用于真值测试的提早终止。

同时,去看看规范里的forEach。貌似没有说为什么。那么怎么办呢?

回顾continue报错提示,需要被包含在迭代语句内,难道forEach不是迭代语句吗?它作用不就是遍历 吗?抱着这些问题,我在规范的目录里走马观花的查看,突然发现这个Iteration Statements,这个目录名不就是continue要求的迭代语句嘛。

我点了下去,大致看了下,果然没有forEach,而且mapfilter等都没有。。。

我有尝试去看v8关于forEach的源码实现,可惜并没有找到。。。

不过这里可以提供一个仿map方法的_map,本质上是一样的,只是侧重点不同,有些实现不同。我们平常这样使用:arr.forEach(function(){}),我们都是在function(){}中去做我们需要的操作,但是,forEach本质上就是一个函数,而我们写的函数其实是传递给它调用的回调函数!!!

所以,当我在回调函数内写了return,即使符合条件也只是跳出回调函数而已,并没有跳出调用它的forEach!

demo
function a(i) {
  console.log(i);
  if(i === 1) {
    return
  }
}
function b(arr) {
  for(var i = 0; i < arr.length; i++) {
    a(i)
  }
}
var arr = [1,2,3,4,5]
b(arr)
复制代码

总结下

由这一个小问题挖掘出这么多小知识也是不错的,有利于夯实js基础。以后遇到类似的业务场景时,可以更好利用出来。