274

I know this will work:

function Foo() {};
Foo.prototype.talk = function () {
    alert('hello~\n');
};

var a = new Foo;
a.talk(); // 'hello~\n'

But if I want to call

Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly

I find some methods to make Foo.talk work,

  1. Foo.__proto__ = Foo.prototype
  2. Foo.talk = Foo.prototype.talk

Are there other ways to do this? I don’t know whether it is right to do so. Do you use class methods or static methods in your JavaScript code?

Bill Keller
  • 793
  • 7
  • 22
lostyzd
  • 4,515
  • 3
  • 19
  • 33
  • 14
    `Foo.talk = function ...` – Premature Optimization Oct 08 '11 at 03:40
  • 1
    @downvoterstepintothelight The `Foo.walk = function() {}` won't effect its instances, as it is not on the prototype chain. Is there cross-browser a method to make a function's `[[prototype]]` point to its `prototype`? – lostyzd Oct 08 '11 at 03:41
  • 3
    probably i have no idea what you want, because **class methods do not affect instances** by definition. – Premature Optimization Oct 08 '11 at 03:46
  • @downvoterstepintothelight I doubt that, [method](http://en.wikipedia.org/wiki/Method_(computer_programming)), in language like python, an instance is able to call its class method, the difference is `this` pointer. – lostyzd Oct 08 '11 at 03:53

15 Answers15

431

First off, remember that JavaScript is primarily a prototypal language, rather than a class-based language1. Foo isn't a class, it's a function, which is an object. You can instantiate an object from that function using the new keyword which will allow you to create something similar to a class in a standard OOP language.

I'd suggest ignoring __proto__ most of the time because it has poor cross browser support, and instead focus on learning about how prototype works.

If you have an instance of an object created from a function2 and you access one of its members (methods, attributes, properties, constants etc) in any way, the access will flow down the prototype hierarchy until it either (a) finds the member, or (b) doesn't find another prototype.

The hierarchy starts on the object that was called, and then searches its prototype object. If the prototype object has a prototype, it repeats, if no prototype exists, undefined is returned.

For example:

foo = {bar: 'baz'};
console.log(foo.bar); // logs "baz"

foo = {};
console.log(foo.bar); // logs undefined

function Foo(){}
Foo.prototype = {bar: 'baz'};
f = new Foo();
console.log(f.bar);
// logs "baz" because the object f doesn't have an attribute "bar"
// so it checks the prototype
f.bar = 'buzz';
console.log( f.bar ); // logs "buzz" because f has an attribute "bar" set

It looks to me like you've at least somewhat understood these "basic" parts already, but I need to make them explicit just to be sure.

In JavaScript, everything is an object3.

everything is an object.

function Foo(){} doesn't just define a new function, it defines a new function object that can be accessed using Foo.

This is why you can access Foo's prototype with Foo.prototype.

What you can also do is set more functions on Foo:

Foo.talk = function () {
  alert('hello world!');
};

This new function can be accessed using:

Foo.talk();

I hope by now you're noticing a similarity between functions on a function object and a static method.

Think of f = new Foo(); as creating a class instance, Foo.prototype.bar = function(){...} as defining a shared method for the class, and Foo.baz = function(){...} as defining a public static method for the class.


ECMAScript 2015 introduced a variety of syntactic sugar for these sorts of declarations to make them simpler to implement while also being easier to read. The previous example can therefore be written as:

class Foo {
  bar() {...}

  static baz() {...}
}

which allows bar to be called as:

const f = new Foo()
f.bar()

and baz to be called as:

Foo.baz()

1: class was a "Future Reserved Word" in the ECMAScript 5 specification, but ES6 introduces the ability to define classes using the class keyword.

2: essentially a class instance created by a constructor, but there are many nuanced differences that I don't want to mislead you

3: primitive values—which include undefined, null, booleans, numbers, and strings—aren't technically objects because they're low-level language implementations. Booleans, numbers, and strings still interact with the prototype chain as though they were objects, so for the purposes of this answer, it's easier to consider them "objects" even though they're not quite.

zzzzBov
  • 174,988
  • 54
  • 320
  • 367
  • Well, just want to make it somehow like oop languages. Should I use `Foo.talk = Foo.prototype.talk` to avoid duplicate definition of `talk`? – lostyzd Oct 08 '11 at 03:33
  • @lostyzd - why is it a method to begin with? Either it uses `this` and needs to be called as an instance method, or it doesn't use `this` and you can make it a simple attribute of `Foo` (and have instances call `Foo.talk()`). – nrabinowitz Oct 08 '11 at 03:48
  • @nrabinowitz I try to make instances have the access to its constructor's method(static method). – lostyzd Oct 08 '11 at 03:59
  • 1
    @lostyzd - well, they can access it, through `Foo.talk()`. You could assign that in the constructor, if you want: `this.talk = Foo.talk` - or, as you note, by assigning `Foo.prototype.talk = Foo.talk`. But I'm not sure this is a good idea - on principle, instance methods should be specific to the instance. – nrabinowitz Oct 08 '11 at 04:02
  • I might be confused about your intent, but in your example, "a" is your instance. And "a" has access to the constructor's method, because you can call "a.talk()". In JS, you would very rarely have a reason to call Foo.talk() — this is essentially calling a method on the constructor, when the OO pattern would be to simple create an instance FROM the constructor and call it on that instance (a.talk). – Doug Avery Oct 08 '11 at 05:53
  • 2
    @Doug Avery, `Foo.talk()` is just calling a namespaced function. You'd use it in situations similar to how static methods are called in OOP languages like Java/C#. A good example of a use case would be a function like [`Array.isArray()`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray). – zzzzBov Oct 08 '11 at 06:01
  • Well put, thank you. I am coming to Javascript from an OOP background (Python / C++), and I find it mind boggling how many ways there are to do things in this language. I need static methods for a geometry module, which I intend to use like so: `var distance_squared = Geometry.Sphere.distance_squared.AABox(a_spherical_object, an_axis_aligned_rectangular_object);` – Dan Ross Dec 17 '12 at 03:07
  • Isn't what he was originally asking just like Array().splice.call()? – Shane Courtrille Apr 04 '13 at 17:28
  • 7
    P.S. null is object typeof null == 'object' – mvladk Jun 19 '13 at 10:55
  • @mvladk, Yea, I've been meaning to update this post, as value objects aren't fully fledged objects either. – zzzzBov Jun 19 '13 at 11:10
  • 1
    The fundamental point you are all missing is that static methods get inherited. `Foo.talk = function ()...` wont be available to subclasses on there own class name. This can be worked around by "extending" subclasses, but I'm also still looking for a more elegant way. –  Jul 27 '13 at 02:07
  • 1
    @nus, only some languages allow static methods to be inherited. If inheritance is desired you shouldn't be using static methods to begin with. – zzzzBov Jul 29 '13 at 01:11
  • Can static method access property defined in class? – Alan Kis Oct 19 '13 at 18:03
  • @AlanKis If you're interested in accessing a non-static property, then you'd typically access it using a non-static function. – WynandB Jan 13 '14 at 23:50
  • I want to remark that JavaScript is indeed OOP! It has all the fundamental features: dynamic dispatch, encapsulation, subtyping, open recursion. The absent of class-concept is compensated by the prototype-concept. Classes were just a additional feature. – Doomjunky Jul 31 '14 at 22:12
69

You can achieve it as below:

function Foo() {};

Foo.talk = function() { alert('I am talking.'); };

You can now invoke "talk" function as below:

Foo.talk();

You can do this because in JavaScript, functions are objects as well.

Bipul
  • 1,564
  • 1
  • 15
  • 16
40

Call a static method from an instance:

function Clazz() {};
Clazz.staticMethod = function() {
    alert('STATIC!!!');
};

Clazz.prototype.func = function() {
    this.constructor.staticMethod();
}

var obj = new Clazz();
obj.func(); // <- Alert's "STATIC!!!"

Simple Javascript Class Project: https://github.com/reduardo7/sjsClass

Eduardo Cuomo
  • 17,828
  • 6
  • 117
  • 94
  • 15
    This is not a static call. var obj = new Clazz(); creates a new _instance_ of Clazz. However, Clazz.staticMethod() achieves the result without all of that other stuff. – mpemburn Nov 12 '14 at 11:05
  • 5
    @mpemburn: Eduardo is also correct in his answer. What he's showing you is not only can you call the static method from "outside" via `Clazz.staticMethod` but he's showing you how to link to these static methods from within an instantiated object. This is especially useful in enviornments like Node.js where, using require, you may not have direct access to the original constructor. The only thing I would add is `this.constructor.staticMethod.apply(this, arguments);` – Mauvis Ledford Jun 12 '15 at 19:15
  • 1
    Absolutely awesome, even works inside a coffee-script constructor: `constructor: (a) -> @constructor.add @` (well almost, anyway) – Orwellophile Aug 26 '16 at 07:45
35

Here is a good example to demonstrate how Javascript works with static/instance variables and methods.

function Animal(name) {
    Animal.count = Animal.count+1||1;// static variables, use function name "Animal"
    this.name = name; //instance variable, using "this"
}

Animal.showCount = function () {//static method
    alert(Animal.count)
}

Animal.prototype.showName=function(){//instance method
    alert(this.name);
}

var mouse = new Animal("Mickey");
var elephant = new Animal("Haddoop");

Animal.showCount();  // static method, count=2
mouse.showName();//instance method, alert "Mickey"
mouse.showCount();//Error!! mouse.showCount is not a function, which is different from  Java
JaskeyLam
  • 15,405
  • 21
  • 114
  • 149
  • Good point : This could be weird not to have access to static function through `this`. – TrapII Oct 16 '15 at 07:26
  • 1
    Thanks for the solution this is what i was looking in which situation there will be access of `this` keyword – santhosh Apr 01 '19 at 07:57
33

In additions, now it is possible to do with class and static

'use strict'

class Foo {
 static talk() {
     console.log('talk')
 };

 speak() {
     console.log('speak')
 };

};

will give

var a = new Foo();
Foo.talk();  // 'talk'
a.talk();    // err 'is not a function'
a.speak();   // 'speak'
Foo.speak(); // err 'is not a function'
Dima Fomin
  • 1,228
  • 1
  • 16
  • 27
  • 1
    This is the best answer, as examples are worth a thousand words. However, it doesn't explain why `a.talk()` doesn't work. The accepted answer says the chain of prototypes should find it, right? But it's not the case – Pynchia Jun 22 '20 at 10:45
  • You can add `talk() { Foo.talk();}` if you really need `a.talk()` – Justin Ohms Apr 16 '22 at 22:32
12

I use namespaces:

var Foo = {
     element: document.getElementById("id-here"),

     Talk: function(message) {
            alert("talking..." + message);
     },

     ChangeElement: function() {
            this.element.style.color = "red";
     }
};

And to use it:

Foo.Talk("Testing");

Or

Foo.ChangeElement();
A-Sharabiani
  • 17,750
  • 17
  • 113
  • 128
7

ES6 supports now class & static keywords like a charm :

class Foo {
    constructor() {}

    talk() {
        console.log("i am not static");
    }

    static saying() {
        console.log(this.speech);
    }

    static get speech() {
        return "i am static method";
    }

}
Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254
  • I was looking for answer like this. Can static method call non-static methods/variables? – Tomasz Mularczyk Dec 12 '16 at 11:22
  • 1
    @Tomasz static methods won't have ´this´ set to any instance of the class, but rather the class itself. So of course, a static method *can* call an instance method, but only if it somehow has access to an instance, such as ´static staticMethod() { new Foo().talk(); }´ – JHH Jan 11 '18 at 09:54
4

If you have to write static methods in ES5 I found a great tutorial for that:

//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 ;)");  
};

