20

With the release of ECMAScript 6 on June 2015, Javascript classes syntax was introduced.

This syntax:

class Polygon {
      constructor(width, height) {
        this.width = width;
        this.height = height;
      }
}

is basically same as:

function Polygon(width, height) {
    this.width = width;
    this.height = height;
}

So what is the benefit of using class instead of traditional function? And in what condition I should use class instead of function?

Edward Anthony
  • 3,354
  • 3
  • 25
  • 40
  • This is like, `var x = (someThing) ? 1 : 0` benefits over `var x; if(someThing){ x=1; }else{ x=0; }` May be readability. – Rajaprabhu Aravindasamy Mar 19 '16 at 08:51
  • 3
    This answer (while not an exact duplicate) explains the differences very well: http://stackoverflow.com/questions/30783217/why-should-i-use-es6-classes – CodingIntrigue Mar 19 '16 at 10:11
  • 5
    Whats wrong with stackoverflow, -5 for just asking normal question. I think that's enough, would learn that myself. Thanks for responders who tried to give explanation, I appreciate that. – Edward Anthony Mar 19 '16 at 11:10
  • 1
    The difference of Function and Class in JS is not opinion based. It is a real difference and clearly needs explanation. See the answer I posted for a more detailed explanation of the subject. – Tero Tolonen Mar 19 '16 at 13:14
  • 2
    Unfortunately some people clearly did not appreciate the answer I gave, but the question is still quite valid and quite important because there are some limitations in Class syntax - the most important in my opinion is lack of private scope for holding variables. – Tero Tolonen Mar 19 '16 at 14:18
  • 2
    Why is this question closed? The accepted answer provides some concrete differences between classes and functions, and I found it quite helpful. The question should not be closed. – TEK Sep 07 '17 at 01:14

2 Answers2

25

There are some differences between Class and Function - most people will start by saying that the Class is "just syntax sugar", but that sugar does matter quite a bit. When the JS parser is processing the JavaScript code the parser will save them in different AST nodes, like shown here the ClassDeclaration and ClassExpression are different node types in the resulting AST tree:

https://github.com/estree/estree/blob/master/es2015.md#classes

You can see that for this parser, the new ES6 Classes spec introduces a number of new AST elements to the syntax:

  • ClassBody
  • MethodDefinition
  • ClassDeclaration
  • ClassExpression
  • MetaProperty

Since the AST syntax is not standard, there can be more or less types depending on the parser, but what is important to notice that when the code enters the class declaration or class expression it will be interpreted differently by the JavaScript engine.

This means, that Class and Function declarations can not be exchanged. You can see this if you try to write

class notWorking {
  return 1;  // <-- creates a parser error
};

This is because when the parser encounters the class -keyword, it will start treating the following code as ClassBody of either ClassDeclaration or ClassExpression and then it expects to find MethodDefinitions.

This is a small problem, because creating private variables becomes a bit more challenging. The function declaration could define a private variable neatly like this:

function myClass() {
    var privateVar;
}

The class declaration can not have this:

class myClass {
    var privateVar; // ERROR: should be a method
}

This is because the syntax of class allows only methods to be declared inside the class body. At least right now.

However, there exists a proposal for creating private fields:

https://github.com/zenparsing/es-private-fields

Thus, in the future you might be able to say

class myClass {
   #privateVar; // maybe this works in the future?
}

There is a separate answer considering the private properties in ES6 Classes, which is suggesting some workarounds, like the use of Symbols:

Private properties in JavaScript ES6 classes

var property = Symbol(); // private property workaround example
class Something {
    constructor(){
        this[property] = "test";
    }
}

Naturally there are more differences between classes and functions. One of them is Hoisting 1 - unlike Functions, you can't declare the Class anywhere in the scope:

An important difference between function declarations and class declarations is that function declarations are hoisted and class declarations are not. You first need to declare your class and then access it

The Class declarations and Function declarations are quite similar;

function foo1() {} // can be used before declaration
class  foo2{}      // new foo2(); works only after this declaration

The class expressions work quite similarly to function expressions, for example they can be assigned to a variable:

