V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mytry
V2EX  ›  程序员

一个 JavaScript 挑战题,看看有多少人能做出来~

  •  1
     
  •   mytry · 2018-11-19 14:29:26 +08:00 · 4022 次点击
    这是一个创建于 2195 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在外部获取闭包内 key 变量的值。(不用考虑所有浏览器,Chrome 支持就可以)

    在线代码: https://jsfiddle.net/Ltse6nf4/

    21 条回复    2018-11-20 11:28:09 +08:00
    suzic
        1
    suzic  
       2018-11-19 15:14:29 +08:00 via Android
    不会。但感觉用 eval 能解
    jowan
        2
    jowan  
       2018-11-19 16:52:41 +08:00
    ```
    recursion = () => {
    var key = apiX(100)
    return k = key <= 1 ? key : recursion()
    }

    try {
    recursion()
    } catch (e) {
    console.log(k)
    }
    hsfzxjy
        3
    hsfzxjy  
       2018-11-19 16:53:07 +08:00   ❤️ 3
    ```
    function d () {
    try {
    return d()
    } catch (e) {
    return apiX()
    }
    }

    console.log(d());
    ```

    用爆栈引发异常
    jerrry
        4
    jerrry  
       2018-11-19 17:07:12 +08:00   ❤️ 1
    这是什么字体?怎么感觉比 FiraCode 还顺眼。
    vicvinc
        5
    vicvinc  
       2018-11-19 17:26:45 +08:00
    为啥 throw 一个 error 不会触发
    zbinlin
        6
    zbinlin  
       2018-11-19 17:32:51 +08:00
    function x(fn) {
    const ret = fn(fn);
    if (ret === fn) {
    try {
    return x(fn);
    } catch (err) {
    return ret();
    }
    } else {
    return ret;
    }
    }

    console.log(x(apiX));
    zbinlin
        7
    zbinlin  
       2018-11-19 17:38:56 +08:00   ❤️ 1
    精简下:

    function x(fn) {
    try {
    return x(fn(fn));
    } catch (err) {
    return fn();
    }
    }

    console.log(x(apiX));
    morethansean
        8
    morethansean  
       2018-11-19 17:40:00 +08:00
    @jerrry #4
    祖传 Monaco
    mytry
        9
    mytry  
    OP
       2018-11-19 17:44:43 +08:00
    @jowan
    @hsfzxjy
    @zbinlin 回答正确~ 💯
    mayday526
        10
    mayday526  
       2018-11-19 17:48:04 +08:00
    @jerrry 用 FiraCode 的话,别人看我的代码要愣一下
    seki
        11
    seki  
       2018-11-19 17:49:02 +08:00   ❤️ 1
    Math.random = () => 1
    lastpass
        12
    lastpass  
       2018-11-19 18:16:55 +08:00 via Android
    回复 @seki 注意执行顺序呀。
    linxiaoziruo
        13
    linxiaoziruo  
       2018-11-19 18:21:14 +08:00
    @hsfzxjy 验证了下代码,执行正确。但是我有个不明白的地方,爆栈应该只会出现在 d()这个函数的递归调用上,到了执行 apiX()的时候,栈应该重新记数了,应该不会触发 apix 的 catch。求解!
    FakeLeung
        14
    FakeLeung  
       2018-11-19 20:23:59 +08:00 via Android
    Emmmmm 作为一个前端,看不懂,跑了。
    Sevenskey
        15
    Sevenskey  
       2018-11-19 20:33:01 +08:00
    @linxiaoziruo 排队求解。顺便一说我发现只要 catch 中执行的函数的函数体内部有 try catch 且 try 中含有函数调用,就会在函数调用处抛爆栈的错;但如果这个函数体内部存在函数调用却没有 try catch,那么就不会抛错。。猜测也许是引擎的某些策略?
    autoxbc
        16
    autoxbc  
       2018-11-19 23:15:11 +08:00
    @linxiaoziruo #13
    @Sevenskey #15

    猜测是不是这样

    执行代码
    function bomb()
    {
    try {
    return bomb()
    } catch(err) {
    return apiX()
    }
    }

    console.log( bomb() )

    爆栈阶段调用过程
    bomb_2 (){
    try {
    bomb_1 (){
    try {
    return bomb_0() ...
    } catch(err) {
    return apiX_0() ...
    }
    }
    } catch(err) {
    apiX_1 (){
    try {
    return internal() ...
    } catch(err) {
    return key
    }
    }
    }
    }

    实际流程
    => bomb_0(申请资源出错) => apiX_0(申请资源出错)
    => bomb_1(抛出错误) => apiX_1(正常执行)
    => internal(申请不到资源) => return key


    本题可解的关键是 return key 分支比 return internal() 少一级函数调用,如果两者调用长度相等,那么就失败了

    简单添加一句代码给 return key 分支加长调用链,令 apiX 为
    apiX = function(x) {
    try {
    return internal(x)
    } catch(err) {
    (function(){})() // 此句新加
    return key
    }
    }

    此时用上面方法爆栈是无法获取 key 的
    Sparetire
        17
    Sparetire  
       2018-11-20 01:17:11 +08:00 via Android
    楼上正解,这里的关键就在于让调用 internal(x)的时候爆栈就行,只要调用栈足够深就爆栈,递归只是达成这一目的的方式
    ericgui
        18
    ericgui  
       2018-11-20 06:12:05 +08:00
    @hsfzxjy 只有你的代码我能看懂
    mytry
        19
    mytry  
    OP
       2018-11-20 10:09:50 +08:00
    公布答案~

    linxiaoziruo
        20
    linxiaoziruo  
       2018-11-20 11:16:33 +08:00
    @mytry 老哥多来点这种趣味性的东西!
    razor1895
        21
    razor1895  
       2018-11-20 11:28:09 +08:00
    apiX(new Error());
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2925 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 11:08 · PVG 19:08 · LAX 03:08 · JFK 06:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.