see @https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/

Combine
  • 3,894
  • 2
  • 27
  • 30
4

Just additional notes. Using class ES6, When we create static methods..the Javacsript engine set the descriptor attribute a lil bit different from the old-school "static" method

function Car() {

}

Car.brand = function() {
  console.log('Honda');
}

console.log(
  Object.getOwnPropertyDescriptors(Car)
);

it sets internal attribute (descriptor property) for brand() to

..
brand: [object Object] {
    configurable: true,
    enumerable: true,
    value: ..
    writable: true

}
..

compared to

class Car2 {
   static brand() {
     console.log('Honda');
   }
}

console.log(
  Object.getOwnPropertyDescriptors(Car2)
);

that sets internal attribute for brand() to

..
brand: [object Object] {
    configurable: true,
    enumerable: false,
    value:..
    writable: true
  }

..

see that enumerable is set to false for static method in ES6.

it means you cant use the for-in loop to check the object

for (let prop in Car) {
  console.log(prop); // brand
}

for (let prop in Car2) {
  console.log(prop); // nothing here
}

static method in ES6 is treated like other's class private property (name, length, constructor) except that static method is still writable thus the descriptor writable is set to true { writable: true }. it also means that we can override it

Car2.brand = function() {
   console.log('Toyota');
};

console.log(
  Car2.brand() // is now changed to toyota
);
jsdev
  • 672
  • 6
  • 14