var myClass = class foobar {};

More differences are 1

  1. The Class expression / declaration body is always executed in Strict mode - no need to specify that manually
  2. Classes have special keyword constructor - there can be only one of them, or error is thrown. Functions could have multiple definitions of variable of function named "constructor"
  3. Classes have special keyword super which relates to the parent classes constructor. If you are inside the constructor you can call super(x, y); to call the parent class constructor but inside the Method you can call super.foobar() to create call to any parent class function. This kind of functionality is not available for standard Functions although you might emulate it with some custom hacking.
  4. Inside class body you can define function with static keyword so it can be called using only ClassName.FunctionName() -syntax.
  5. Both class declarations and expressions can use extends keyword like class Dog extends Animal
  6. MethodDeclaration does not need function -prefix, thus you can define function "ok" inside the class "m" like this: class m { ok() { } }. Actually it is not even allowed to define function as class m { function ok() { } }

However, after the parser has completed it's job, the class instance is essentially running the same way as any other object.

The new ES6 Class syntax is essentially more clear way of expressing objects in a traditional OOP way and if you like it, then you should use it.

EDIT: also, the ES6 Class syntax has also another limitation: it does not allow the member functions to use lexically binded using fat arrow. ES7 seems to have experimental feature allowing it. That can be useful for example when binding methods to event handlers, the related question is here.

1 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

Hasta Dhana
  • 4,699
  • 7
  • 17
  • 26
Tero Tolonen
  • 4,144
  • 4
  • 27
  • 32
  • I also added a notice about the missing fat-arrow syntax for the ES6 Class declaration. – Tero Tolonen Mar 19 '16 at 16:26
  • @TeroTolonen: That's hardly a "feature" that would distinguish classes from functions. You can use arrow functions fine inside the constructor and not on the prototype. – Bergi Mar 19 '16 at 16:34
  • @Bergi: I mean like this: class a { n = (val) => { } } – Tero Tolonen Mar 19 '16 at 16:38
  • @TeroTolonen: What's that supposed to be? That's obviously a syntax error, like `function n = (val) => {}` would be. You need to use `class a { constructor() { this.n=val=>{…}; } }` - the same as you'd do in a constructor created using the `function` keyword. – Bergi Mar 19 '16 at 16:40
  • (new a()).n() works in babel repl fine, but that's exprerimental still, like explained in the text and other answers – Tero Tolonen Mar 19 '16 at 16:43
  • @Bergi and also, if you try to use super.n() in a subclass there might be problems if you declare the function by assigning it to this in the traditional way – Tero Tolonen Mar 19 '16 at 16:56
  • @TeroTolonen: If you refer to the experimental class values proposal, where this kind of syntax already works, that's nothing but syntactical sugar for the code I've given. Binding arrow functions to instances always only works in methods (including `.constructor`), and the `super` problems are the same. – Bergi Mar 19 '16 at 16:59
  • @Bergi You are now mixing things, it is different to declare a class and modify instance at runtime – Tero Tolonen Mar 19 '16 at 17:01
  • @TeroTolonen: Your syntax `class a { n = (val) => { } }` (from the ES8 proposal) *is* creating those properties only during the instantiation. – Bergi Mar 19 '16 at 17:03
  • @Bergi yes, that is true, but the purpose of the ES8 proposal is to make possible to declare those properties "because there is no clear distinction between initialization logic and the intended shape of the class." like stated in the proposal – Tero Tolonen Mar 19 '16 at 17:23
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/106834/discussion-between-tero-tolonen-and-bergi). – Tero Tolonen Mar 20 '16 at 09:28
0

class its nothing but a syntactical sugar over javascript logic class creation using function. if you are using a function as class the entire function is act as a constructor, if you want to put other member functions you need to do that in constructor like this.something = ..., or var something = ... in case of private members (if you are not injecting from outside, assume you are creating object with other methods / properties), but in case of class the entire function is not actually act a constructor you can explicitly separate it with other member functions and data.

Koushik Chatterjee
  • 4,106
  • 3
  • 18
  • 32