Learning JavaSCript while trying to improve this tool so please comment on this simple JavaScript logging tool

StackOverflow https://stackoverflow.com/questions/1905151

Question

I was just trying to learn and understand jQuery source code (so far with little success X_X) in order to improve my JavaScript skills. As my understand of JavaScript increases I came up with this little logging/debugging tool. As of my level of JavaScript I am posting the code here for people to judge and audit. So potentially I can learn from the comments made. Can someone please point out potential issues, improvements? I tried to encapsulate the console implementation and map it to window.$console (the only place that messes with global scope).

(function() {
    var proxy = {}, //use private proxy object to prevent binding to global (window) object
        _id = "",
        _warning = false;
        results = {};

    if (this.$console) { //check if $console exists in global (window)
        warning("$console is conflicting with existing object and could not be mapped.");
    }
    else {
        this.$console = proxy; //if undefined we then map proxy to global (window) object
    }

    proxy.init = function(id) { //map the display ol html element on the page
        _id = id;
        results = document.getElementById(id);
        return this;
    }

    proxy.log = function(msg) {
        append(msg);
        return this;
    };

    proxy.assert = function(pass, msg) {
        var html = (pass) ? "<b style=\"color: green;\">Pass</b>, " + msg
                    : "<b style=\"color: red;\">Fail</b>, " + msg ;
        append(html);
        return this;
    }

    proxy.error = function(msg) {
        var html = "<b style=\"color: red;\">Error</b>, " + msg + "";
        append(html);
        return this;
    }

    function append(msg) {
        if (results != null) {
            results.appendChild(getChild("li", msg));
        }
        else {
            warning("Message could not be appended to element with \"Id: " + _id + "\".");
        }
        return this;
    };

    function getChild(type, html) {
        var child = document.createElement(type);
        child.innerHTML = html;
        return child;
    }

    function warning(msg) {
        if (!_warning) {
            _warning = true;
            alert(msg);
        }
    }

    return proxy;
}());

Usage

$console.init("console").log("hello world");
$console.assert(true, "This is a pass.");

ps: As I've made a few revisions to the code the question is quite different from what it was originally.

Was it helpful?

Solution

It seems like it would work OK. I find your use of anonymous functions a bit confusing, though. Since Console doesn't have any private data, why not define it like so:

var Console = {

    instance: document.getElementById('console'),

    Print: function (msg) {
        this.instance.innerHTML += msg;
        return this;
    },

    Log: function (msg) {
        this.Print("<br/>").Print(msg);
    }
};

I also removed the anonymous function used in the assignment of instance, since it didn't appear to be doing anything.

Edit

The evaluation-of-an-anonymous-function technique is typically used to hide declared variables. See http://yuiblog.com/blog/2007/06/12/module-pattern/ for a discussion.

If, for example, you wanted to hide the instance property, you might achieve that using an anonymous function in the following way:

var Console = (function () {

    // object containing public members to be returned
    var c = {};

    // not visible outside anonymous function
    var instance = document.getElementById('console');

    // a 'public' property
    c.Print = function (msg) {
        instance.innerHTML += msg;
        return this;
    };

    // a 'public' property
    c.Log = function (msg) {
        this.Print("<br/>").Print(msg);
    };

    return c;
}());

The resulting Console object exposes only the Print and Log properties.

OTHER TIPS

The only issue I see as far, is that you are actually exposing two globals, window.Console that is fine, since you want to expose it there, and $c.

This is because you are not using the var statement on the assignment, should be:

 var $c = this.Console;

If you don't use it, $c will be global.

Aside of that, maybe you may want to work on naming conventions, usually in JavaScript you name almost everything in camelCase, and only constructor functions in PascalCase, it's just a comment, I personally try to stick that convention but is up to you and your team.

Edit: about the concatenation made using the innerHTML property, if you will handle large amounts of data in your div, I would recommend you to use DOM manipulation, instead of replacing the whole innerHTML every time.

By DOM manipulation I refer to create your log messages as nested DOM elements of your div, by using document.createElement and element.appendChild.

I'd try to use the same API that Firebug and the IE Developer Toolbar expose so that you can degrade nicely. One build in that direction would be that if window.console already exists, then don't execute your code. That way you'll get the native debugger when it's available, otherwise you'll get your implementation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top