8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

Chrome 的 JavaScript 控制台在评估对象时是否很懒惰?

A. D'Alfonso 1月前

51 0

我先从代码开始:var s = [\'hi\'];console.log(s);s[0] = \'bye\';console.log(s);很简单,对吧?响应此代码,Firefox 控制台显示:[ \'hi\' ][ “...

我将从代码开始:

var s = ["hi"];
console.log(s);
s[0] = "bye";
console.log(s);

很简单,对吧?Firefox 控制台响应此消息并显示:

[ "hi" ]
[ "bye" ]

太棒了,但是 Chrome 的 JavaScript 控制台(7.0.517.41 beta)显示:

[ "bye" ]
[ "bye" ]

是我做错了什么吗,还是 Chrome 的 JavaScript 控制台在评估我的数组时特别懒惰?

Screenshot of the console exhibiting the described behavior.

帖子版权声明 1、本帖标题:Chrome 的 JavaScript 控制台在评估对象时是否很懒惰?
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由A. D'Alfonso在本站《object》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 这个问题已经回答过了,但我还是会放弃我的答案。我实现了一个简单的控制台包装器,它不会受到这个问题的影响。需要 jQuery。

    它只实现了 log , warn error 方法,你必须添加更多方法才能与常规方法互换 console .

    var fixedConsole;
    (function($) {
        var _freezeOne = function(arg) {
            if (typeof arg === 'object') {
                return $.extend(true, {}, arg);
            } else {
                return arg;
            }
        };
        var _freezeAll = function(args) {
            var frozen = [];
            for (var i=0; i<args.length; i++) {
                frozen.push(_freezeOne(args[i]));
            }
            return frozen;
        };
        fixedConsole = {
            log: function() { console.log.apply(console, _freezeAll(arguments)); },
            warn: function() { console.warn.apply(console, _freezeAll(arguments)); },
            error: function() { console.error.apply(console, _freezeAll(arguments)); }
        };
    })(jQuery);
    
  • 到目前为止最短的解决方案是使用数组或对象扩展语法来获取要在记录时保存的值的克隆,即:

    console.log({...myObject});
    console.log([...myArray]);
    

    但要注意,因为它执行的是浅拷贝,所以任何深层嵌套的非原始值都不会被克隆,因此在控制台中会显示它们的修改状态

  • @Shadow Wizard:显然,您的函数将无法克隆属性,并且无法对没有长度属性的任何对象起作用。webkit 错误会影响所有对象,而不仅仅是数组。

  • 对象,您指的是这个吗?var s = { param1: \'hi\', param2: \'how are you?\' }; 如果是这样,我刚刚测试过,当您有 s[\'param1\'] = \'bye\'; 时,它按预期正常工作。您能否发布 \'它不适用于对象\' 的示例?我会看看并尝试爬上那个。

  • @Shadow Wizard:好观点:clone.length 总是等于 i。它不适用于对象。也许有一个使用“for each”的解决方案。

  • alo 1月前 0 只看Ta
    引用 7

    没有错误,我执行了它,没有问题。 clone[clone.length] 与 clone[i] 完全相同,因为数组的长度从 0 开始,循环迭代器 \'i\' 也是如此。无论如何,不​​确定它在处理复杂对象时会如何表现,但在我看来,值得一试。就像我说的,这不是解决方案,而是解决问题的一种方法。

  • 这很好,但是由于它是浅拷贝,因此仍然可能存在更微妙的问题。那么那些不是数组的对象怎么办?(现在这些才是真正的问题。)我认为您所说的“预编译”并不准确。此外,代码中有一个错误:clone[clone.length] 应该是 clone[i]。

  • 看起来 Chrome 正在其 \'预编译' 阶段用 实际数组的 指针

    解决方法之一是克隆数组,然后记录新副本:

    var s = ["hi"];
    console.log(CloneArray(s));
    s[0] = "bye";
    console.log(CloneArray(s));
    
    function CloneArray(array)
    {
        var clone = new Array();
        for (var i = 0; i < array.length; i++)
            clone[clone.length] = array[i];
        return clone;
    }
    
  • 可以确认。当尝试注销 ReactSyntheticEvents 时,这确实是最糟糕的情况。即使是 JSON.parse(JSON.stringify(event)) 也无法获得正确的深度/准确性。调试器语句是我发现的唯一真正获得正确见解的解决方案。

  • Webkit 已经修复了这个问题,但是在使用 React 框架时,在某些情况下会出现这种情况,如果您遇到此类问题,请按照其他人的建议使用:

    console.log(JSON.stringify(the_array));
    
  • 引用 12

    您可以使用以下方法克隆数组 Array#slice

    console.log(s); // ["bye"], i.e. incorrect
    console.log(s.slice()); // ["hi"], i.e. correct
    

    您可以使用不存在此问题的函数 console.log 如下:

    console.logShallowCopy = function () {
        function slicedIfArray(arg) {
            return Array.isArray(arg) ? arg.slice() : arg;
        }
    
        var argsSnapshot = Array.prototype.map.call(arguments, slicedIfArray);
        return console.log.apply(console, argsSnapshot);
    };
    

    不幸的是,对于对象的情况,最好的方法似乎是先使用非 WebKit 浏览器进行调试,或者编写一个复杂的函数进行克隆。如果您只处理简单对象,其中键的顺序无关紧要,并且没有函数,您可以随时执行以下操作:

    console.logSanitizedCopy = function () {
        var args = Array.prototype.slice.call(arguments);
        var sanitizedArgs = JSON.parse(JSON.stringify(args));
    
        return console.log.apply(console, sanitizedArgs);
    };
    

    所有这些方法显然都非常慢,因此与正常方法相比 console.log ,您必须在调试完成后将其剥离。

  • 任何复制列表/对象的解决方案都可以。我最喜欢的对象浅拷贝自 ECMAScript 2018 开始可用:copy = {...orig}

  • 根据Eric的解释,这是由于 console.log() 排队,并且打印了数组(或对象)的后续值。

    可能有 5 种解决方案:

    1. arr.toString()   // not well for [1,[2,3]] as it shows 1,2,3
    2. arr.join()       // same as above
    3. arr.slice(0)     // a new array is created, but if arr is [1, 2, arr2, 3] 
                        //   and arr2 changes, then later value might be shown
    4. arr.concat()     // a new array is created, but same issue as slice(0)
    5. JSON.stringify(arr)  // works well as it takes a snapshot of the whole array 
                            //   or object, and the format shows the exact structure
    
  • 使用调试器从代码中插入断点也是一个不错的选择。(或者,如果可行的话,从开发人员工具中手动添加断点)。

  • 我只想提一下,在当前的 Chrome 版本中,控制台延迟并且再次输出错误值(或者曾经正确过)。例如,我正在记录一个数组并在记录后弹出顶部值,但它显示时没有弹出值。您的 toString() 建议确实很有帮助,让我能够看到我需要的值。

  • 引用 17

    执行以下操作:console.log(JSON.parse(JSON.stringify(s));

  • 引用 18

    实际上,对于关联数组或其他对象,这可能是一个真正的问题,因为 toString 不会产生任何有价值的东西。对于一般对象,有没有简单的解决方法?

  • 引用 19

    感谢评论,tec。我找到了一个现有的未经证实的 Webkit 错误来解释这个问题: https://bugs.webkit.org/show_bug.cgi?id=35801 ?id=35801(编辑:现已修复!)

    关于这个错误有多严重以及是否可以修复,似乎存在一些争议。在我看来,这确实是一种不好的行为。这对我来说尤其令人不安,因为至少在 Chrome 中,当代码驻留在立即执行的脚本中时(在页面加载之前),即使控制台已打开,只要页面刷新,就会发生这种情况。在控制台尚未激活时调用 console.log 只会导致对排队对象的引用,而不是控制台将包含的输出。因此,在控制台准备就绪之前,不会对数组(或任何对象)进行评估。这确实是一种惰性评估的情况。

    但是,有一个简单的方法可以在代码中避免这种情况:

    var s = ["hi"];
    console.log(s.toString());
    s[0] = "bye";
    console.log(s.toString());
    

    通过调用 toString,您可以在内存中创建一个表示形式,该表示形式不会被以下语句改变,控制台将在准备就绪时读取该表示形式。控制台输出与直接传递对象略有不同,但似乎是可以接受的:

    hi
    bye
    
  • 2020 年 4 月,Chrome 中出现此问题。我花了 2 个小时寻找代码中的错误,结果发现是 Chrome 中的一个错误。

返回
作者最近主题: