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

一个神奇的 js 问题

  •  1
     
  •   atwoodSoInterest · 2019-12-03 17:59:37 +08:00 · 2530 次点击
    这是一个创建于 1577 天前的主题,其中的信息可能已经有所发展或是发生改变。
    今天遇到了一个神奇的 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 )
    第 1 条附言  ·  2019-12-03 19:37:49 +08:00

    ie必须指定url,直接复制这段到控制台运行就行了

    function func() {	
        var s = "heheda";
        $.ajax({
            type: "post",
            dataType: "text",
            contentType: "application/json; charset=utf-8",
            url: "http://www.baidu.com",
            data: JSON.stringify([{}]),
            success: function () {
            },
            error: function (ex) {
                debugger;
                s = "inner heheda";
            }
        });
    
        $.ajax({
            type: "post",
            dataType: "text",
            contentType: "application/json; charset=utf-8",
            url: "http://www.baidu.com",
            data: JSON.stringify([{}]),
            success: function () {
            },
            error: function (ex) {
                debugger;
                bug = "WTF?!";
            }
        });
    }
    func();
    
    第 2 条附言  ·  2019-12-03 19:47:23 +08:00

    结果果然如 @xiangyuecn 大佬所说,是浏览器行为,换ie就没有这个问题了,是chrome自己的行为。结贴,感谢@xiangyuecn

    突然感慨,热帖 程序员总喜欢自断后路,难怪职业生涯只能到 35 岁 中的那种自我保护,从小了看似乎能保全一时,但是往大了看,其实是一种自我投毒。即使真有少部分人能用这种手段保全职位,但对于大多数情况和大多数人来说,都是没有前途的。

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

    (图 2)

    (图 3)
    xiangyuecn
        14
    xiangyuecn  
       2019-12-05 08:41:55 +08:00
    @xingyue #13 也许图 3 这个 Closure 是和变量一样被优化掉了吧,f2 函数内没有任何东西需要用到闭包。加一点别的什么的构成引用,应该就会显示这个 Closure
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1230 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 23:22 · PVG 07:22 · LAX 16:22 · JFK 19:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.