In Chrome the console object defines two methods that seem to do the same thing:
console.log(...)
console.dir(...)
I read somewhere online that dir takes a copy of the object before logging it, whereas log just passes the reference to the console, meaning that by the time you go to inspect the object you logged, it may have changed. However some preliminary testing suggests that there's no difference and that they both suffer from potentially showing objects in different states than when they were logged.
Try this in the Chrome console (Ctrl+Shift+J) to see what I mean:
> o = { foo: 1 }
> console.log(o)
> o.foo = 2
Now, expand the [Object] beneath the log statement and notice that it shows foo with a value of 2. The same is true if you repeat the experiment using dir instead of log.
My question is, why do these two seemingly identical functions exist on console?
In Firefox, these function behave quite differently: log only prints out a toString representation, whereas dir prints out a navigable tree.
In Chrome, log already prints out a tree -- most of the time. However, Chrome's log still stringifies certain classes of objects, even if they have properties. Perhaps the clearest example of a difference is a regular expression:
> console.log(/foo/);
/foo/
> console.dir(/foo/);
* /foo/
global: false
ignoreCase: false
lastIndex: 0
...
You can also see a clear difference with arrays (e.g., console.dir([1,2,3])) which are logged differently from normal objects:
> console.log([1,2,3])
[1, 2, 3]
> console.dir([1,2,3])
* Array[3]
0: 1
1: 2
2: 3
length: 3
* __proto__: Array[0]
concat: function concat() { [native code] }
constructor: function Array() { [native code] }
entries: function entries() { [native code] }
...
DOM objects also exhibit differing behavior, as noted on another answer.
Another useful difference in Chrome exists when sending DOM elements to the console.
Notice:
console.log prints the element in an HTML-like tree
console.dir prints the element in a JSON-like tree
Specifically, console.log gives special treatment to DOM elements, whereas console.dir does not. This is often useful when trying to see the full representation of the DOM JS object.
There's more information in the Chrome Console API reference about this and other functions.
None of the 7 prior answers mentioned that console.dir supports extra arguments: depth, showHidden, and whether to use colors.
Of particular interest is depth, which (in theory) allows travering objects into more than the default 2 levels that console.log supports.
I wrote "in theory" because in practice when I had a Mongoose object and ran console.log(mongoose) and console.dir(mongoose, { depth: null }), the output was the same. What actually recursed deeply into the mongoose object was using util.inspect:
import * as util from 'util';
console.log(util.inspect(myObject, {showHidden: false, depth: null}));
I think Firebug does it differently than Chrome's dev tools. It looks like Firebug gives you a stringified version of the object while console.dir gives you an expandable object. Both give you the expandable object in Chrome, and I think that's where the confusion might come from. Or it's just a bug in Chrome.
In Chrome, both do the same thing. Expanding on your test, I have noticed that Chrome gets the current value of the object when you expand it.
> o = { foo: 1 }
> console.log(o)
Expand now, o.foo = 1
> o.foo = 2
o.foo is still displayed as 1 from previous lines
> o = { foo: 1 }
> console.log(o)
> o.foo = 2
Expand now, o.foo = 2
You can use the following to get a stringified version of an object if that's what you want to see. This will show you what the object is at the time this line is called, not when you expand it.
console.log(JSON.stringify(o));
Use console.dir() to output a browse-able object you can click through instead of the .toString() version, like this:
console.dir(obj/this/anything)
How to show full object in Chrome console?
From the firebug site
http://getfirebug.com/logging/
Calling console.dir(object) will log an interactive listing of an object's properties, like > a miniature version of the DOM tab.
Following Felix Klings advice I tried it out in my chrome browser.
console.dir([1,2]) gives the following output:
Array[2]
0: 1
1: 2
length: 2
__proto__: Array[0]
While console.log([1,2]) gives the following output:
[1, 2]
So I believe console.dir() should be used to get more information like prototype etc in arrays and objects.
Difference between console.log() and console.dir():
Here is the difference in a nutshell:
console.log(input): The browser logs in a nicely formatted manner
console.dir(input): The browser logs just the object with all its properties
Example:
The following code:
let obj = {a: 1, b: 2};
let DOMel = document.getElementById('foo');
let arr = [1,2,3];
console.log(DOMel);
console.dir(DOMel);
console.log(obj);
console.dir(obj);
console.log(arr);
console.dir(arr);
Logs the following in google dev tools:
Well, the Console Standard (as of commit ef88ec7a39fdfe79481d7d8f2159e4a323e89648) currently calls for console.dir to apply generic JavaScript object formatting before passing it to Printer (a spec-level operation), but for a single-argument console.log call, the spec ends up passing the JavaScript object directly to Printer.
Since the spec actually leaves almost everything about the Printer operation to the implementation, it's left to their discretion what type of formatting to use for console.log().
Related
In Safari with no add-ons (and actually most other browsers), console.log will show the object at the last state of execution, not at the state when console.log was called.
I have to clone the object just to output it via console.log to get the state of the object at that line.
Example:
var test = {a: true}
console.log(test); // {a: false}
test.a = false;
console.log(test); // {a: false}
I think you're looking for console.dir().
console.log() doesn't do what you want because it prints a reference to the object, and by the time you pop it open, it's changed. console.dir prints a directory of the properties in the object at the time you call it.
The JSON idea below is a good one; you could even go on to parse the JSON string and get a browsable object like what .dir() would give you:
console.log(JSON.parse(JSON.stringify(obj)));
What I usually do if I want to see it's state at the time it was logged is I just convert it to a JSON string.
console.log(JSON.stringify(a));
Vanilla JS:
#evan's answer seems best here. Just (ab)use JSON.parse/stringify to effectively make a copy of the object.
console.log(JSON.parse(JSON.stringify(test)));
JQuery specific solution:
You can create a snapshot of an object at a certain point in time with jQuery.extend
console.log($.extend({}, test));
What is actually happening here is jQuery is creating a new object with the test object's content, and logging that (so it will not change).
AngularJS (1) specific solution:
Angular provides a copy function that can be used to the same effect: angular.copy
console.log(angular.copy(test));
Vanilla JS wrapper function:
Here is an function which wraps console.log but will make a copy of any objects before logging them out.
I wrote this in response to a few similar but less robust functions in the answers. It supports multiple arguments, and will not try to copy things if they are not regular objects.
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))
}
example usage: consoleLogWithObjectCopy('obj', {foo: 'bar'}, 1, /abc/, {a: 1})
That > Object in the console, isn't only showing the current state. It actually is deferring reading the object and it's properties until you expand it.
For example,
var test = {a: true}
console.log(test);
setTimeout(function () {
test.a = false;
console.log(test);
}, 4000);
Then expand the first call, it will be correct, if you do it before the second console.log returns
using Xeon06's hint, you may parse his JSON in an object, and here is the log function I now use to dump my objects :
function odump(o){
console.log($.parseJSON(JSON.stringify(o)));
}
There is an option to use a debugger library.
https://debugjs.net/
Just include the script into your web page and put log statements.
<script src="debug.js"></script>
Logging
var test = {a: true}
log(test); // {a: true}
test.a = false;
log(test); // {a: false}
I defined an utility:
function MyLog(text) {
console.log(JSON.stringify(text));
}
and when I want to log on console I simply do:
MyLog("hello console!");
It works very well!
You might want to log the object in a human readable way:
console.log(JSON.stringify(myObject, null, 2));
This indents the object with 2 spaces at each level.
How can I pretty-print JSON using JavaScript?
There's a new option as of late 2022:
Deep copy the object with the new DOM structuredClone method:
console.log(structuredClone(obj))
which uses the same cloning algorithm that's used to transfer messages between web workers.
This should be faster and work with more types of objects than the JSON.parse(JSON.stringify(obj)) technique.
See https://developer.mozilla.org/en-US/docs/Web/API/structuredClone for details.
I may be shot for suggesting this, but this can be taken one step further. We can directly extend the console object itself to make it more clear.
console.logObject = function(o) {
(JSON.stringify(o));
}
I don't know if this will cause some type of library collision/nuclear meltdown/rip in the spacetime continuum. But it works beautifully in my qUnit tests. :)
Simply refresh the page after you open the console or open the console before you submit the request to the targeted page....
Just print whole object on console.
console.log(object);
this is my javascript test code:
console.log( [] == 'a' );
when running in my firefox it gives this error:
"TypeError: can't convert [] to primitive type"
what does this mean? It does not seem to apply to every browser/browser version, or in my case, even a tab.
I have two chrome tabs open, if I try the code in one it gives an error, but in the other tab it works fine - making me very confused about the inconsistency.
Here is an image showing the errors
So what am I missing here, why the inconsistency on chrome? Any help appreciated!
(EDIT 1)
I've found that the error comes when adding/changing a bunch of prototypes onto the Array object, so how can I add prototypes without causing this error?
{
// if I omit the first line, the error does not occur
Array.prototype.join = Array.prototype.concat;
console.log( [] == 'a' );
}
As you note, this is a consequence of modifying the Array prototype. Specifically because the method toString is used during an equality check between an array and a primitive value.
Generally, when you use == where one operand is an object, javascript will try to convert the object to a primitive using the steps outlined in the ECMAScript Spec. Parts 3 and 4 specifically:
If hint is "string", then let methodNames be «"toString", "valueOf"».
Else, Let methodNames be «"valueOf", "toString"».
As you can see, the toString method will be called as part of the attempt to convert the array to a primitive. The array valueOf method does not return a primitive by default, and since you've overriden the toString method, now it does not return a primitive either! Thus we move past step 5 and go on to 6 which says:
Throw a TypeError exception.
Here's a demonstration:
const oldToString = Array.prototype.toString;
Array.prototype.toString = function() {
console.log("Array toString method called!");
return "[" + this.join(", ") + "]";
}
// No type error, because we converted to a primitive (in this
// case, a string) successfully.
console.log([1, 2, 3] == "[1, 2, 3]")
Array.prototype.toString = function() {
return {};
}
// Type error, because we tried to convert to a primitive using
// toString, but we got an object back?!
console.log([1, 2, 3] == "[1, 2, 3]")
To be clear, this issue has nothing to do with browser differences or Firefox specifically but is instead a consequence of your modifications combined with the ECMAScript spec which all browsers follow.
In Safari with no add-ons (and actually most other browsers), console.log will show the object at the last state of execution, not at the state when console.log was called.
I have to clone the object just to output it via console.log to get the state of the object at that line.
Example:
var test = {a: true}
console.log(test); // {a: false}
test.a = false;
console.log(test); // {a: false}
I think you're looking for console.dir().
console.log() doesn't do what you want because it prints a reference to the object, and by the time you pop it open, it's changed. console.dir prints a directory of the properties in the object at the time you call it.
The JSON idea below is a good one; you could even go on to parse the JSON string and get a browsable object like what .dir() would give you:
console.log(JSON.parse(JSON.stringify(obj)));
What I usually do if I want to see it's state at the time it was logged is I just convert it to a JSON string.
console.log(JSON.stringify(a));
Vanilla JS:
#evan's answer seems best here. Just (ab)use JSON.parse/stringify to effectively make a copy of the object.
console.log(JSON.parse(JSON.stringify(test)));
JQuery specific solution:
You can create a snapshot of an object at a certain point in time with jQuery.extend
console.log($.extend({}, test));
What is actually happening here is jQuery is creating a new object with the test object's content, and logging that (so it will not change).
AngularJS (1) specific solution:
Angular provides a copy function that can be used to the same effect: angular.copy
console.log(angular.copy(test));
Vanilla JS wrapper function:
Here is an function which wraps console.log but will make a copy of any objects before logging them out.
I wrote this in response to a few similar but less robust functions in the answers. It supports multiple arguments, and will not try to copy things if they are not regular objects.
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))
}
example usage: consoleLogWithObjectCopy('obj', {foo: 'bar'}, 1, /abc/, {a: 1})
That > Object in the console, isn't only showing the current state. It actually is deferring reading the object and it's properties until you expand it.
For example,
var test = {a: true}
console.log(test);
setTimeout(function () {
test.a = false;
console.log(test);
}, 4000);
Then expand the first call, it will be correct, if you do it before the second console.log returns
using Xeon06's hint, you may parse his JSON in an object, and here is the log function I now use to dump my objects :
function odump(o){
console.log($.parseJSON(JSON.stringify(o)));
}
There is an option to use a debugger library.
https://debugjs.net/
Just include the script into your web page and put log statements.
<script src="debug.js"></script>
Logging
var test = {a: true}
log(test); // {a: true}
test.a = false;
log(test); // {a: false}
I defined an utility:
function MyLog(text) {
console.log(JSON.stringify(text));
}
and when I want to log on console I simply do:
MyLog("hello console!");
It works very well!
You might want to log the object in a human readable way:
console.log(JSON.stringify(myObject, null, 2));
This indents the object with 2 spaces at each level.
How can I pretty-print JSON using JavaScript?
There's a new option as of late 2022:
Deep copy the object with the new DOM structuredClone method:
console.log(structuredClone(obj))
which uses the same cloning algorithm that's used to transfer messages between web workers.
This should be faster and work with more types of objects than the JSON.parse(JSON.stringify(obj)) technique.
See https://developer.mozilla.org/en-US/docs/Web/API/structuredClone for details.
I may be shot for suggesting this, but this can be taken one step further. We can directly extend the console object itself to make it more clear.
console.logObject = function(o) {
(JSON.stringify(o));
}
I don't know if this will cause some type of library collision/nuclear meltdown/rip in the spacetime continuum. But it works beautifully in my qUnit tests. :)
Simply refresh the page after you open the console or open the console before you submit the request to the targeted page....
Just print whole object on console.
console.log(object);
I need to test deletion from a hash:
store = { 'a': 4 }
delete store['a']
expect(store['a']).toBeUndefined()
this test passed on chrome, but not in firefox. I get:
Expected null not to be defined.
How can I avoid this bug?
You're testing the wrong condition so it doesn't matter if Chrome and Firefox are returning different values (but see below). Consider this:
store = { a: 11 }
store['a'] = undefined
That will give you a store['a'] that is undefined but store will still have 'a' as a key.
If you want to check if delete removes the property, say exactly that:
expect('a' of store).toBe(false)
CoffeeScript's of operator is JavaScript's in operator and from the fine manual:
Using in with deleted or undefined properties
If you delete a property with the delete operator, the in operator returns false for that property.
[...]
If you set a property to undefined but do not delete it, the in operator returns true for that property.
That's exactly the behavior you're trying to test.
For the record, when I say:
store = { 'a': 4 }
delete store['a']
console.log store['a']
I get undefined in the latest Firefox.
My question is the same as Are Javascript arrays sparse? with one difference...
Are JavaScript arrays sparse, as implemented in Node.js (and/or V8)? I had assumed the were, but then I did the following test:
var testArray = [];
testArray[10000] = 'test';
console.log(testArray);
Returned is 10,000 blank elements, with 'test' at the end. Is this because of the way the debugging output works, or does Node.js actually allocate memory for the undefined array elements when adding new elements?
What you are seeing is not an actual array, just a representation. The console checks for the presence of a length and a splice property and prints the numeric properties of the object, which is why jQuery collections appear to be arrays when logged.
function RandomThingThatIsDefinitelyNotAnArray() {
this.splice = function() {};
this.length = 10;
this[5] = 5;
}
console.log(new RandomThingThatIsDefinitelyNotAnArray());
// shows [undefined, undefined, undefined, undefined, undefined, 5]
jsfFiddle for a live demo.
Node's util.inspect function specifically checks for sparse arrays to print them like that. In fact, it has a test that specifically checks for it. I know this because my full rewrite of node's inspector ultimately didn't make it into core, and lead to my UltraREPL.