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

2018-11-19 14:29:26 +08:00
 mytry

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

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

3938 次点击
所在节点    程序员
21 条回复
suzic
2018-11-19 15:14:29 +08:00
不会。但感觉用 eval 能解
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
2018-11-19 16:53:07 +08:00
```
function d () {
try {
return d()
} catch (e) {
return apiX()
}
}

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

用爆栈引发异常
jerrry
2018-11-19 17:07:12 +08:00
这是什么字体?怎么感觉比 FiraCode 还顺眼。
vicvinc
2018-11-19 17:26:45 +08:00
为啥 throw 一个 error 不会触发
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
2018-11-19 17:38:56 +08:00
精简下:

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

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

linxiaoziruo
2018-11-20 11:16:33 +08:00
@mytry 老哥多来点这种趣味性的东西!

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

https://www.v2ex.com/t/509253

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

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

© 2021 V2EX