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

2024-11-02 21:00:00
admin
原创
368
摘要:问题描述:我将从代码开始:var s = ["hi"]; console.log(s); s[0] = "bye"; console.log(s); 很简单,对吧?Firefox 控制台回应道:[ "hi&quo...

问题描述:

我将从代码开始:

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 控制台在评估我的数组时特别懒惰?

展现所描述行为的控制台的屏幕截图。


解决方案 1:

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

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

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

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

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

hi
bye

解决方案 2:

根据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

解决方案 3:

您可以使用以下方法克隆数组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,您必须在完成调试后将其剥离。

解决方案 4:

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

console.log(JSON.stringify(the_array));

解决方案 5:

看起来 Chrome 在其“预编译”阶段用指向实际数组的指针替换了“s”的任何实例。

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

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;
}

解决方案 6:

到目前为止最短的解决方案是使用数组或对象扩展语法来获取要在记录时保存的值的克隆,即:

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

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

解决方案 7:

这个问题已经回答过了,但我还是会放弃我的答案。我实现了一个简单的控制台包装器,它不会受到这个问题的影响。需要 jQuery。

它仅实现了logwarnerror方法,您必须添加更多方法才能使其与常规互换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);
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用