console.log()在值实际更改之前显示变量的更改值

Fre*_*k H 43 javascript variables google-chrome

我理解这段代码.我们制作A的副本并将其称为C.当A被更改时,C保持不变

var A = 1;
var C = A;
console.log(C); // 1
A++;
console.log(C); // 1
Run Code Online (Sandbox Code Playgroud)

但是当A是阵列时,我们会有不同的情况.C不仅会改变,而且会在我们触及A之前发生变化

var A = [2, 1];
var C = A;
console.log(C); // [1, 2]
A.sort();
console.log(C); // [1, 2]
Run Code Online (Sandbox Code Playgroud)

有人可以解释第二个例子中发生的事情吗?

Ka *_*ech 37

Console.log()将记录对象,因此值将在打印中更改.为避免这种情况,请执

console.log(JSON.parse(JSON.stringify(c)))
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请访问https://developer.mozilla.org/en-US/docs/Web/API/Console/log


Ell*_* B. 30

Pointy的答案有很好的信息,但这不是这个问题的正确答案.

OP描述的行为是2010年3月首次报告的错误的一部分,2012年8月针对Webkit进行了修补,但截至撰写本文时尚未集成到Google Chrome中.该行为取决于在传递对象文字时控制台调试窗口是打开还是关闭console.log().

摘自原始错误报告(https://bugs.webkit.org/show_bug.cgi?id=35801):

描述来自mitch kramer 2010-03-05 11:37:45太平洋标准时间

1)创建具有一个或多个属性的对象文字

2)console.log该对象但保持关闭(不要在控制台中展开它)

3)将其中一个属性更改为新值

现在打开console.log并且由于某种原因你会看到它具有新值,即使它的值在生成时是不同的.

我应该指出,如果你打开它,它将保留正确的值,如果不清楚.

来自Chromium开发人员的回复:

评论#2来自Pavel Feldman 2010-03-09 06:33:36太平洋标准时间

我认为我们永远不会解决这个问题.我们无法在将对象转储到控制台时克隆对象,并且我们也无法监听对象属性的更改以使其始终是实际的.

我们应该确保现有的行为是可以预期的.

很多抱怨随之而来,最终导致错误修复.

2012年8月实施的补丁中的更改日志说明(http://trac.webkit.org/changeset/125174):

截至今天,将对象(数组)转储到控制台将导致在控制台对象扩展(即懒惰)时读取对象的属性.这意味着在使用控制台进行调整时转储相同的对象将很难调试.

此更改开始在记录时生成对象/数组的缩写预览,并将此信息传递到前端.这只发生在前端已经打开时,它只适用于console.log(),而不适用于实时控制台交互.

  • 今天*部分的*实际上应该是第一位的. (4认同)
  • 尽管被"修复",但这个问题仍然在我身上发生,包括Chrome 46.0.2490.86以及Qt的WebKit(Qt 5.5).当对象的记录值*改变*时,非常令人困惑.现在我想我可以尝试通过每次打印时对对象进行深层复制来避免此问题. (2认同)
  • 因此,开发人员不必仅仅打印所涉及的对象或数组,而是必须找到一种冗长且泛滥的方式来打印该对象或数组的内容,因为Chrome开发人员太顽固而无法实现这个补丁?完全精神错乱! (2认同)

ray*_*chz 18

截至 2021 年 8 月,Mozilla的最新指南:

不要用console.log(obj),用console.log(JSON.parse(JSON.stringify(obj)))

这样您就可以确定您obj在记录它的那一刻看到了它的价值。否则,许多浏览器会提供随着值的变化不断更新的实时视图。这可能不是您想要的。

  • 谢谢!哎呀,在 javascript 中做基本事情的样板数量,而不是搬起石头砸自己的脚...... (5认同)
  • 整个日志记录的要点不是基于在程序执行的逻辑流内的精确点保存现实快照的需要吗?因此,一旦程序结束,为了支持任意的“无论最后的值”而删除这些快照实际上是无意义的。 (3认同)
  • @Bennybear 这也让我吃了几天的苦头,这就是为什么我每月更新这个答案,哈哈 (2认同)

Poi*_*nty 11

数组是对象.变量指的是对象.因此,第二种情况下的赋值将对数组的引用从"A" 复制到"C".之后,两个变量都引用相同的单个对象(数组).

像你这样的简单赋值,像数字这样的原始值完全从一个变量复制到另一个变量.该null语句为"A"分配一个新值.

说另一种方式:一个变量的值可以是一个原始值(数字,布尔值,null或字符串),或者它可以是一个参考的一个对象.字符串基元的情况有点奇怪,因为它们更像是对象而不是原始(标量)值,但它们是不可变的,因此可以假装它们就像数字一样.

  • @Nate是的; 我不确定我的回答是什么让人困惑.原始问题中的第二个例子可能是`console.log`工作方式固有的延迟的副作用.根据我的经验,Chrome的开发者控制台在这方面是最成问题的. (3认同)
  • 那么有没有办法打印出一个数组到控制台,修改这个数组,然后打印出修改后的版本呢? (2认同)
  • @Nate OK - 根据我的经验,Chrome是最糟糕的.我从来没有找到让它表现得更好的方法,但是我也没有真正尝试过那么努力. (2认同)