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

2018 年 11 月 19 日
 mytry

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

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

4496 次点击
所在节点    程序员
21 条回复
suzic
2018 年 11 月 19 日
不会。但感觉用 eval 能解
jowan
2018 年 11 月 19 日
```
recursion = () => {
var key = apiX(100)
return k = key <= 1 ? key : recursion()
}

try {
recursion()
} catch (e) {
console.log(k)
}
hsfzxjy
2018 年 11 月 19 日
```
function d () {
try {
return d()
} catch (e) {
return apiX()
}
}

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

用爆栈引发异常
jerrry
2018 年 11 月 19 日
这是什么字体?怎么感觉比 FiraCode 还顺眼。
vicvinc
2018 年 11 月 19 日
为啥 throw 一个 error 不会触发
zbinlin
2018 年 11 月 19 日
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
2018 年 11 月 19 日
精简下:

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

console.log(x(apiX));
morethansean
2018 年 11 月 19 日
@jerrry #4
祖传 Monaco
mytry
2018 年 11 月 19 日
@jowan
@hsfzxjy
@zbinlin 回答正确~ 💯
mayday526
2018 年 11 月 19 日
@jerrry 用 FiraCode 的话,别人看我的代码要愣一下
seki
2018 年 11 月 19 日
Math.random = () => 1
lastpass
2018 年 11 月 19 日
回复 @seki 注意执行顺序呀。
linxiaoziruo
2018 年 11 月 19 日
@hsfzxjy 验证了下代码,执行正确。但是我有个不明白的地方,爆栈应该只会出现在 d()这个函数的递归调用上,到了执行 apiX()的时候,栈应该重新记数了,应该不会触发 apix 的 catch。求解!
FakeLeung
2018 年 11 月 19 日
Emmmmm 作为一个前端,看不懂,跑了。
Sevenskey
2018 年 11 月 19 日
@linxiaoziruo 排队求解。顺便一说我发现只要 catch 中执行的函数的函数体内部有 try catch 且 try 中含有函数调用,就会在函数调用处抛爆栈的错;但如果这个函数体内部存在函数调用却没有 try catch,那么就不会抛错。。猜测也许是引擎的某些策略?
autoxbc
2018 年 11 月 19 日
@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
2018 年 11 月 20 日
楼上正解,这里的关键就在于让调用 internal(x)的时候爆栈就行,只要调用栈足够深就爆栈,递归只是达成这一目的的方式
ericgui
2018 年 11 月 20 日
@hsfzxjy 只有你的代码我能看懂
mytry
2018 年 11 月 20 日
公布答案~

linxiaoziruo
2018 年 11 月 20 日
@mytry 老哥多来点这种趣味性的东西!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://v2ex.xtra.eu.org/t/509253

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX