Question

In PHP, you can do something like that:

class myClass() {
    function doSomething(someVar) {
         // do something here
    }
    // etc... (other methods and properties)
}

Then, of course, you could call that method after instanciating the class, like that:

$myObj = new myClass();
$myObj->doSomething();

But you would also have the option to call the method as a standalone function, without instantiating the class (but you'd have to pay attention to dependencies in that function), like that:

myClass::doSomething();

I believe it's something borrowed for C++... It's known as a Scope Resolution Operator (Paamayim Nekudotayim in the PHP code...)
http://en.wikipedia.org/wiki/Scope_resolution_operator#PHP
http://www.php.net/manual/en/language.oop5.paamayim-nekudotayim.php

How would you do something like that in JavaScript? It doesn't seem to be possible. Maybe I am approaching this the wrong way, I should disclose what I'm trying to achieve...

I simply have a function, which goes like this:

function submitContactForm(form) {
    // pretty JavaScript...
}

And I'm happy with it being a function. But I'd like to implement a "resetContactForm()" but would like to have it attached somehow to the submitConatctForm function.

I know I could probably do this:

var contactForm = {
   "submit" : function(form) {
       //...
   },
   "reset" : function(form) {
       //...
   }
}

And I'd have answered my own question like that...

But, besides the fact that I don't like this syntax, and would like to avoid it, there is also the fact that the above structure cannot be used as a class definition, it is not the same than in PHP... so going back to the original question: is there a way to have a JavaScript structure that can be used as a class definition and a collection of stand-alone functions at once?

Was it helpful?

Solution

You are mis-understanding prototypal inheritance - you actually can use your second example as a "class" definition and the methods can be invoked either from the "class" or from the "instance":

// This is a normal JavaScript object
// not JSON as another commenter pointed out.
var ContactForm = {
   submit: function(form) {
       form = form || this.form;
       // general contact form submission implementation
   },
   reset: function(form) {
       form = form || this.form;
       // general contact form reset implementation
   },
   setForm: function(form) {
       this.form = form;
   }
};

// Now we will create an instance of the contactForm "class"
// We are setting the prototype of `firstContactForm`
// to point at the `contactForm` object.
// If we wanted to we could create a function on the
// ContactForm object (e. g. `create`) that would invoke
// Object.create for us. (i. e. `ContactForm.create()`)
var firstContactForm = Object.create(ContactForm);
firstForm.setForm(document.getElementById("someForm"));
firstForm.reset();

 // But, we can also use the function as a "static":
 ContactForm.reset(document.getElementById("someForm"));

In answer to the other part of your question, if you want to make it something that is invokable "stand-alone" you can also allow the data to be passed in directly, as we are doing in the example with our form = form || this.form; checks in submit and reset.

Alternately, you can use call and apply (as @elclanrs points out in his answer) and always use this.form:

 ContactForm.reset.call({form: document.getElementById("someForm")});

OTHER TIPS

In JavaScript's object syntax you don't need quotes if there aren't any special characters:

var obj = {
   key: function() {
     ...
   },
   ...
}

Paamayim Nekudotayim has no place in JavaScript as there are no classes, no static methods. But JavaScript has a dynamic context, what we call this. It is not in any way similar to this in PHP or other classical inheritance languages, other than the name of the keyword.

A typical JavaScript "class" looks like:

// A "Class"
var Person = (function(){
  // Private stuff, shared across instances
  var instances = [];

  // The constructor AKA "__construct"
  function Person(name) {
    this.name = name;
    instances.push(this); // keep track of instances
  }

  // Static methods, attached to the constructor
  // don't need an instance
  Person.instances = function() {
    return instances;
  };

  // Public methods
  Person.prototype = {
    say: function() {
      return this.name +' says hello!';
    }
  };

  return Person;
}());

Now, how you use this:

var mike = new Person('Mike');
mike.say(); //=> Mike says hello!
Person.instances().length; //=> 1

So good so far. As for "scope resolution" in JavaScript, you can pass the context explicitly; knowing that this is dynamic, you can borrow the Person's say method and invoke it in any other context, for example:

Person.prototype.say.call({name:'John'}); //=> John says hello!

You can make it a class like this:

function ContactForm(form) {
    this.form = form;
}

ContactForm.prototype.submit = function() {
    console.log('submiting: ' + this.form);// do something with the form
}

ContactForm.prototype.reset = function() {
    console.log('reseting: ' + this.form);
}



var someForm = ...;

var form = new ContactForm(someForm);

form.submit();
form.reset();

Or if you want to use them statically you can do as following:

var ContactForm = (function() {
    var reset = function(form) {
        console.log('reseting' + form);
    };

    var submit = function(form) {
        console.log('submiting' + form);
    }

    return {
        submit: submit,
        reset: reset
    }
}()); // note that this is self-executing function

and use it like

ContactForm.submit(form);
ContactForm.reset(form);

Reading Sean Vieira and elclanrs' answers gave me better insight. I've come up with this code as a proof of concept, and to make sure I understood what I was reading. This is essentially a simplified version of elclanrs' answer:

function contactForm(form) {
    this.form = form;
}
contactForm.prototype.submit = function() {
    alert("submit "+this.form);
}
contactForm.prototype.reset = function() {
    alert("reset "+this.form);    
}

// Without instanciating:
contactForm.prototype.submit.call({form:'form2'});

// With instance:
myForm = new contactForm('form1');
myForm.reset();

So it seams this "functionality" is already available in JavaScript, albeit in a different, less straightforward form.

Also, Sean Vieira's approach, completed:

var ContactForm = {
   submit: function(form) {
       form = form || this.form;
       alert("submit "+form);
   },
   reset: function(form) {
       form = form || this.form;
       alert("reset "+form);
   },
   createForm: function(form) {
       var myForm = Object.create(this);
       myForm.setForm(form);
       return(myForm);
   },
   setForm: function(form) {
       this.form = form;
   }
};

// instanciated
myContactForm = ContactForm.createForm('Me Form');
myContactForm.submit();

// no instance
ContactForm.submit("Some Form");

Also (my contribution), how about using wrapper functions, like that? Looks like a decent option to me.

function contactForm(form) {
    this.form = form;
    this.submit = function() {
        submitContactForm(this.form)
    }
    this.reset = function() {
        resetContactForm(this.form);
    }
}
function submitContactForm(form) {
    alert("submit "+form);
}
function resetContactForm(form) {
    alert("reset "+form);    
}

// Without instanciating:
submitContactForm('form2');

// With instance:
myForm = new contactForm('form1');
myForm.reset();

There is no perfect solution...

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