Static and Instance Methods in JavaScript


I thought I quite ‘understood’ inheritance in JavaScript until I got flummoxed while trying to test my understanding. The JS prototypical inheritance model is hugely different from the classical approaches of the languages I started out with; the only way to fix this that I know of is by writing code and after spending hours screaming at my console I finally saw the light Alhamdulilah.

JS is a weakly-typed prototypical language and thus classes aren’t really ‘classes‘; instead they are functions which are in turn objects. New objects are created from constructor functions by using the new keyword and this allows you to kind of ‘simulate’ OOP. But mind you; its inheritance model is still different.

Some sample code that shows this difference between static and instance properties. All object properties are public although can easily make them private by declaring them with var (I added an example); for these private properties you’ll have to add accessors and setters; read this for an explanation of closures and this pattern.

//Constructor
var Person = function (name, age){
//private properties
var priv = {};
//Public properties
this.name = name;
this.age = age;
//Public methods
this.sayHi = function(){
alert('hello');
}
}
// A static method; this method only
// exists on the class and doesn't exist
// on child objects
Person.sayName = function() {
alert("I am a Person object ;)");
};
// An instance method;
// All Person objects will have this method
Person.prototype.setName = function(nameIn) {
this.name = nameIn;
}
// Tests
var per = new Person('John Doe', 22);
//Shows alert
Person.sayName();
//TypeError: Object [object Object] has no method 'sayName'
per.sayName()
//Show alert
per.sayHi();
//John Doe
per.name;
//22
per.age;
per.setName('Jane Doe');
//Jane Doe
per.name;
view raw gistfile1.js hosted with ❤ by GitHub

It’s interesting to see that static fields cannot be accessed from child context in JavaScript (which makes sense); Java, however, allows static fields to be accessed from object context; this is kinda weird as the objects don’t really ‘have’ that variable.

Here’s a quote from the Java Tutorials website:

Note: You can also refer to static fields with an object reference like myBike.numberOfBicycles but this is discouraged because it does not make it clear that they are class variables.

One tip: don’t just read code and assume you understand it. Sure, you can always convince yourself that you know it. However, if you really want to KNOW it, then read it, write it and then try extend it (if you have the time and enthusiasm).

So, what other differences do you know between classical and prototypical inheritance?

Related articles

19 thoughts on “Static and Instance Methods in JavaScript

  1. “classes aren’t really classes”?
    classes are classes.
    It’s just that there is no concept of class in ES5.
    You’re in functional programming territory now. Try to remove the concept of class all together, else you’ll just get confused and potentially confuse others also.
    There are other ways of creating objects than via the JavaScript constructor. Lets not neglect them, as they are our bread and butter?
    It’s not kind of simulating OOP. It’s OOP at it’s best.

    Why does using var create a private property (more specifically now a variable)?
    Variables are properties, but not vice versa.
    The VariableObject in ES3 or VariableEnvironment in ES5 Can be seen in the EcmaScript specs.
    Each execution context (be it global or any function) has an associated VariableObject.
    Variables (and functions) created within a given context are bound as properties of that context’s VariableObject (private).
    Even function parameters are added as properties of the VariableObject.
    Discussed in depth in:
    ECMAScript3 spec under “10 Execution Contexts”
    ECMAScript5 spec under “10.3 Execution Contexts” onwards

    What you’re showing here highlights why prototypal inheritance is more OO than classical inheritance.
    With prototypal inheritance, a child object only needs to inherit the parent objects specific properties pertinent to it.
    With classical inheritance, a child object inherits all the parent objects members, even the ones that it should have no knowledge of.

    A static method doesn’t exist on the class at all, as there is no concept of class in JavaScript.
    In your example, you are assigning a function to an objects (the constructor function) property.

    You should never invoke a constructor function directly without the new prefix as you have in your example.
    If you do, then the “this” of the sayName function will not be bound to the new object, but rather to the outer scoped object (Person in this case), so
    instead of augmenting your new object (sayName), you will be clobbering the outer scoped objects variables.

    Here’s a better way to achieve what you’re trying to achieve:

    Once you have Person and Person.sayName defined, you could assign Person.sayName to Person.prototype.sayName
    Person.prototype.sayName = Person.sayName;
    Do your invocation not forgetting new
    Then use your static as an instance method.
    per.sayName();

    So also, as you can see, static properties can be accessed from child context in JavaScript.

    Always favour composition over inheritance. Be it classical or prototypal.
    Angus Croll says it better than I can here: http://javascriptweblog.wordpress.com/2010/12/22/delegation-vs-inheritance-in-javascript/
    Even the Java creator James Gosling says he’d do away with classes or classical inheritance if he could write the language again: http://www.artima.com/intv/gosling34.html
    One of the Fluent Conference talks on why we should steer away from classical inheritance: http://fluentconf.com/fluent2013/public/schedule/detail/27878

    Like

    1. What? This makes hardly any sense to me.

      ” “classes aren’t really classes”?
      classes are classes.
      It’s just that there is no concept of class in ES5.”

      Classes in JavaScript aren’t really classes. I don’t know why you correct him for saying they aren’t really classes, by saying there are classes, then go on to say there actually aren’t classes…

      “You’re in functional programming territory now. Try to remove the concept of class all together, else you’ll just get confused and potentially confuse others also.”

      Functional programming and classes are not mutually exclusive. See F#. As far as I know, there is no canonical precise definition for functional programming. Functional programming isn’t just one language.

      “Why does using var create a private property (more specifically now a variable)?
      Variables are properties, but not vice versa.”

      var is private because you can’t access the variable without an accessor function once you make the object from the class.

      “You should never invoke a constructor function directly without the new prefix as you have in your example.”

      He didn’t as far as I can tell. I don’t see Person() being called anywhere without ‘new’.

      “Once you have Person and Person.sayName defined, you could assign Person.sayName to Person.prototype.sayName
      Person.prototype.sayName = Person.sayName;
      Do your invocation not forgetting new”

      WHAT?? Why?

      “Always favour composition over inheritance. Be it classical or prototypal.”

      While generally accepted as better, inheritance isn’t evil, and can be helpful if you know what you’re doing. I don’t think that one rule should apply to everything.

      Like

  2. Thanks for the explanation Abdul. This is too good. I was able to understand and free my confusion on the topic.

    Like

  3. On line 11, you’ve got a method you describe as a public method. [I think] It’s actually better described as a ‘privileged method’, as only it will have access to the private variables within the constructor. Both ‘privileged’ and ‘instance’ methods are then public in the object instances which the constructor constructs.

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.