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

一个神奇的 js 问题

  •  1
     
  •   atwoodSoInterest · 6 天前 · 1573 次点击
    今天遇到了一个神奇的 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 条附言  ·  6 天前

    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 条附言  ·  6 天前

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

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

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

    (图 2)

    (图 3)
        14
    xiangyuecn   5 天前
    @xingyue #13 也许图 3 这个 Closure 是和变量一样被优化掉了吧,f2 函数内没有任何东西需要用到闭包。加一点别的什么的构成引用,应该就会显示这个 Closure
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4480 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 25ms · UTC 02:17 · PVG 10:17 · LAX 18:17 · JFK 21:17
    ♥ Do have faith in what you're doing.