一个BUG引发的对return和for的研究

153 阅读3分钟

起因:在前段时间因为下面这个代码引发了我对return和for的研究

    function test(query){
        for (const item in query) {
            if(query[item] === 'category') return
            console.log('this is item', item)
        }
        console.log('这是一个无法被执行的语句')
    }
    const query = ['style', 'industry', 'category', 'dimension', 'quantity']
    test(query)

这个for in 循环里面有一个return 大家都知道,return在for for-in等里面会退出整个循环,并且结束整个函数。当时就是因为这个return导致了整个循环退出,导致数据处理不全,进而导致了整个页面的崩溃。当然知道为何修改BUG就很简单了。只需要吧return替换为continue就好了。但这只是我研究return和for的开始。

可能大家在开发的时候就会发现,在.map,forEach这一类在Array.prototype上的循环函数,在执行的是时候是没法退出的,任你你如何写return和barck都不会终止这次循环,仅仅只能结束当次循环。

当然你可以像这样去终止一次forEach循环

   try {
        var array = ["first","second","third","fourth"];
        // 执行到第3次,结束循环
        array.forEach(function(item,index){
            if (item == "third") {
                throw new Error("EndIterative");
            }
            alert(item);// first,sencond
        });
    } catch(e) {
        if(e.message!="EndIterative") throw e;
    };
    // 下面的代码不影响继续执行
    alert(10);

ps:上面这个是黑科技,在平时开发的时候千万不要使用这个代码去结束循环。因为他从某种意义上来讲存在这“安全隐患”。

这时候产生疑问了,因为js在这么多年以来虽然每次新版本都会发布很多APi但是新加的过语句少之又少。
就连class都是利用了原型链的方式完成的,从某种意义上讲就是个语法糖。
那实际上的forEach这些函数核心还是使用的for循环搞定的。既然forEach的核心还是使用的for那为何使用return没法结束那是为什么呢。
下面我们就来刨析下forEach的核心内容。

    array.forEach((e)=>{
        console.log(e)
    })

我们从这个上面的代码也能看出一点端倪,可以看出forEach()这类的函数他们传入的是一个函数。
那就可以推理出forEach map等的核心代码原理应该是下面这样的

    function forEach(fun){
        for (let i =0; i < array.length; i++){
            fun(array[i])
        }
    }

搞清楚了为何forEach不能直接用return back 等直接退出循环那return作用清晰了。
return的目的就是用于终止当前函数的执行,并返回值。
在ECMA-262里面将for if for-in while等定义为了语句,也就是语句只包含执行条件加上代码块构成的流控制器,他们不是函数,他们只是构成函数的组成部分。虽然他们在ES6里加入了块级作用域,拥有了函数的一些特征。但是终究还是只是流控制器并不是函数。
所以在for和for-in里面进行retrun就会立即结束这个函数。因为函数被立即结束后那return后面的代码也就无法继续执行。

ps:第一次尝试写文章如有错误,欢迎指正。