提问人:Frederik H 提问时间:7/2/2012 最后编辑:danronmoonFrederik H 更新时间:4/13/2023 访问量:67407
console.log() 在变量实际更改之前显示变量的更改值
console.log() shows the changed value of a variable before the value actually changes
问:
这段代码我明白了。我们复制了 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]
有人可以解释第二个例子中发生了什么吗?
答:
数组是对象。变量是指对象。因此,在第二种情况下,赋值将对数组的引用(地址)从“A”复制到“C”。之后,两个变量都引用同一个对象(数组)。
像数字这样的原始值在像您这样的简单赋值中从一个变量完全复制到另一个变量。“A++;” 语句为“A”分配一个新值。
换一种说法:变量的值可以是原始值(数字、布尔值或字符串),也可以是对对象的引用。字符串基元的情况有点奇怪,因为它们更像是对象而不是基元(标量)值,但它们是不可变的,所以可以假装它们就像数字一样。null
评论
console.log
splice()
编辑:保留此答案只是为了在下面保留有用的评论。
@Esailija实际上是正确的 - 不一定会记录变量在您尝试记录它时的值。在您的例子中,两个调用都将记录排序后的值。console.log()
console.log()
C
如果您尝试在控制台中以 5 个单独的语句的形式执行相关代码,您将看到预期的结果(首先是、 ,然后是 )。[2, 1]
[1, 2]
评论
console.log()
.sort()
虽然它并非在所有情况下都有效,但我最终使用了一个“断点”来解决这个问题:
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'}
评论
console.log
Pointy 的回答有很好的信息,但这不是这个问题的正确答案。
OP 描述的行为是 2010 年 3 月首次报告的错误的一部分,该错误于 2012 年 8 月针对 Webkit 进行了修补,但截至撰写本文时,尚未集成到 Google Chrome 中。该行为取决于在将对象文本传递给 时控制台调试窗口是打开还是关闭。console.log()
原始错误报告摘录(https://bugs.webkit.org/show_bug.cgi?id=35801):
描述 From mitch kramer 2010-03-05 11:37:45 PST
1) 创建具有一个或多个属性的对象文字
2) console.log 该对象,但将其关闭(不要在控制台中展开它)
3) 将其中一个属性更改为新值
现在打开该控制台.log,您会看到它出于某种原因具有新值,即使它在生成时的值不同。
我应该指出,如果你打开它,如果不清楚,它将保留正确的值。
来自 Chromium 开发人员的回复:
评论 #2 来自 Pavel Feldman 2010-03-09 06:33:36 PST
我认为我们永远不会解决这个问题。我们无法在将对象转储到控制台时克隆对象,也无法侦听对象属性的更改以使其始终实际。
不过,我们应该确保现有行为是预期的。
随之而来的是很多抱怨,最终导致了错误修复。
2012 年 8 月实施的补丁的更新日志说明 (http://trac.webkit.org/changeset/125174):
从今天开始,将对象(数组)转储到控制台将导致对象的属性 在控制台对象扩展时读取(即延迟)。这意味着转储相同的对象,而 使用控制台进行调试将很难对其进行更改。
此更改开始为对象/数组生成缩写预览,此时 日志记录并将此信息传递到前端。这仅在前端发生 ,它仅适用于控制台.log,不适用于实时控制台交互。
评论
let test = [{a: 1}, {b: 2}]; console.log(test); test[0].xxx = 100; console.log(test);
console.log()
传递对对象的引用,因此控制台中的值会随着对象的更改而变化。为避免这种情况,您可以:
console.log(JSON.parse(JSON.stringify(c)))
请注意,如果您在最新版本的 Chrome 和 Firefox 中记录对象,则您在控制台上记录的是对对象的引用,这不一定是您调用时对象的“值”,但它是您打开控制台时对象的值。
console.log()
评论
Safari 中也存在此问题。正如其他人在此问题和类似问题中指出的那样,控制台被传递到对对象的引用,它打印打开控制台时对象的值。例如,如果直接在控制台中执行代码,则按预期打印值。 我更喜欢传播数组,而不是 JSON 字符串化(例如,在您的案例中 console.log([...C]);)和对象:结果完全相同,但代码看起来更简洁一些。我有两个 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))) 相同的输出,您可以根据需要省略字符串部分。顺便说一句,扩展语法通常可以节省时间和代码。
截至2023年3月9日的信息
Mozilla 截至 2023 年 3 月的最新指南:
延迟检索有关对象的信息。这意味着日志消息显示对象在首次查看时的内容,而不是在记录对象时的内容。例如:
const obj = {};
console.log(obj);
obj.prop = 123;
这将输出 .但是,如果展开对象的详细信息,您将看到 .{}
prop: 123
如果要更改对象,并且希望阻止更新记录的信息,则可以在记录对象之前对其进行深度克隆。一种常见的方法是,然后:JSON.stringify()
JSON.parse()
console.log(JSON.parse(JSON.stringify(obj)));
还有其他在浏览器中起作用的替代方法,例如 structuredClone(),
它们在克隆不同类型的对象时更有效。
const mushrooms1 = {
amanita: ["muscaria", "virosa"],
};
const mushrooms2 = structuredClone(mushrooms1);
mushrooms2.amanita.push("pantherina");
mushrooms1.amanita.pop();
console.log(mushrooms2.amanita); // ["muscaria", "virosa", "pantherina"]
console.log(mushrooms1.amanita); // ["muscaria"]
MDN 的上一页指导
Mozilla 截至 2023 年 2 月的最新指南:
不要使用,使用.
console.log(obj)
console.log(JSON.parse(JSON.stringify(obj)))
这样,您就可以确定在记录它的那一刻看到了它的价值。否则,许多浏览器会提供实时视图,该视图会随着值的变化而不断更新。这可能不是你想要的。
obj
评论
console.log(C.slice()); A.sort(); console.log(C);
console