3

Given var a = {a:'a', b:'b', c:[1,2,3], d:{ d1:{ d2:{ d3:[1,2,3] }}}}; I would like to get the following output from console.log( util.inspect( a, {depth:null}));

{ a: 'a',
  b: 'b',
  c: Array[3],
  d: { d1: { d2: { d3: Array[3] } } } }

I tried the following but all I get is undefined

a.inspect = function(depth){
  var self = this;
  Object.keys(self).forEach( function(key){
    if(Array.isArray(self[key])){
      return key+': Array['+self[key].length+']';
    }else{
      return util.inspect(self[key]);
    }
  });
};

The documentation at node.js isn't very helpful, and all of the pages I've found on Google merely parrot the node.js text.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Jeff
  • 2,095
  • 25
  • 18
  • I'm no Node expert, but is `this` (and thus `self`) actually what you think it is? Why don't you just refer to `a` instead? – Cedric Reichenbach Dec 17 '15 at 08:39
  • The example in the node.js documentation uses `this.name` to refer to the object's `name` attribute, so I figured it would follow to use it the same way. – Jeff Dec 17 '15 at 08:43

2 Answers2

0

The problem is that your return statements refer to the inline function used for iterating over those items, so the inspect function doesn't return anything at all.

To fix that, you can iterate over the entries using a (blocking) for loop and return from there.

Apart of that, you should accumulate sub-results from each key and only return in the end.

I.e something like (not tested):

a.inspect = function(depth) {
  var result = '{';
  for (var key in this) {
    if (Array.isArray(this[key]))
      result += key + ': Array[' + this[key].length + ']';
    else
      result += util.inspect(this[key]);
  }
  result += '}';
  return result;
};

Note how you don't need any replacement for this, as you're always in the same closure.

Cedric Reichenbach
  • 8,970
  • 6
  • 54
  • 89
0

Cedric, you are correct that I wasn't returning anything from inspect -- the peril of trying to write code at 4am! But I can't seem to get rid of using self=this because it seems like I have to keep attaching the inspect function to the inner objects. After further experimentation, I have ended up with something that does not quite format things exactly the way util.inspect does, but it's close enough for my purposes.

var util=require('util');
var a = {a:'a', b:'b', c:[1,2,3], d:{ d1:{ d2: { d3:[1,2,3] }}, dd1: { dd2: { dd3: [1,2,3]}}}};
a.inspect = function(depth){
    var self = this;
    var sp = '  ';
    return '{ ' + Object.keys(self).reduce( function(str,key){
        if( key==='inspect' && typeof self[key]==='function' ) return str ;
        if(Array.isArray(self[key])){
            return str+(str?',\n'+sp.repeat(depth+1):'')+key+': Array['+self[key].length+']';
        }else{
            if( typeof self[key] === 'object' ) self[key].inspect=a.inspect ;
            return str+(str?',\n'+sp.repeat(depth+1):'')+key+': '+util.inspect(self[key], {colors:true,depth:null});
        }
    }, '') + ' }'
};
console.log( util.inspect( a, {colors:true,depth:null} ));

This requires a version of node that supports the repeat method, otherwise see MDN for a polyfill. Here is the output:

{ a: 'a',
  b: 'b',
  c: Array[3],
  d: { d1: { d2: { d3: Array[3] } },
  dd1: { dd2: { dd3: Array[3] } } } }
Jeff
  • 2,095
  • 25
  • 18