V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhaomeicheng
V2EX  ›  前端开发

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

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

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

    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))
    }
    zhaomeicheng
        6
    zhaomeicheng  
    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));
    }
    zhaomeicheng
        9
    zhaomeicheng  
    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
    enchilada2020
        15
    enchilada2020  
       2022-06-20 19:52:20 +08:00
    ```JS
    const compose = ([f, ...arr]) => arr.length
    ? () => f(compose(arr))
    : () => f?.(() => { });
    ```
    enchilada2020
        16
    enchilada2020  
       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 自动补全的代码
    enchilada2020
        21
    enchilada2020  
       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 中去就行了。
    zhaomeicheng
        38
    zhaomeicheng  
    OP
       2022-06-21 13:50:48 +08:00
    @ryougifujino 说真的,我看不懂😂
    Lenic
        39
    Lenic  
       2022-06-25 12:33:39 +08:00
    建议看下 Array.prototype.reduce 方法
    channg
        40
    channg  
       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   ·   实用小工具   ·   2757 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 13:02 · PVG 21:02 · LAX 05:02 · JFK 08:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.