Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

%j specifier in console.log excludes some properties

I was recently trying to load the bson (binary JSON) module in node.js. The API docs were unclear, so I thought inspecting the objects would help me. The results of the inspection were baffling.

Finally I found out it was because I was using %j which "lies" -- it doesn't print all of an object's dictionary keys! (I am using Python terminology for "attributes" as things referenced with a dot, and "dictionary keys" for things referenced with brackets, because I don't know the proper names for these things in JS.)

Here is an example:

var bson = require("bson");
console.log("bson as %%j: %j", bson);
console.log("bson as console.log: ", bson);

And here's the output:

bson as %j: {"BSONPure":{},"BSONNative":{}}
bson as console.log:  { BSONPure: 
   { Code: [Function: Code],
     Symbol: [Function: Symbol],
     BSON: 
      { [Function: BSON]
        BSON_INT32_MAX: 2147483647,
        BSON_INT32_MIN: -2147483648,
        BSON_INT64_MAX: 9223372036854776000,
        BSON_INT64_MIN: -9223372036854776000,
...

I thought since x.key is the same as x["key"], that this means attributes and dictionary keys are "the same thing" in JS. I found after experimenting that BSON.BSONPure is {}, however BSON.BSONPure.BSON and BSON.BSONPure["BSON"] are a function object!

This leads me to believe that whatever "%j" does, must somehow be excluding some keys. How does it decide which keys to exclude? Why would it even do that? JS is a really confusing language sometimes!

Related Github ticket: https://github.com/mongodb/js-bson/issues/97

like image 628
picomancer Avatar asked Oct 08 '14 20:10

picomancer


1 Answers

Down in the node.js source, the %j placeholder results in a call to JSON.stringify() on the passed argument.

The thing is, in passing your bson variable, you are not passing an valid JSON object. You are passing a node.js module which among other things has exported functions.

So, what happens when JSON.stringify() hits a function?

If undefined, a function, or a symbol is encountered during conversion it is either omitted (when it is found in an object) or censored to null (when it is found in an array). (MDN)

So the behaviour you are seeing is completely expected, you are trying to log something as JSON that is not valid JSON.

> JSON.stringify({name: "Bob"}) 
> "{"name":"Bob"}"

> JSON.stringify({func: function(){}}) 
> "{}"
like image 153
Pero P. Avatar answered Nov 02 '22 07:11

Pero P.