What's the difference between console.dir and console.log? - javascript

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

arrays containing string indexes

In python, a list, even when it is a class, prohibits its instances from creating more user attributes.
>> x = list()
>> x.new_attribute = 90
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'new_attribute'
This as expected throws error even when classes could possibly accept more attributes through __dict__. This makes sense.
Even though it isn't exactly similar, my questions is that javascript arrays act weirdly when they are given properties.
let x = [1,2,3]
x.foo = "this is unexcpected"
console.log(x)
This would print [1, 2, 3, foo: "this is unexcpected"]. Here is my questions, Aren't arrays supposed to have all their keys to be autogenerated numbers? I mean if I check the length it is still three and it isn't counting foo as part of the array in the usual sense, more over all the methods like pop doesn't apply to the key-value pair. This makes a good sense, but makes me wounder if this (addition of key-value pairs) is allowed so that they could be used to store metadatas about the arrays, after all length is also kind of a property. One more questions, if arrays can store key-value pairs, what makes them different from object except some of the methods like inserting, poping ...?
I know this thread is old, but I find the question interesting...
The main part of the question is what's the difference between an object and an array. As mentioned in the comments, Array.prototype IS an object. Which allows us to do some kind of weird things. Take this code for example:
let y = [0,1,2,3];
y.foo = "Testing";
console.log(y);
y.sample = function(){
console.log("Hello world");
}
y.sample()
Yes, you can add methods to an array, on the console it outputs this:
> (4) [0, 1, 2, 3, foo: 'Testing']
0: 0
1: 1
2: 2
3: 3
foo: "Testing"
sample: ƒ ()
length: 4
[[Prototype]]: Array(0)
> Hello World
Considering the way that Javascript was made, we can do odd things like add methods to arrays and treat them as objects. However, these objects have intended uses and built-in methods provided by the developers (push, pop, etc.). Maybe you could create your own modified datatype in JS by modifying the Array.prototype object. Outside of that, it feels kinda weird to add methods and properties to arrays...at that point just make an object for the sake of readability, but hey, as long as your code is understandable and it works, it's good to me.

How to specify which property to display when doing console.log to object?

When creating an object from constructor, sometimes the result object
have too much property to display when using console.log. How can I
specify which property to display?
For example if I have a constructor like this:
function Obj(source) {
this.lines = source.split('\n'); // it can be 1000 lines or even more
}
So, If I do:
var obj = new Obj(source);
console.log(obj);
it will print all those lines to the console. I want to exclude that
property on console.log, how?
On nodejs, console.log does use util.inspect to format objects for printing. You can customise it by providing your own inspect method on your objects.
Another simple way to prevent a property from being printed to the node console is to make it non-enumerable, as long as that doesn't break your code.
In browsers, with their interactive inspection of logged objects, you usually don't have a problem with too-large objects, as they will be expanded only on request. If you want to control exactly what is printed, your only option is to pass a string to console.log, though.
Other than using something else, no, you can't reasonably limit what console.log shows, and what it shows varies from console implementation to console implementation (or even within the same implementation depending on whether you're showing the console or not when log is called).
You may find console.dir more useful in this case than console.log. From MDN:
Displays an interactive list of the properties of the specified JavaScript object. The output is presented as a hierarchical listing with disclosure triangles that let you see the contents of child objects.
Of course, that's only really useful if you have an interactive console display (such as in a browser).
Alternately, you could use console.log(String(obj)); and override the default toString to do what you want:
Obj.prototype.toString = function() {
// generate your designer output here
return desiredOutputString;
};
Depending on the console implementation, in some cases, you may not need the String(...) part when calling console.log, but in most of them you would.
It will by default print all the properties. Unless you specify which property you want to print, it will print all.
If you don't want all the lines then define the property as a function which will give line by line view
function Obj(source) {
this.source = source;
this.lines = function(){
return this.source.split('\n');
}
}
Now if you do console.log(Obj) it will only show one line.
Add a method which will print the object as you like. E.g.
Obj.prototype.debug = function () {
console.log({
x: this.x,
y: this.y
});
};
If it's just in the logging that you want to omit the property you could define and immediately call a function in your console.log command.
The function could copy the object, remove the lines property from it and log the resulting object:
function Obj(source) {
this.lines = source.split('\n'); // it can be 1000 lines or even more
}
var obj = new Obj(source);
console.log((function(){var copy = Object.assign({}, obj); delete copy.lines; return copy;})())

