如何使console.log显示对象的当前状态?

164
在Safari和其他大多数浏览器中,console.log将显示对象在最后执行状态下的情况,而不是调用console.log时的状态。
我必须克隆对象才能通过console.log输出它,以获取该行代码中对象的状态。 示例:
var test = {a: true}
console.log(test); // {a: false}
test.a = false; 
console.log(test); // {a: false}

2
以下是与问题相关的jsfiddle示例和各种解决方案:http://jsfiddle.net/luken/M6295/ - Luke
11
对于 log 函数输出对象的实时引用是极其反直觉的。这被称为 watch,与日志条目有很大不同。在记录存储原始值的变量时,将对象记录下来并没有任何意义。 - faintsignal
2
我以前怎么从来没有遇到过这个?我觉得这很可怕。 - ErikAGriffin
12个回答

181

我认为你需要使用console.dir()

console.log()不能满足你的需求,因为它打印了一个对象的引用,而当你打开它时,它已经发生了改变。而console.dir在调用它时会打印该对象中所有属性的目录。

下面的JSON方法也不错,你甚至可以解析JSON字符串并获取一个可浏览的对象,就像使用.dir()一样:

console.log(JSON.parse(JSON.stringify(obj)));


42
对于我在Chrome13中,console.logconsole.dir 没有区别。 - Andrew D.
1
我在Chrome中看到的是,如果在日志语句运行后打开控制台,那么它将在您展开它时进行惰性评估。但是,如果控制台已经打开(例如,您打开控制台,然后在页面上点击刷新),它将进行急切评估——即在运行日志语句时打印该值。 - Polemarch
6
就像浅拷贝和深拷贝的关系一样,dir 与 JSON 也有类似的关系。console.dir() 只会评估顶层对象的属性(其他更深层的对象不会被评估),而 JSON 会进行递归评估。 - Polemarch
9
同样地,对于我来说,在 Chrome(v33)中 console.dir 不起作用。这是人们提供的解决方案的比较:http://jsfiddle.net/luken/M6295/。 - Luke
我没有像 Polemarch 那样体验到效果。我一直保持控制台打开状态,但 console.dir 仍然与 console.log 没有区别。 - Magne
显示剩余6条评论

74

如果我想要查看它被记录时的状态,我通常会将其转换为JSON字符串。

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

4
太好了,这对我是个不错的提示:我只需要再次解析它,就可以在控制台中正确地获取我的对象。function odump(o){ console.log($.parseJSON(JSON.stringify(o))); } - Chris
1
谢谢,这对我有用!console.dir没有打印它。 - ah-shiang han
1
如果您的对象恰好包含循环结构,该怎么办? - Alex McMillan
1
@AlexMcMillan 你可以使用其中之一 几个 ,这些库允许对具有循环引用的对象进行 JSON 字符串化。 - Alex Turpin
8
哎呀,这个应该是一件简单而明显的事情。相反,我们必须进行字符串化、解析、记录并使用一个特殊的循环引用库!?!我认为浏览器需要更好地支持简单的调试需求。 - Mars

32

纯JavaScript:

@evan的回答 在这里似乎是最好的。只需滥用JSON.parse/stringify来有效地复制对象即可。

console.log(JSON.parse(JSON.stringify(test)));

JQuery的专用解决方案:

您可以使用jQuery.extend在特定时间点创建对象快照。

console.log($.extend({}, test));

这里实际上发生的是jQuery使用test对象的内容创建了一个新对象,并记录了它(因此不会改变)。

AngularJS(1)特定解决方案:

Angular提供了一个copy函数,可用于同样的效果:angular.copy

console.log(angular.copy(test));

Vanilla JS包装函数:

这是一个函数,它包装了console.log,但在将对象记录出来之前会先复制一份。

我写这篇文章是为了回应答案中的几个类似但不够健壮的函数。它支持多个参数,并且如果它们不是常规对象,则不会尝试复制它们。

function consoleLogWithObjectCopy () {
  var args = [].slice.call(arguments);
  var argsWithObjectCopies = args.map(copyIfRegularObject)
  return console.log.apply(console, argsWithObjectCopies)
}

function copyIfRegularObject (o) {
  const isRegularObject = typeof o === 'object' && !(o instanceof RegExp)
  return isRegularObject ? copyObject(o) : o
}

function copyObject (o) {
  return JSON.parse(JSON.stringify(o))
}

使用示例: consoleLogWithObjectCopy('obj', {foo: 'bar'}, 1, /abc/, {a: 1})


8

控制台中的> Object,不仅仅显示当前状态。实际上,在您展开它之前,它会推迟读取对象及其属性。

例如:

var test = {a: true}
console.log(test);
setTimeout(function () {
    test.a = false; 
    console.log(test);
}, 4000);

然后展开第一个调用,如果在第二个console.log返回之前执行,则会得到正确的结果。


2

使用Xeon06的提示,您可以将其JSON解析为对象,这是我现在用来转储对象的日志函数:

function odump(o){
   console.log($.parseJSON(JSON.stringify(o)));
}

2

有一个使用调试器库的选项。

https://debugjs.net/

只需将脚本包含到您的网页中并放置日志语句即可。

<script src="debug.js"></script>

日志记录

var test = {a: true}
log(test); // {a: true}
test.a = false; 
log(test); // {a: false}

1

到2022年底,出现了一个新选项: 使用新的DOM structuredClone方法对对象进行深拷贝:

console.log(structuredClone(obj))

它使用与在 Web Worker 之间传输消息时使用的克隆算法相同的克隆算法。

这应该比 JSON.parse(JSON.stringify(obj)) 技术更快,并且适用于更多类型的对象。

有关详细信息,请参见 https://developer.mozilla.org/en-US/docs/Web/API/structuredClone


1
我定义了一个实用程序:

function MyLog(text) {
    console.log(JSON.stringify(text));
}

而当我想要在控制台上登录时,我只需执行以下操作:

MyLog("hello console!");

它非常好用!


1

-1

我可能因为提出这个建议而被批评,但是我们可以更进一步。我们可以直接扩展控制台对象本身,使其更清晰明了。

console.logObject = function(o) {
  (JSON.stringify(o));
}

我不知道这是否会导致某种类型的库冲突/核融合/时空连续性破裂。但它在我的qUnit测试中运行得非常完美。:)


3
这并不记录任何内容,它只是吞噬了对某个东西进行 stringify 后的结果。有趣的是它已经得到了投票支持。 - Zach Lysobey
请在您的答案中添加一些解释,以便其他人可以从中学习。 - Nico Haase

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接