Chrome log()显示变量值实际更改前的更改值

doinxwow  于 2022-12-06  发布在  Go
关注(0)|答案(7)|浏览(167)

这段代码我理解。我们复制一个A并称之为C。当A改变时,C保持不变

var A = 1;
var C = A;
console.log(C); // 1
A++;
console.log(C); // 1

但是当A是一个数组时,我们就有了不同的位置。不仅C会改变,而且在我们碰到A之前它就已经改变了

var A = [2, 1];
var C = A;
console.log(C); // [1, 2]
A.sort();
console.log(C); // [1, 2]

有人能解释一下第二个例子中发生了什么吗?

9rygscc1

9rygscc11#

Console.log()被传递了一个对对象的 * 引用 *,因此Console中的值会随着对象的更改而更改。要避免这种情况,您可以:

console.log(JSON.parse(JSON.stringify(c)))

MDN warns
请注意,如果您在最新版本的Chrome和Firefox中记录对象,您在控制台上记录的是对对象的引用,它不一定是您调用console.log()时对象的“值”,但它是您打开控制台时对象的值。

ltqd579y

ltqd579y2#

Pointy's answer提供了很好的信息,但不是此问题的正确答案。
OP描述的行为是2010年3月首次报告的bug的一部分,2012年8月为Webkit打了补丁,但截至本文撰写时尚未集成到Google Chrome中。该行为取决于在对象文字传递到console.log()时控制台调试窗口是打开还是关闭
原始错误报告(https://bugs.webkit.org/show_bug.cgi?id=35801)摘录:
描述来自米奇·克雷默2010-03-05 11:37:45 PST
1)创建具有一个或多个属性的对象文本
2)console.log该对象,但使其处于关闭状态(不要在控制台中展开它)
3)将其中一个属性更改为新值
现在打开console.log,您将看到它由于某种原因而具有新值,即使它的值在生成时是不同的。
我应该指出,如果您打开它,它将保留正确的值,如果这是不清楚的。
来自Chromium开发人员的回应:
评论#2来自帕维尔·费尔德曼2010-03-09 06:33:36 PST
我不认为我们会解决这个问题。我们不能在将对象转储到控制台时克隆对象,我们也不能监听对象属性的更改以使其始终是真实的。
我们应该确保现有的行为是预期的。
很多抱怨接踵而至,最终导致了bug修复。
2012年8月实施的修补程序(http://trac.webkit.org/changeset/125174)的更改日志说明:
到目前为止,将对象(数组)转储到控制台将导致对象的属性在控制台对象扩展时被读取(即延迟)。这意味着在改变同一对象的同时转储该对象将很难使用控制台进行调试。
此更改在记录对象/数组时开始生成其缩略预览,并将此信息沿着到前端。这仅在前端已打开时发生,它仅适用于console.log(),而不适用于实时控制台交互。

gopyfrb3

gopyfrb33#

Mozilla截至2022年12月的最新指引:
不要使用console.log(obj),使用console.log(JSON.parse(JSON.stringify(obj)))
这样你就可以确定你在记录obj的时候看到了它的值。否则,很多浏览器提供的实时视图会随着值的变化而不断更新。这可能不是你想要的。

3xiyfsfu

3xiyfsfu4#

数组是对象。变量引用对象。因此,第二种情况下的赋值将数组的引用(地址)从“A”复制到“C”。之后,两个变量引用同一个对象(数组)。
像数字这样的基元值在像你这样的简单赋值语句中完全从一个变量复制到另一个变量。语句将新值赋给“A”。
换一种说法:变量的值可以是一个基元值(数字、布尔值、null或字符串),也可以是对一个对象的引用。字符串基元的情况有点奇怪,因为它们更像对象而不是基元(标量)值,但它们是不可变的,所以可以假装它们就像数字。

qybjjes1

qybjjes15#

**编辑:**保留此答案只是为了保留下面有用得评论.

@Esailija是对的-console.log()不一定会记录变量在你试图记录它时的值。在你的例子中,两个对console.log()的调用都会记录C**排序后的值。
如果您尝试在控制台中以5个单独的语句执行相关代码,您将看到预期的结果(首先是[2, 1],然后是[1, 2])。

eqzww0vc

eqzww0vc6#

虽然这并不适用于所有情况,但我最终使用了一个“断点”来解决这个问题:

mysterious = {property:'started'}

// prints the value set below later ?
console.log(mysterious)

// break,  console above prints the first value, as god intended
throw new Error()

// later
mysterious = {property:'changed', extended:'prop'}
b1payxdu

b1payxdu7#

这个问题在Safari中也存在。正如其他人在这个问题和类似问题中指出的,控制台被传递了一个对对象的引用,它在控制台打开时打印对象的值。例如,如果你直接在控制台中执行代码,值会按预期打印。而不是JSON字符串化,我更喜欢扩展数组(例如,在您的例子中,console.log([... C]); )和对象:结果是完全一样的,但是代码看起来更干净一些。2我有两个VS代码片段要分享。

"Print object value to console": {
      "prefix": "clo",
      "body": [
         "console.log(\"Spread object: \", {...$0});"
      ],
      "description": "Prints object value instead of reference to console, to avoid console.log async update"
   },
   "Print array value to console": {
      "prefix": "cla",
      "body": [
         "console.log(\"Spread array: \", [...$0]);"
      ],
      "description": "Prints array value instead of reference to console, to avoid console.log async update"
   }

为了获得与 console.log(JSON.parse(JSON.stringify(c))) 相同的输出,如果愿意,可以省略字符串部分。

相关问题