前端大佬能当场写出这道题吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
nazalewoyuanyi
V2EX    前端开发

前端大佬能当场写出这道题吗?

  •  
  •   nazalewoyuanyi 2022-06-20 18:02:49 +08:00 4896 次点击
    这是一个创建于 1213 天前的主题,其中的信息可能已经有所发展或是发生改变。

    当场没写出来,面试官劝我别紧张,说这道题很基础,可是面试后自己在这也没写出来...

    111

    第 1 条附言    2022-06-21 02:35:04 +08:00

    综合了一下大家的回答,感觉这个代码能不费力看懂~

    41 条回复    2023-04-22 11:52:47 +08:00
    Yumwey
        1
    Yumwey  
       2022-06-20 18:24:36 +08:00
    看看 koa 的源码吧,这是很基础的 compose 了,实现方式很多,递归,迭代都可以
    Biwood
        2
    Biwood  
       2022-06-20 18:24:56 +08:00 via Android
    感觉还好,思路:遍历,使用.bind()把后一个 fn 作为参数绑定到前一个 fn 上,即前一个 fn 参数中的 next ,遍历完后执行第一个 fn 即可。

    猜测一下,expressjs 这类框架的中间件大概是类似原理吧。
    Yumwey
        3
    Yumwey  
       2022-06-20 18:25:36 +08:00
    Yumwey
        4
    Yumwey  
       2022-06-20 18:27:05 +08:00
    也可以看看 redux 的实现,应该都挺常见的
    Cbdy
        5
    Cbdy  
       2022-06-20 18:28:42 +08:00
    一行代码的事情

    export function compose(middlewares = (ctx, next) => (void 0)) {
    if (!middlewares || !middlewares.length) {
    return ctx => (void 0)
    }
    return ctx => middlewares[0](ctx, () => compose(middlewares.slice(1))(ctx))
    }
    nazalewoyuanyi
        6
    nazalewoyuanyi  
    OP
       2022-06-20 18:36:21 +08:00
    @Cbdy 是怎么做到一下子写出来的...看来这道题真的很基础,面试官没说错。
    cyrbuzz
        7
    cyrbuzz  
       2022-06-20 18:42:19 +08:00
    ```
    const compose = arr => {
    const run = lastArr => {
    if (lastArr.length === 0) {
    return;
    }
    const first = lastArr.shift();

    first(() => run(arr));
    };
    return () => {
    run(arr);
    };
    };
    ```

    这样?运行结果是 ok 的,没做检查。
    rabbbit
        8
    rabbbit  
       2022-06-20 18:56:16 +08:00
    哎,想了十几分钟才有思路。现场肯定是写不出来了
    function compose(arr) {
    const next = (fn = (() => {}), arr) => {
    fn(next.bind(this, arr[0], arr.slice(1)));
    };
    return next.bind(this, arr[0], arr.slice(1));
    }
    nazalewoyuanyi
        9
    nazalewoyuanyi  
    OP
       2022-06-20 18:57:17 +08:00
    @cyrbuzz 对的,我刚刚自己又尝试了一下,写出来的与你思路一致... 看样子我是能做出来的...唉
    cyrbuzz
        10
    cyrbuzz  
       2022-06-20 19:01:07 +08:00
    @zhaomeicheng

    hh ,我一开始也没有思路,不过有个好队友提示。
    TWorldIsNButThis
        11
    TWorldIsNButThis  
       2022-06-20 19:06:45 +08:00 via iPhone
    swr 的 middleware 就是这个结构
    其他前端框架应该有不少类似的
    des
        12
    des  
       2022-06-20 19:18:46 +08:00 via iPhone
    忘了在哪里看到的了
    arr.reverse().reduce((a, b) => () => b(a), Function.prototype)()
    rabbbit
        13
    rabbbit  
       2022-06-20 19:20:00 +08:00
    哪里有类似 Leetcode 能刷这种题的题库吗?
    Cbdy
        14
    Cbdy  
       2022-06-20 19:46:26 +08:00
    如果觉得 JS 版本太难懂,可以看一下 Java 版本
    https://github.com/cbdyzj/nanometer/blob/main/common/src/main/java/nano/support/Onion.java
    KMpAn8Obw1QhPoEP
        15
    KMpAn8Obw1QhPoEP  
       2022-06-20 19:52:20 +08:00
    ```JS
    const compose = ([f, ...arr]) => arr.length
    ? () => f(compose(arr))
    : () => f?.(() => { });
    ```
    KMpAn8Obw1QhPoEP
        16
    KMpAn8Obw1QhPoEP  
       2022-06-20 20:02:27 +08:00   1
    没想到还有更简单的

    ```JS
    const compose = arr => arr.reduceRight((acc, cur) => () => cur(acc), () => { });
    ```
    tyx1703
        17
    tyx1703  
       2022-06-20 20:03:36 +08:00
    想了十几分钟,代码倒是简单,思路很重要。估计我面试时也会紧张写不出来。

    // 递归
    function compose(middlewares) {
    if (middlewares.length === 0) {
    return () => {}
    }
    const middleware = middlewares.shift()
    return middleware.bind(null, compose(middlewares))
    }

    // 迭代
    function compose(middlewares) {
    let res;
    for (let i = middlewares.length - 1; i >= 0; i--) {
    if (!res) {
    res = middlewares[i].bind(null, () => {})
    } else {
    res = middlewares[i].bind(null, res)
    }
    }
    return res;
    }
    dinjufen
        18
    dinjufen  
       2022-06-20 20:10:45 +08:00 via Android   3
    sweetcola
        19
    sweetcola  
       2022-06-20 20:25:21 +08:00   4
    综合上面回答的缩减版()

    const compose = ([fn, ...fns]) => () => fn?.(compose(fns))
    isbase
        20
    isbase  
       2022-06-20 21:21:58 +08:00
    https://s2.loli.net/2022/06/20/UiwjuvXhOoVeLAm.png

    Github Copilot 自动补全的代码
    KMpAn8Obw1QhPoEP
        21
    KMpAn8Obw1QhPoEP  
       2022-06-20 21:32:14 +08:00 via Android
    @sweetcola 很极致 我喜欢
    skies457
        22
    skies457  
       2022-06-20 21:52:37 +08:00
    const compose = ((self, [fn, ...fns]) => () => fn?.(self(self, fns)))((self, [fn, ...fns]) => () => fn?.(self(self, fns)), arr)

    还可以升级一下难度,只使用匿名函数(逃
    skies457
        23
    skies457  
       2022-06-20 21:53:33 +08:00
    const compose = arr => ((self, [fn, ...fns]) => () => fn?.(self(self, fns)))((self, [fn, ...fns]) => () => fn?.(self(self, fns)), arr)

    少了 arr => (
    dasbn
        24
    dasbn  
       2022-06-20 22:46:07 +08:00
    @skies457 Y= f => (x => v => f(x(x))(v)) (x => v => f(x(x))(v))

    提取出你的 Y (
    molvqingtai
        25
    molvqingtai  
       2022-06-20 23:09:44 +08:00 via Android
    洋葱圈模型还挺实用的,koa 就不用说了,比如前端使用的 redux 、vue-router 内部实现都是使用洋葱模型

    我也这种模式封装了一个 http 客户端:
    https://github.com/molvqingtai/resreq
    chezs66
        26
    chezs66  
       2022-06-20 23:13:47 +08:00
    这就是栈呀。。。无非是自己写一个栈,或用 js 自带的栈
    zyxyz123
        27
    zyxyz123  
       2022-06-20 23:17:32 +08:00
    const compose = (arr) => {
    if (arr.length === 0) {
    return () => {}
    }
    return () => {
    arr[0](compose(arr.slice(1)))
    }
    }
    otakustay
        28
    otakustay  
       2022-06-20 23:29:13 +08:00
    const compose = handlers => handlers.reduceRight((out, v) => () => v(out), () => {});

    手写倒有点难,电脑敲再简单调试一下下可以
    Agassiz
        29
    Agassiz  
       2022-06-21 00:54:36 +08:00 via iPhone
    洋葱模型
    walpurgis
        30
    walpurgis  
       2022-06-21 01:40:31 +08:00
    middlewares = [fn1,fn2,fn3]
    compose 展开后是这样
    fn = () => fn1(() => fn2(() => fn3(() => {})));

    暴力拼接法

    function compose(arr) {
    const fn = arr.pop();
    let composed = () => fn(() => {});
    while (arr.length > 0) {
    const fn = arr.pop();
    composed = ((next) => () => fn(next))(composed)
    };
    return composed;
    }
    wanacry
        31
    wanacry  
       2022-06-21 03:19:59 +08:00 via iPhone
    这是啥玩意 我也会 js 但是为啥我都看不懂
    MonkeyD1
        32
    MonkeyD1  
       2022-06-21 09:04:55 +08:00
    @wanacry 哈哈 1 我也是
    banmuyutian
        33
    banmuyutian  
       2022-06-21 09:47:03 +08:00
    才疏学浅,请教下这个洋葱模型是不是类似于 Spring Boot 的堆栈?
    danhua
        34
    danhua  
       2022-06-21 10:14:32 +08:00
    为啥我第一眼感觉可以用异步来解决,不过异步比上面大佬们给出的方法要麻烦多了。
    dtdths1
        35
    dtdths1  
       2022-06-21 10:56:54 +08:00
    洋葱圈模型
    ryougifujino
        36
    ryougifujino  
       2022-06-21 12:43:51 +08:00
    function compose(arr) {
    let next = function () {
    }
    arr.reverse().forEach(fn => {
    const nextFn = next
    next = function () {
    fn(nextFn)
    }
    })
    return next
    }
    ryougifujino
        37
    ryougifujino  
       2022-06-21 12:48:27 +08:00
    @ryougifujino #36 个人感觉我这个思路很简单,确实就是洋葱圈模型。next 顾名思义,就是下一次要执行的函数,所以核心思路就是把下一次的函数放到 next 中去就行了。
    nazalewoyuanyi
        38
    nazalewoyuanyi  
    OP
       2022-06-21 13:50:48 +08:00
    @ryougifujino 说真的,我看不懂
    Lenic
        39
    Lenic  
       2022-06-25 12:33:39 +08:00
    建议看下 Array.prototype.reduce 方法
    usdc
        40
    usdc  
       2022-08-03 17:56:54 +08:00
    我感觉这道题是需要多次运行 fn() 可以再出输入 1 2 3 3.1 2.1 1.1 吧 难道是我想多了?
    @zhaomeicheng
    @ryougifujino
    @Cbdy
    @cyrbuzz
    houchangxiaowang
        41
    houchangxiaowang  
       2023-04-22 11:52:47 +08:00
    图片挂了,重新帖下?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5826 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 39ms UTC 06:18 PVG 14:18 LAX 23:18 JFK 02:18
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86