Create Object in Object

I'm confuse the way how Google Chrome developer tool console is displaying if the (A) is the actual object created in the loop, why are the (B) contains 3 objects?
Does it means (A) will contain 3 objects?
Demo: https://jsfiddle.net/LygmkgLm/
var test={}
for(var i=0;i<3;i++){
test[i]={}
test[i].y="111"
console.log("test",test)
}
You're misinterpreting the console output. It correctly and and as expected shows the increasing contents of the object within the loop, hence the 1, 2 and 3 members in the output. At the end however the variable 'test' is the fully filled object, and when you expand the first line it shows the contents at the time of expansion. Being the fully filled object with 3 children.
Your confusion arises from the fact that the logging does not store the state of the object at logging time.
Chrome console shows the final object in console. It shows whatever the values have gone through the object. So in console first it will show you
test Object {0: Object}
But when you extend, it will have three object which has passed through it.
test Object {0: Object}0: Object1: Object2: Object__proto__: Object
One thing to note that, at first iteration of the loop, you may see three object in console but only one object i.e.
test Object {0: Object}
is actually accessible. If you want to check actual state of object in each iteration, you have to clone it like below
var newObject = jQuery.extend(true, {}, test);
Here is the fiddle which will give you an idea of my points https://jsfiddle.net/qtdurtzc/

nodejs `arguments` is object but in the browser, it is an `array`

When I access arguments from inside called function in nodejs...
echo '!function(){ console.log(arguments) }(1,2,3)' | node
... it outputs an object ...
{ '0': 1, '1': 2, '2': 3 }
... but in google chrome ...
!function(){ console.log(arguments) }(1,2,3)
... outputs ...
[1, 2, 3]
Why is it not consistent? What other js environments have this different behaviour? Is it ok for me to use arguments? How can I ensure it is always an array before I use it?
There are no rules for console output. The output doesn't represent anything that has to do with the language standard.
If you create a program that logs values from within a JS program, you're free to display those values however you want.
The arguments object is the same in both places. Only how it's being displayed is different.
How can I ensure it is always an array before I use it?
It's never an array. It's always an array-like object. In both cases its showing a value at object members 0, 1 and 2. Just uses different display syntax to do it.
In Chrome, try creating an object like this:
var my_obj = {
"0": 1,
"2": 3,
"1": 2,
length: 3,
splice: function(){},
};
And the log it in the console. It'll probably look like an Array literal, though it's obviously not.
It's not an Array in the browser, either. The arguments object has actually been in JavaScript longer than Arrays have, and when Arrays were first added to JavaScript (back in its 1.1 days), they didn't update arguments to be an Array. They haven't done it since then either, because of worries about backward-compatibility. It shows up in some browser consoles as though it were an Array because the debug console knows that most people plan to treat it as one anyway.
But the arguments object is close enough to an Array that it's easy to convert. One way to do it is like this:
var args = Array.prototype.slice.call(arguments, 0);
Array.prototype.slice, like most of Array.prototype's methods, is written to be generic: you can call it on Objects that aren't Arrays, and as long as they have properties with numeric names and a length property that's a Number, it'll work. The arguments object has both of these things, so these functions will work on it.
The slice function returns an Array which is a shallow copy of whatever object was passed into it, starting and ending at whatever numbers you specify. We tell it to start at zero, and because we didn't say where to stop, it assumes we want it to stop at the end, wherever that might be. This way, we copy all of the elements of arguments into a new Array, and now you can do whatever other Array things you want with it.

How to modify the output in chrome console when printing a javascript object

I would like to know what's behind the scenes when I print an object in the console (like in the situation illustrated in the image).
How can I define a special function inside the object for printing my own code instead of all the attribute of the object (the equivalent of toString in Objective-C)? For example if I evaluate a in the console I want to print only the string "hello" and not all {one: 1, two: 2, hello: "hello"}.
Can I do it without using console.log() or similar functions?
Well, I am not sure if this is your question, but you could always override the toString() method of the object.
var a = {a:"something", hello:"hello", toString:function(){console.log(this.hello)}};
a.toString() // prints hello
Hope that helps!

Categories