Write Information about JavaScript Objects to the Browser Console

The approach described in this blog post writes information about JavaScript objects (including their properties, methods, and values) to the console, recursing through objects exposed as properties, making it easier to see what is available without referring to the documentation, and writing identifiers to the console that a developer can easily copy and paste into code. There are probably better ways to do this, libraries even; but this works for me and I like to have this level of control over instrumentation. I am currently using this to evaluate the Contentstack UI extension JavaScript library, but a similar approach should work with any library.

After a few decades of doing my best to avoid it, I am finally starting to learn JavaScript. I know that I should read books. I know that I should read the documentation. I spend plenty of time reading code samples. I often find it easier and faster to scan data and read code, especially when I can copy and paste. The approach described here allows copying identifiers rather than calculating them from API docs.

It took a while to get it working, but there really is not much to the code. You need to pass the object to debug to a recursive method. In this case, I am developing a Contentstack widget, which is a form of UI extension, and I want to see what the extension framework provides. First, this code outputs the JSON of the entry selected in the content management UI, which provides a tree nav. Then it outputs some information about the extension object, its methods, and its values. The code descends into any properties of type object, showing the same information indented an additional level, and additional levels for their object descendants.

The “reflection” work is apparently fast, but there is some delay before the output appears on the console.

Below is the bare-bones code, which I subsequently incorporated into to the developer widget that I had developed previously.

Without saying anything about best practice, code quality, or testing, this seems to function with no adverse side-effects.

<html>
  <head>
    <script src="https://www.contentstack.com/sdks/contentstack-ui-extensions/dist/latest/ui-extension-sdk.js" />
  </head>
  <body>
    <div id="scratch">Thinking (or possibly in an error state)...</div>
    <script>

ContentstackUIExtension.init().then(function(extension)
{
  console.log("Entry JSON:");
  console.log(extension.entry._data);
  recurse("extension.entry", extension.entry);
//  recurse("extension", extension);
  document.getElementById("scratch").innerHTML = "Done thinking. See output in JavaScript console.";
});

// log object elements, recursively
function recurse(name, obj, spaces = '')
{
  var value = "";

  // don't show function bodies
  if (typeof(obj) != "function")
  {
    value = " : " + obj;
  }
  
  // log the object
  var msg = spaces + name + " : " + typeof(obj) + value;
  console.log(msg);

  // log methods of the object
  for (const [method, body] of Object.entries(getMethods(obj)))
  {
    var msg = spaces + "  " + name + "." + method + "()" + " : method" /* + body*/;
    console.log(msg);
  }

  // log values in the object
  var lastKey;

  try
  {
    // store most recently attempted key in case of error
    var lastKey;

    for (const [key, value] of Object.entries(obj))
    {
        lastKey = key;

        // recurse descendants of object
        if (typeof(value) == "object")
        {
          recurse(name + "." + key, value, spaces + "  ");
        }
        else
        {
            output = "";

            // don't render method bodies
            if (typeof(value) != "function")
            {
                output = " : " + value;
            }

            var msg = "  " + spaces + '' + name + "['" + key + "'] : " + typeof(value) + output;
            console.log(msg);
        }
    }
  }
  catch(error)
  {
    var msg = "ERROR accessing " + name + "[" + lastKey + "]" + " : " + error
    console.log(msg);
  }
}

// get the methods in the object and its base prototypes(s)
function getMethods(obj)
{
  var methods = {};
  var currentObj = obj
  
  do
  {
    for(const key of Object.getOwnPropertyNames(currentObj))
    {
      // try to limit methods shown for object/array/string/etc

      if (typeof(obj[key]) === "function")
      {
        if (key != "hasOwnProperty"
          && key != "isPrototypeOf" 
          && key != "propertyIsEnumerable" 
          && key != "toString" 
          && key != "constructor" 
          && key != "concat" 
          && key != "copyWithin" 
          && key != "fill" 
          && key != "find" 
          && key != "findIndex" 
          && key != "lastIndexOf" 
          && key != "pop" 
          && key != "push" 
          && key != "reverse" 
          && key != "shift" 
          && key != "unshift" 
          && key != "slice" 
          && key != "sort" 
          && key != "splice" 
          && key != "includes" 
          && key != "indexOf" 
          && key != "join" 
          && key != "keys" 
          && key != "entries" 
          && key != "values" 
          && key != "forEach" 
          && key != "filter" 
          && key != "flat" 
          && key != "flatMap" 
          && key != "map" 
          && key != "every" 
          && key != "some" 
          && key != "map" 
          && key != "reduce" 
          && key != "reduceRight" 
          && key != "toLocaleString" 
          && key != "valueOf"
          && !key.startsWith("__"))
        {
          methods[key] = obj[key].toString()
        }
      }
    }
  } while ((currentObj = Object.getPrototypeOf(currentObj)));
  
  return methods;
}

    </script>
  </body>
</html>

One thought on “Write Information about JavaScript Objects to the Browser Console

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: