Chris
Chris

Reputation: 14218

JS call static method from class

I have a class with a static method:

class User {
  constructor() {
    User.staticMethod();
  }

  static staticMethod() {}
}

Is there an equivalent to this for static methods (i.e. refer to the current class without an instance)?

this.staticMethod()

So I don't have to write the class name: "User".

Upvotes: 49

Views: 71259

Answers (7)

Rohith K P
Rohith K P

Reputation: 3551

From MDN documentation

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 functions.

For more please see=> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static

You can do something like this => this.constructor.staticMethod(); to call static method.

class StaticMethodCall {
  constructor() {
    console.log(StaticMethodCall.staticMethod()); 
    // 'static method has been called.' 

    console.log(this.constructor.staticMethod()); 
    // 'static method has been called.' 
  }

  static staticMethod() {
    return 'static method has been called.';
  }
}

Upvotes: 85

Santhosh Kumar
Santhosh Kumar

Reputation: 91

Instead of: User.staticMethod() you can use: this.constructor.staticMethod()

Upvotes: 7

mgoetz
mgoetz

Reputation: 129

@Rohith K P 's answer is the solution in short.

If you want to understand it, you need to understand what JavaScript classes are “under the hood".

This is how you would create a class prior to ES6:

// This is a constructor function that initializes new Range objects. 
// Note that it does not create or return the object. It just initializes this. 
function Range(from, to) { 
    // Store the start and end points (state) of this new range object.
    // These are noninherited properties that are unique to this object. 
    this.from = from; 
    this.to = to; 
} 

// All Range objects inherit from this object. 
// Note that the property name must be "prototype" for this to work. 
// Note that the prototype property is the property of the Range function
Range.prototype = { 
    // create some methods

    // Return true if x is in the range, false otherwise 
    // This method works for textual and Date ranges as well as numeric. 
    includes: function(x) { return this.from <= x && x <= this.to; },

    // A generator function that makes instances of the class iterable. 
    // Note that it only works for numeric ranges. 
    [Symbol.iterator]: function*() { 
        for( let x = Math.ceil( this.from); x <= this.to; x ++) yield x; 
    }, 

    // Return a string representation of the range 
    toString: function() { return "(" + this.from + "..." + this.to + ")"; } 
}; 

// Here are example uses of this new Range class 
let r = new Range(1,3); 
// r inherits from Range.prototype
r.includes(2) // = > true: 2 is in the range 
r.toString() // = > "(1...3)" 
[...r] // => [1, 2, 3]; convert to an array via iterator

Image of inheritance strructure in this case

So, a class is essentially a function, which is a public interface (constructor) of its prototype object.

let F = function() {}; // This is a function object.
let p = F.prototype; // This is the prototype object associated with F. 
let c = p.constructor; // This is the function associated with the prototype. 
c === F // true

It is important to understand that the class defined in this Example works in exactly the same way as ES6 classes. The introduction of the "class" keyword to the language does not alter the fundamental nature of JavaScript’s prototype-based classes.

Static methods

Static methods are defined as properties of the constructor function rather than properties of the prototype object.

static parse(s) { 
    let matches = s.match(/^\((\d+)\.\.\.(\d+)\)$/); 
    if (!matches) { 
        throw new TypeError(`Cannot parse Range from "${s}".`) 
    } 
    return new Range(parseInt(matches[1]), parseInt(matches[2])); 
}

The method defined by this code is Range.parse(), not Range.prototype.parse(), and you must invoke it through the constructor, not through an instance:

let r = Range.parse('(1...10)'); // Returns a new Range object 
r.parse('(1...10)'); // TypeError: r.parse is not a function 

You’ll sometimes see static methods called class methods because they are invoked using the name of the class/ constructor. When this term is used, it is to contrast class methods with the regular instance methods that are invoked on instances of the class. Because static methods are invoked on the constructor rather than on any particular instance, it almost never makes sense to use the this keyword in a static method.

Source: Flanagan, David. JavaScript: The Definitive Guide.

Upvotes: 4

Leander
Leander

Reputation: 713

I just came across a similar issue (referencing super static methods), leaving an answer here in case someone else finds it useful.

In essence, the solution is passing the class itself into the static method. For example:

class Foo {
  static greet(Type) {
    return `Hello, ${Type.name()}`
  }
  static name() {
    return 'foo'
  }
}
class Bar extends Foo {
  static name() {
    return 'bar'
  }
}

Now you can call

Bar.greet(Bar) // returns 'Hello, bar'

Upvotes: 1

Rafiq
Rafiq

Reputation: 11465

static members of a class in javascript are added as class properties, you can see the list by using code

        console.log(Object.getOwnPropertyNames(PaymentStrategy));

and for accessing the member just

const memberFun = PaymentStrategy["memberName"];
//if member is a function then execute 
memberFun();
 //or 
memberFun(data);

example:

class PaymentStrategy{

    static Card(user){
        console.log(`${user} will pay with a credit card`);
    }

    static PayPal(user){
        console.log(`${user} will pay through paypal`);

    }

    static BKash(user){
        console.log(`${user} will pay through Bkash`);
    }
}

export default PaymentStrategy;

import PaymentStrategy from "./PaymentStrategy";
class Payment{
    constructor(strategy = "BKash"){
        this.strategy = PaymentStrategy[strategy];
        console.log(Object.getOwnPropertyNames(PaymentStrategy));
    }

    changeStrategy(newStratgey){
        this.strategy = PaymentStrategy[newStratgey];

        console.log(`***Payment Strategy Changed***`);
    }

    showPaymentMethod(user){
        this.strategy(user);
    }
}

export default Payment;
```
```
import Payment from "./Payment"


const strategyPattern = (()=>{
    const execute = ()=>{
        const paymentMethod = new Payment();

        paymentMethod.showPaymentMethod("Suru");
        paymentMethod.showPaymentMethod("Nora");

        paymentMethod.changeStrategy("PayPal");

        paymentMethod.showPaymentMethod("Rafiq");
    }
    return{
        execute:execute
    }
})();

export {strategyPattern}
```

Upvotes: 2

Chris C.
Chris C.

Reputation: 139

In @Ninjaneer 's accepted answer:

class StaticMethodCall {   constructor() {
    console.log(StaticMethodCall.staticMethod()); 
    // 'static method has been called.' 

    console.log(this.constructor.staticMethod()); 
    // 'static method has been called.'    }

  static staticMethod() {
    return 'static method has been called.';   } }

this.constructor.staticMethod() will throw an error because you must call the super constructor before accessing this in the constructor.

Assuming you fix this aforementioned issue, no pun intended, I think the only benefit of calling this.constructor.staticMethod() is that you're not dependent on the name of the class -- if it ever changes. However, this benefit is probably insignificant since it only benefits static method calls made from inside the class. Static method calls made externally would have to be something like StaticMethodCall.constructor.staticMethod() which is defeats the purpose and looks silly.

In Summary:

If you plan on using the static method outside of the class, I'd definitely stick with using StaticMethodCall.staticMethod() since it's more idiomatic and concise.

If you only plan on using the static method within the class, then maybe it's ok to to use this.constructor.staticMethod(), but it'll probably confuse other developers and lead them back to this page :-)

Upvotes: 0

Suresh Atta
Suresh Atta

Reputation: 121998

static things bind to class rather than instance. So you must at least specify the class name.

If you don't want to bind to them to a class make them global.

Upvotes: 1

Related Questions