Zed
Zed

Reputation: 5931

Advantages of treating function as an object

Recently I came across a simple Command pattern implementation in JavaScript that uses function as an object instead of pure object to define functionality:

var CommandManager = (function() {
  function CommandManager() {}

  CommandManager.executed = [];
  CommandManager.unexecuted = [];

  CommandManager.execute = function execute(cmd) {
    cmd.execute();
    CommandManager.executed.push(cmd);
  };

  CommandManager.undo = function undo() {
    var cmd1 = CommandManager.executed.pop();
    if (cmd1 !== undefined){
      if (cmd1.unexecute !== undefined){
        cmd1.unexecute();
      }
      CommandManager.unexecuted.push(cmd1);
    }
  };

  CommandManager.redo = function redo() {
    var cmd2 = CommandManager.unexecuted.pop();

    if (cmd2 === undefined){
      cmd2 = CommandManager.executed.pop();
      CommandManager.executed.push(cmd2); 
      CommandManager.executed.push(cmd2); 
    }

    if (cmd2 !== undefined){
      cmd2.execute();
      CommandManager.executed.push(cmd2); 
    }
  };

  return CommandManager;
})(); 

and the usage:

CommandManager.execute({
  execute: function(){
    // do something
  },
  unexecute: function(){
    // undo something
  }
});

//call unexecute of prev. command
CommandManager.undo(); 
//call execute of prev. command
CommandManager.redo(); 

My question would be, is there any advantages in defining CommandManager function this way, instead of directly defining properties on object literal and assigning it back to var CommandManager

Upvotes: 0

Views: 70

Answers (1)

Guffa
Guffa

Reputation: 700302

The only use for that would be that you have a function that does absolutely nothing:

CommandManager(); // does nothing, returns undefined

Other than that, you can just as well write the code as an object literal and use this to avoid it being dependant on its own name:

var CommandManager = {
  executed: [],
  unexecuted: [],

  execute: function execute(cmd) {
    cmd.execute();
    this.executed.push(cmd);
  },

  undo: function undo() {
    var cmd1 = this.executed.pop();
    if (cmd1 !== undefined){
      if (cmd1.unexecute !== undefined){
        cmd1.unexecute();
      }
      this.unexecuted.push(cmd1);
    }
  },

  redo: function redo() {
    var cmd2 = this.unexecuted.pop();

    if (cmd2 === undefined){
      cmd2 = this.executed.pop();
      this.executed.push(cmd2); 
      this.executed.push(cmd2); 
    }

    if (cmd2 !== undefined){
      cmd2.execute();
      this.executed.push(cmd2); 
    }
  }

}

Upvotes: 1

Related Questions