V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
nazalewoyuanyi

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

  •  
  •   nazalewoyuanyi · Jun 20, 2022 · 5188 views
    This topic created in 1410 days ago, the information mentioned may be changed or developed.

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

    111

    Supplement 1  ·  Jun 21, 2022

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

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

    猜测一下,expressjs 这类框架的中间件大概是类似原理吧。
    Yumwey
        4
    Yumwey  
       Jun 20, 2022
    也可以看看 redux 的实现,应该都挺常见的
    Cbdy
        5
    Cbdy  
       Jun 20, 2022
    一行代码的事情

    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
       Jun 20, 2022
    @Cbdy 是怎么做到一下子写出来的...看来这道题真的很基础,面试官没说错。
    cyrbuzz
        7
    cyrbuzz  
       Jun 20, 2022
    ```
    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  
       Jun 20, 2022
    哎,想了十几分钟才有思路。现场肯定是写不出来了
    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
       Jun 20, 2022
    @cyrbuzz 对的,我刚刚自己又尝试了一下,写出来的与你思路一致... 看样子我是能做出来的...唉
    cyrbuzz
        10
    cyrbuzz  
       Jun 20, 2022
    @zhaomeicheng

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

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

    // 递归
    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  
       Jun 20, 2022 via Android   ❤️ 3
    sweetcola
        19
    sweetcola  
       Jun 20, 2022   ❤️ 4
    综合上面回答的缩减版()

    const compose = ([fn, ...fns]) => () => fn?.(compose(fns))
    isbase
        20
    isbase  
    PRO
       Jun 20, 2022
    https://s2.loli.net/2022/06/20/UiwjuvXhOoVeLAm.png

    Github Copilot 自动补全的代码
    KMpAn8Obw1QhPoEP
        21
    KMpAn8Obw1QhPoEP  
       Jun 20, 2022 via Android
    @sweetcola 很极致 我喜欢
    skies457
        22
    skies457  
       Jun 20, 2022
    const compose = ((self, [fn, ...fns]) => () => fn?.(self(self, fns)))((self, [fn, ...fns]) => () => fn?.(self(self, fns)), arr)

    还可以升级一下难度,只使用匿名函数(逃
    skies457
        23
    skies457  
       Jun 20, 2022
    const compose = arr => ((self, [fn, ...fns]) => () => fn?.(self(self, fns)))((self, [fn, ...fns]) => () => fn?.(self(self, fns)), arr)

    少了 arr => (
    dasbn
        24
    dasbn  
       Jun 20, 2022
    @skies457 Y= f => (x => v => f(x(x))(v)) (x => v => f(x(x))(v))

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

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

    手写倒有点难,电脑敲再简单调试一下下可以
    Agassiz
        29
    Agassiz  
       Jun 21, 2022 via iPhone
    洋葱模型
    walpurgis
        30
    walpurgis  
       Jun 21, 2022
    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  
       Jun 21, 2022 via iPhone
    这是啥玩意 我也会 js 但是为啥我都看不懂
    MonkeyD1
        32
    MonkeyD1  
       Jun 21, 2022
    @wanacry 哈哈 ➕1 我也是
    banmuyutian
        33
    banmuyutian  
       Jun 21, 2022
    才疏学浅,请教下这个洋葱模型是不是类似于 Spring Boot 的堆栈?
    danhua
        34
    danhua  
       Jun 21, 2022
    为啥我第一眼感觉可以用异步来解决,不过异步比上面大佬们给出的方法要麻烦多了。
    dtdths1
        35
    dtdths1  
       Jun 21, 2022
    洋葱圈模型
    ryougifujino
        36
    ryougifujino  
       Jun 21, 2022
    function compose(arr) {
    let next = function () {
    }
    arr.reverse().forEach(fn => {
    const nextFn = next
    next = function () {
    fn(nextFn)
    }
    })
    return next
    }
    ryougifujino
        37
    ryougifujino  
       Jun 21, 2022
    @ryougifujino #36 个人感觉我这个思路很简单,确实就是洋葱圈模型。next 顾名思义,就是下一次要执行的函数,所以核心思路就是把下一次的函数放到 next 中去就行了。
    nazalewoyuanyi
        38
    nazalewoyuanyi  
    OP
       Jun 21, 2022
    @ryougifujino 说真的,我看不懂😂
    Lenic
        39
    Lenic  
       Jun 25, 2022
    建议看下 Array.prototype.reduce 方法
    usdc
        40
    usdc  
       Aug 3, 2022
    我感觉这道题是需要多次运行 fn() 可以再出输入 1 2 3 3.1 2.1 1.1 吧 难道是我想多了?
    @zhaomeicheng
    @ryougifujino
    @Cbdy
    @cyrbuzz
    houchangxiaowang
        41
    houchangxiaowang  
       Apr 22, 2023
    图片挂了,重新帖下?
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   930 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 85ms · UTC 19:14 · PVG 03:14 · LAX 12:14 · JFK 15:14
    ♥ Do have faith in what you're doing.