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

时间:2012-07-01 18:36:45

标签: javascript google-chrome variables

我理解这段代码。我们制作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]

有人可以解释第二个例子中发生了什么吗?

7 个答案:

答案 0 :(得分:27)

Pointy's answer有很好的信息,但这不是这个问题的正确答案。

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 PST

     

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

     

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

     

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

     

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

     

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

Chromium开发人员的回应:

  

评论#2来自Pavel Feldman 2010-03-09 06:33:36 PST

     

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

     

我们应该确保预期现有行为。

随后出现了很多抱怨,最终导致错误修复。

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

  

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

     

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

答案 1 :(得分:22)

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

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

了解更多信息https://developer.mozilla.org/en-US/docs/Web/API/Console/log

答案 2 :(得分:10)

数组对象。变量引用到对象。因此,第二种情况下的赋值将引用复制到数组中,从“A”复制到“C”。之后,两个变量都引用同一个对象(数组)。

像数字这样的原始值在像你这样的简单赋值中完全从一个变量复制到另一个变量。 A++;语句为“A”分配一个新值。

换句话说:变量的值可能是 原始值(数字,布尔值,null或字符串),或者它可能是引用到对象。字符串基元的情况有点奇怪,因为它们更像是对象而不是原始(标量)值,但它们是不可变的,因此可以假装它们就像数字一样。

答案 3 :(得分:4)

编辑:保留此答案只是为了保留以下有用的评论。

@Esailija实际上是正确的 - console.log()不一定会记录变量在您尝试记录时的值。在您的情况下,对console.log()的两次调用都会在排序后记录C 的值。

如果您尝试在控制台中以5个单独的语句执行相关代码,您将看到预期的结果(首先是[2, 1],然后是[1, 2])。

答案 4 :(得分:3)

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

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

答案 5 :(得分:0)

Safari中也存在该问题。正如其他人在此问题和类似问题中所指出的那样,控制台被传递了对对象的引用,它在控制台打开时输出对象的值。例如,如果直接在控制台中执行代码,则值将按预期打印。 除了使用JSON字符串化之外,我更喜欢散布数组(例如您的情况 console.log([... C]); )和对象:结果是完全一样的,但是代码看起来像清洁一点。我有两个here可以分享。

    "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)))相同的输出,可以根据需要省略字符串部分。顺带提一下,VS code snippets通常可以节省时间和代码。

答案 6 :(得分:0)

Mozilla截至2019年11月的最新指南:

  

请勿使用console.log(obj),而应使用console.log(JSON.parse(JSON.stringify(obj)))

     

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