V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
autoxbc
V2EX  ›  JavaScript

偶得一法跳出数组循环

  •  
  •   autoxbc · 2018-12-31 21:04:27 +08:00 · 4864 次点击
    这是一个创建于 1934 天前的主题,其中的信息可能已经有所发展或是发生改变。

    some 和 every 可以用 return 值跳出循环

    forEach,filter,find,findIndex,map,reduce,reduceRight 没有可用的跳出方法,continue 和 break 都不能用,那么怎么跳出这些数组循环?

    网上搜索了一下,只见到一种构造 try catch 结构然后 throw 的方法,一点也不优雅

    用于循环的数组自身消失的话,循环不就自然中止了

    [1,2,3,4,5].forEach( (val,idx,arr) => {
        if( val > 3 )
            return arr.length = 0 ;
        console.log(val);
    } );
    

    跳出过程并未本质改变这些循环的语义,所有的返回值(比如 reduce)仍然有效,显然比抛出错误法好多了

    唯一需要注意的是,因为置空的副作用,部分情况要先对数组做浅拷贝

    第 1 条附言  ·  2019-01-01 00:22:31 +08:00
    16 条回复    2019-01-25 09:01:23 +08:00
    autoxbc
        1
    autoxbc  
    OP
       2018-12-31 21:26:37 +08:00
    改进一下例子
    ```js
    [1, 2, 3, 4, 5].forEach((val, idx, arr) => {
    if (val < 3){
    console.log(`${val} < 3`);
    }
    else {
    console.log(`${val} >= 3`);
    arr.length = 0;
    }
    })
    ```
    ssynhtn
        2
    ssynhtn  
       2018-12-31 22:04:30 +08:00 via Android   ❤️ 1
    学点函数式编程就知道你这做法不好了
    要达到你这效果,简单的做法是先 take until > 3, 然后该干嘛干嘛
    lastpass
        3
    lastpass  
       2018-12-31 22:25:45 +08:00 via Android
    system.exot()
    lastpass
        4
    lastpass  
       2018-12-31 22:26:20 +08:00 via Android
    o --> i
    congeec
        5
    congeec  
       2018-12-31 22:31:17 +08:00 via iPhone
    二楼说得对,你需要 takewhile 函数
    will0404
        6
    will0404  
       2018-12-31 22:31:37 +08:00 via Android
    这些方法不应该有 side effort。
    will0404
        7
    will0404  
       2018-12-31 22:32:51 +08:00 via Android
    effort -> effect
    zealot0630
        8
    zealot0630  
       2018-12-31 23:02:05 +08:00   ❤️ 1
    unfold 可以,然而这个函数太难驾驭,大部分库和语言都不支持。

    https://srfi.schemers.org/srfi-1/srfi-1.html#FoldUnfoldMap


    随便写了个 js 实现:

    ···
    function unfold(p, f, g, seed, reduce, tailgen) {
    function recursive(iter) {
    if (p(iter)) return tailgen(iter);
    return reduce(f(iter), recursive(g(iter)));
    }

    return recursive(seed);
    }
    ···

    举一个简单的例子,比如说把一个数组累加起来:

    ···
    sum(a) = unfold(
    (e) => !e /* 没有元素时候终止 */,
    identify /* identify 函数,返回元素本身 */,
    (iter) => iter.nex() /* generator,如何遍历元素 */
    a[@@iterator]() /* 种子,数组的迭代器 */
    (head, tail) => head + tail /* reduce,如何汇总 */
    (e) => 0 /* 如何处理尾巴,也可以理解为初始值 */
    )
    ```

    unfold 功能相当强大,你要问有多强大,他是其他所有容器函数( forEach,filter,find,findIndex,map,reduce,reduceRight )的母亲,这些函数都能用一个 unfold 调用,在一行里面实现。
    zealot0630
        9
    zealot0630  
       2018-12-31 23:25:34 +08:00   ❤️ 1
    JS 的 iterator 是 mutable 的,简直反设计,下面是个能跑的实现和例子

    https://gist.github.com/kghost/b001d39b6c6b541a289774bf137f2da8

    第一个参数 p 决定什么时候跳出来,楼主按照需求实现 p 函数就可以了
    Justin13
        10
    Justin13  
       2019-01-01 09:00:12 +08:00 via Android
    乱改属性可是大忌。可以学学 haskell
    msg7086
        11
    msg7086  
       2019-01-01 09:37:12 +08:00
    没过几个月,楼主就被后来接手的程序员打死了。
    lihongjie0209
        12
    lihongjie0209  
       2019-01-01 09:45:23 +08:00
    瞎搞
    plqws
        13
    plqws  
       2019-01-01 09:51:52 +08:00   ❤️ 1
    在操作前先 slice 不好吗
    tinywhale
        14
    tinywhale  
       2019-01-01 12:35:03 +08:00
    我觉得你想要的效果是 elixir 里的 `Enum.reduce_while/3`,我偶尔也觉得 js array 应该有个类似的,后来觉得如果要这样的效果还不如直接 for loop
    codeduan
        15
    codeduan  
       2019-01-02 10:32:20 +08:00
    一般来说用 some 已经够了,不行的话就用 for loop 吧。
    ghostheaven
        16
    ghostheaven  
       2019-01-25 09:01:23 +08:00 via Android
    用 generator 重新实现那几个函数,自己定义一个用于结束的 Symbol,当 yield 这个 Symbol 的时候循环结束,并返回默认值
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5190 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 03:48 · PVG 11:48 · LAX 20:48 · JFK 23:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.