5

I'm more of a back-end guy than a front-end guy, but JavaScript intrigues me. I'm trying to wrap my head around what seem to me to be multiple different methods of modeling objects.

For the past few years I've been primarily been writing code that looks similar to this (assume jQuery is loaded):

var TicketForm = {

    elements: ['input', 'textarea', 'select', 'checkbox'],

    enable: function(form) {
        this.elements.forEach( function(el) {
            form.find(el).prop('disabled', false);
        });
    },

    disable: function(form) {
        this.element.forEach( function(el) {
            form.find(el).prop('disabled', true);
        });
    }
};

This way I can simply call TicketForm.enable($('#whatever')); to enable a particular form, very similar to a static method call in PHP.

I've been playing with closures in PHP lately, and I'm aware that they exist (and I'm using them) in JavaScript as well. I'm trying to really grasp the concept more thoroughly. After coming across this amazing script: http://codepen.io/stuffit/pen/KrAwx, I decided I wanted to make an effort to mimic the coding style of that author. Just attempting to copy his style, I rewrote my code like this:

var TicketForm = function() {
    this.elements = ['input', 'textarea', 'select', 'checkbox'];
};

TicketForm.prototype.enable = function(form) {
    this.elements.forEach( function(el) {
        form.find(el).prop('disabled', false);
    });
};

TicketForm.prototype.disable = function(form) {
    this.elements.forEach( function(el) {
        form.find(el).prop('disabled', true);
    });
};

However, When I call TicketForm.enable($('#whatever')); in this case, I get the error

Uncaught TypeError: Object function () {
    this.elements = ['input', 'textarea', 'select', 'checkbox'];
} has no method 'enable'

So I did a little digging on SO and found How does JavaScript .prototype work?. The second answer in particular is very enlightening, as I come from a class-concept background rather than a prototype-concept background. I also flipped through a few of these slides: http://ejohn.org/apps/learn/#65, which was also helpful. It turns out that all I had to do was create an instance of TicketForm, at which time it's methods became available to me:

var myForm = new TicketForm();
myForm.enable(form); // works as expected

I have three questions:

  1. Why, aside from personal coding style, would one choose either one of the methods above over the other?
  2. Why do I have to declare an instance of the object with the second method, while I don't with the first?
  3. Are there proper names for either of these coding styles?
Community
  • 1
  • 1
Ben Harold
  • 6,242
  • 6
  • 47
  • 71
  • http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752/ – smk Jun 19 '13 at 20:42
  • 1
    Nothing to do with you actual question, but just saying, sometime, it is better to extend jQuery instead of creating an athor object : http://jsfiddle.net/rMXRB/1/. Instad of doing `obj.method(selector)` you do `select.method()`. It is good to know when to create obj and when to extend an object! – Karl-André Gagnon Jun 19 '13 at 21:03

3 Answers3

3

Your first method defines an object literal, basically creating a "singleton". If you need multiple instances of the same "class", you need a constructor function (or Object.create).

bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • I believe this answers all your 3 questions, please let me know if it doesn't. – bfavaretto Jun 19 '13 at 20:45
  • Also, maybe this other answer I just wrote might be helpful: http://stackoverflow.com/questions/17200558/javascript-functions-and-objects-using-keyword-this-does-not-work – bfavaretto Jun 19 '13 at 20:53
  • MDN page for [`Object.create`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create). – Paul S. Jun 19 '13 at 21:11
  • 1
    @PaulS. Added to the answer, I was being lazy! – bfavaretto Jun 19 '13 at 21:14
  • Ahhh...I think I understand. The first method I am defining one specific object, sort of like if I said `$var = new \stdclass;` in PHP, whereas the second method is more similar to writing a class in PHP. – Ben Harold Jun 19 '13 at 21:15
2

In JavaScript objects are mutable by default. This means that unless you're using a modern JavaScript engine and someone intentionally prevented the object from being modified, you can always add, remove and modify properties in an object.

In the first case you're using special syntax that simplifies object creation. The {} syntax creates a simple object which is no more than an instance of Object. This, combined with the mutability of objects in JS, means the following snippets are all equivalent:

var TicketForm = {
  elements: ['input', 'textarea', 'select', 'checkbox']
};

var TicketForm = {};
TicketForm.elements = ['input', 'textarea', 'select', 'checkbox'];

var TicketForm = new Object();
TicketForm.elements = ['input', 'textarea', 'select', 'checkbox'];

Essentially using {} is similar to creating an instance of an object in a classical OOP language, while creating a constructor function is similar to using a class. In a constructor function and its prototype you define a blueprint that all instances of that constructor function (all objects that share that prototype) will adopt.

So it's not about style, but rather about what you need to create. If you need multiple copies of the same thing, you use a constructor function. If you need only one, just create a plain object, no need to follow an etiquette, make a singleton and sign everything by triplicate ;)

juandopazo
  • 6,283
  • 2
  • 26
  • 29
0

The first method is a "litteral object", quite like a static class, "this" refers to the parent object "TicketForm", you can understand it like a "self". In the second method "this" refer to the window, it's not oo, unless you make:

var myForm = new TicketForm();

here "this" refers to the instance myForm. This method is the "constructor" method (TicketForm is the constructor)

Pierre
  • 429
  • 3
  • 15