一个神奇的 js 问题

2019-12-03 17:59:37 +08:00
 atwoodSoInterest
今天遇到了一个神奇的 js 问题,debug 到最后发现了问题,但是不知道原理,有大佬能解释下吗?

function func() {
var s = "heheda";
$.ajax({
type: "post",
dataType: "text",
contentType: "application/json; charset=utf-8",
url: "",
data: JSON.stringify([{}]),
success: function () {
},
error: function (ex) {
//debugger;
s = "inner heheda";
}
});

$.ajax({
type: "post",
dataType: "text",
contentType: "application/json; charset=utf-8",
url: "",
data: JSON.stringify([{}]),
success: function () {
},
error: function (ex) {
//debugger;
bug = "WTF?!";
}
});
}

测试环境:win10 chrome 78.0.3904.108 (正式版本) ( 64 位)

定义一个这样的函数,调用之后在 debug 模式下发现,在使用了外部变量 s 的 ajax callback 里面,s 是可以显示值的。但是在没有使用外部变量 s 的 ajax callback 里面,s 就变成了 undefined !这。。。也太神奇了吧
(不要用 console 打印哦,因为打印也用到了变量 s )
2659 次点击
所在节点    程序员
14 条回复
f056917
2019-12-03 18:02:34 +08:00
没使用变量 S,可不就是打印 undefined 吗,未定义啊
atwoodSoInterest
2019-12-03 18:05:55 +08:00
@f056917 外部变量 s 的作用域会因为内部使不使用而改变吗?你可以把 debugger 注释放开,调试一下。
guoguo2003guo
2019-12-03 18:09:36 +08:00
里面的 s 也定义一下呗
lqzhgood
2019-12-03 18:10:25 +08:00
不知道 lz 在说啥…
gaoryrt
2019-12-03 18:20:32 +08:00
变量提升
s = 123 第一步相当于 var s = undefined 放到第一行,执行到的时候再赋值 123
debugger 中断的时候可不就是 undefined 嘛
xiangyuecn
2019-12-03 18:42:59 +08:00
换 ie 试试应该就没有这个问题了。怀疑是 chrome 对这种闭包内压根没有作用的代码进行了优化,新版本浏览器经常 debugger 会出现这种,不过手动展开作用域里面的 Closure 会发现是有值的,手动存一个全局变量就能得到实际的值。
atwoodSoInterest
2019-12-03 19:48:22 +08:00
@xiangyuecn 正解!感谢
chairuosen
2019-12-03 19:54:23 +08:00
是 chrome 的优化,很早(起码 2-3y)就有了
caola
2019-12-03 21:06:14 +08:00
虽然不知道具体的表达,
callback 是异步执行的,你想直接在 callback 里面打印是不是有点搞笑了。。。
fox0001
2019-12-03 22:19:06 +08:00
@lqzhgood #4 确实不知道…我试了一下,可以在 callback 里改变 s 的值
atwoodSoInterest
2019-12-04 08:35:25 +08:00
@lqzhgood @caola @fox0001 我再解释一下,示例代码中的变量 s 的作用域应该在整个 func 函数中,两个 ajax callback 也都应该在作用域内。但是在 chrome 浏览器的 debug 模式下,就会发现神奇的一幕:使用了变量 s 的 callback 中,控制台可以输入 s,显示有值;没有使用变量 s 的 callback 中,控制台输出 s,显示 s is not defined。
laravel
2019-12-04 11:31:48 +08:00
setInterval('debugger', 1000);
xingyue
2019-12-04 23:48:49 +08:00
@xiangyuecn #6 你好,图 1 和图 2 是我复现楼主的代码,确实在[[Scopes]]中 Closure 找到了未使用的变量;但是图 3 中我注释掉了使用内部变量的代码,再次查看闭包返回的函数 f1 发现[[Scopes]]中 Closure 都没了,请问这是怎么回事
(图 1)

(图 2)

(图 3)
xiangyuecn
2019-12-05 08:41:55 +08:00
@xingyue #13 也许图 3 这个 Closure 是和变量一样被优化掉了吧,f2 函数内没有任何东西需要用到闭包。加一点别的什么的构成引用,应该就会显示这个 Closure

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

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

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

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

© 2021 V2EX