19

I'm trying to figure out if there's any different when defining functions inside or outside of a class in JavaScript. Why would I choose to do it one way over the other? (Notice my getName [inside class] and getName2 [outside of class]).

class TestClass {
    constructor(myName) {
        this.name = myName;
    }

    getName() {
        return this.name;
    }
}

TestClass.getName2 = function() {
    //won't actually print the name variable set since not associated with an instance of the class?
    console.log(this.name);
};

var test = new TestClass("Joe");

console.log(test.getName());

///////////////

TestClass.getName2();

Output:

Joe
TestClass

The only difference I can really see so far through my testing here is that I cannot access this.name within my getName2 since I believe it's not associated with any instance of the TestClass. So my getName2 is almost like a static class function where it's not associated with an instance of the class?? Please help me clarify this and why I would choose to implement a function one way over the other.

Birdman
  • 1,404
  • 5
  • 22
  • 49

3 Answers3

23

From the MDN doc:

JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript.

So this...

class TestClass {
  constructor(myName) {
    this.name = myName;
  }

  getName() {
    return this.name;
  }

  static getName2() {
    return 'getName2 result';
  }
}

...is exactly equivalent to this:

const TestClass = function(myName) {
  this.name = myName;
}

TestClass.prototype.getName = function() {
  return this.name;
}

TestClass.getName2 = function() {
  return 'getName2 result';
}

So whether you use the older prototype syntax or the newer ES6 class syntax is just a matter of personal preference, and as you suspected, defining methods directly on a class is exactly equivalent to creating a static class method.

Brian Adams
  • 43,011
  • 9
  • 113
  • 111
0

I don't think there's any reason you would ever do

TestClass.getName2 = function() {

If you want a standalone function, make it a standalone function.

e.g.

export function getName2() {...};
export TestClass;

If you want to extend an existing class, you'd do

TestClass.prototype.getName2 = function() {

which will allow you to access this.

jeznag
  • 4,183
  • 7
  • 35
  • 53
  • 1
    The reason to do ... is: *Scope*. `getName2 =` creates a variable in the scope that it is within. `TestClass.getName2 = ` creates a variable that is scoped by `TestClass.`. As much as possible, it is good to restrict variables to the appropriate context. This minimizes "namespace pollution". And signals that `getName2` is probably accessing or setting values that have to do with TestClass, but are not part of a single TestClass instance. Perhaps "configuration settings" that should influence all TestClass instances. – ToolmakerSteve Nov 01 '19 at 13:12
0

One thing that I noticed is you are using a reserved keyword for objects, properties, and methods. TestClass.getName2() should return undefined, but since you used the "name" reserve keyword. It returned the name of the class, which is considered an object like a function. In your case, you are using this.name which refers to the class name and it returns "TestClass".

Example:

class TestClass {
    constructor(userName) {
        this._userName = userName;
    }

    getName() {
        return this._userName;
    }
}

TestClass.getName2 = function() {
    // returns undefined now
    console.log(this._userName);
};

var test = new TestClass("Joe");

console.log(test.getName()); // returns Joe

///////////////

TestClass.getName2(); // returns undefined
let testClassName = TestClass.name; // Just a little proof of what is returned below
console.log(testClassName); // returns TestClass

My only suggestion is that you should stay abreast of the current reserved keywords and where you can and cannot use them. You could also focus on your naming convention in your code.

Elugens
  • 12
  • 2