2

When you try to call Foo.talk, the JS tries to search a function talk through __proto__ and, of course, it can't be found.

Foo.__proto__ is Function.prototype.

Tunaki
  • 132,869
  • 46
  • 340
  • 423
2

Static method calls are made directly on the class and are not callable on instances of the class. Static methods are often used to create utility function

Pretty clear description

Taken Directly from mozilla.org

Foo needs to be bound to your class Then when you create a new instance you can call myNewInstance.foo() If you import your class you can call a static method

Dave Keane
  • 729
  • 8
  • 19
0

In your case, if you want to Foo.talk():

function Foo() {};
// But use Foo.talk would be inefficient
Foo.talk = function () {
    alert('hello~\n');
};

Foo.talk(); // 'hello~\n'

But it's an inefficient way to implement, using prototype is better.


Another way, My way is defined as static class:

var Foo = new function() {
  this.talk = function () {
    alert('hello~\n');
    };
};

Foo.talk(); // 'hello~\n'

Above static class doesn't need to use prototype because it will be only constructed once as static usage.

https://github.com/yidas/js-design-patterns/tree/master/class

Nick Tsai
  • 3,799
  • 33
  • 36
0

When i faced such a situation, i have done something like this:

Logger = {
    info: function (message, tag) {
        var fullMessage = '';        
        fullMessage = this._getFormatedMessage(message, tag);
        if (loggerEnabled) {
            console.log(fullMessage);
        }
    },
    warning: function (message, tag) {
        var fullMessage = '';
        fullMessage = this._getFormatedMessage(message, tag);
        if (loggerEnabled) {
            console.warn(fullMessage);`enter code here`
        }
    },
    _getFormatedMessage: function () {}
};

