3

As a learning experience, I'm trying to make my own little console debug script that is object-oriented. I want it to be similar to jQuery in that you can call it as a function (jQuery('div')) or as an object (jQuery.ajax()).

I have the code below which is almost working. It is basically an alias of "console.log".

My goal is to be able to perform the following:

var log = new RadDebug;
// Create our function

log('You selected: %s', fruit_type);
// Invoke the top-level function
// Output: You selected: "Apple"

log.warn('You selected: %s', fruit_type);
// Invoke a method "warn", which displays a caution icon next to the log.
// Output: (!) You selected "Apple"

The script I am working on:

function RadDebug() {
  var debug_enabled = (debug_mode && window.console && window.console.log instanceof Function);

  // If this object was already initialize, redirect the function call to the ".log()" as default
  if ( this.initialized ) {
    return this.log.apply( this, arguments );
  }
  this.initialized = true;

  this.log = function() {
    if ( !debug_enabled ) return;
    console.log.apply( console, arguments );
  };

  this.info = function() {
    if ( !debug_enabled ) return;
    console.info.apply( console, arguments );
  };

  // More methods below
}

The problem:

Calling log.warn("hello world") works as you would expect.

Calling log("hello world") tells me that TypeError: Object is not a function.

Question: How do I get it to work as a function and having object-like properties? (Like how jQuery does it)

(This question has been resolved thanks to @FelixKling. The final code is available as a Gist if you want to check it out).

Radley Sustaire
  • 3,382
  • 9
  • 37
  • 48
  • 3
    Every function is also an object in JavaScript, see http://stackoverflow.com/questions/3449596/every-object-is-a-function-and-every-function-is-object-which-is-correct – Niko Oct 24 '14 at 19:22
  • I'm aware of this, but the issue is that `log()` is no longer usable as a function - *only* as an object (such as `log.info()`). It's the one thing I'm not able to figure out for this mini-project. – Radley Sustaire Oct 24 '14 at 19:24
  • ^ Don't use `RadDebug` as constructor function, just attach the methods to the function itself. – Felix Kling Oct 24 '14 at 19:24
  • 1
    @FelixKling I tried that, `var log = function() {...}`. It resolves the `log()` issue. But then I cannot use `log.info()`. I'd like to have "the best of both worlds". – Radley Sustaire Oct 24 '14 at 19:27
  • 2
    I think you missed the second part of what @Felix Kling mentioned, "just attach the methods to the function itself" – thefourtheye Oct 24 '14 at 19:27
  • Oh, I hadn't thought of that, I'll play with it. He also posted an answer that I'll check out. Thanks guys – Radley Sustaire Oct 24 '14 at 19:28

2 Answers2

8

Don't use RadDebug as constructor function, just attach the methods to the function itself.

For example:

var RadDebug = (function() {
  // Some IIFE to keep debug_enabled and functions local
  var debug_enabled = (debug_mode && window.console && window.console.log instanceof Function);

  // Functions here
  function log() {
    if ( !debug_enabled ) return;
    console.log.apply( console, arguments );
  }

  function info() {
    if ( !debug_enabled ) return;
    console.info.apply( console, arguments );
  }

  // ...

  // Attach methods to "main" log function
  log.log = log;
  log.info = info;
  // ...

  // Return log function (RadDebug === log)
  return log;
}());

Then you use it as

RadDebug('You selected: %s', fruit_type);
// same as
RadDebug.log('You selected: %s', fruit_type);

RadDebug.info('You selected: %s', fruit_type);

or alias RadDebug to whatever you want (e.g. log).

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Yes this is it! Very interesting way to do it. It'll take a bit more time to soak in how this all works but it seems pretty slick. The anonymous function is building the "log" function and attaching the methods to it. Seems very clean that way. Thank you! – Radley Sustaire Oct 24 '14 at 19:40
  • This is just an excellent answer. It explains so much about the way to approach javascript. I wish i could vote more. – Pogrindis Oct 24 '14 at 19:41
2

Functions are Objects in Javascript. You can return a function in your RadDebug function and set one of its members to the same returned function. For example:

var hello = function () {
  var fn = function () {
    console.log("Hello");
  }

  fn.hello = fn;

  return fn;
}

var sayHello = new hello();
sayHello(); // prints "Hello"
sayHello.hello(); // prints "Hello"
ncardeli
  • 3,452
  • 2
  • 22
  • 27