so now i can call the info method as Logger.info("my Msg", "Tag");

Vishnu
  • 1,516
  • 1
  • 10
  • 15
  • I do this all the time, but it's basically just namespacing. It doesn't allow you to create instances with instance vars? – dcsan Jun 14 '18 at 03:44
0

Javascript has no actual classes rather it uses a system of prototypal inheritance in which objects 'inherit' from other objects via their prototype chain. This is best explained via code itself:

function Foo() {};
// creates a new function object

Foo.prototype.talk = function () {
    console.log('hello~\n');
};
// put a new function (object) on the prototype (object) of the Foo function object

var a = new Foo;
// When foo is created using the new keyword it automatically has a reference 
// to the prototype property of the Foo function

// We can show this with the following code
console.log(Object.getPrototypeOf(a) === Foo.prototype); 

a.talk(); // 'hello~\n'
// When the talk method is invoked it will first look on the object a for the talk method,
// when this is not present it will look on the prototype of a (i.e. Foo.prototype)

// When you want to call
// Foo.talk();
// this will not work because you haven't put the talk() property on the Foo
// function object. Rather it is located on the prototype property of Foo.

// We could make it work like this:
Foo.sayhi = function () {
    console.log('hello there');
};

Foo.sayhi();
// This works now. However it will not be present on the prototype chain 
// of objects we create out of Foo
Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
0

There are tree ways methods and properties are implemented on function or class objects, and on they instances.

  1. On the class (or function) itself : Foo.method() or Foo.prop. Those are static methods or properties
  2. On its prototype : Foo.prototype.method() or Foo.prototype.prop. When created, the instances will inherit those object via the prototype witch is {method:function(){...}, prop:...}. So the foo object will receive, as prototype, a copy of the Foo.prototype object.
  3. On the instance itself : the method or property is added to the object itself. foo={method:function(){...}, prop:...}

The this keyword will represent and act differently according to the context. In a static method, it will represent the class itself (witch is after all an instance of Function : class Foo {} is quite equivalent to let Foo = new Function({})

With ECMAScript 2015, that seems well implemented today, it is clearer to see the difference between class (static) methods and properties, instance methods and properties and own methods ans properties. You can thus create three method or properties having the same name, but being different because they apply to different objects, the this keyword, in methods, will apply to, respectively, the class object itself and the instance object, by the prototype or by its own.

class Foo {
  constructor(){super();}
  
  static prop = "I am static" // see 1.
  static method(str) {alert("static method"+str+" :"+this.prop)} // see 1.
  
  prop="I am of an instance"; // see 2.
  method(str) {alert("instance method"+str+" : "+this.prop)} // see 2.
}

var foo= new Foo();
foo.prop = "I am of own";  // see 3.
foo.func = function(str){alert("own method" + str + this.prop)} // see 3.
FrViPofm
  • 345
  • 2
  • 10