4

Both classes and constructors can be used to create objects. The typeof for both of them is function. So, when should I use a class and when a constructor?

user3885927
  • 3,363
  • 2
  • 22
  • 42
marco
  • 1,152
  • 1
  • 9
  • 20
  • 4
    There isn't really such a thing as a `class` in Javascript, classes are really just syntax sugar. You would use classes if you like how classes look & feel, you would use functional protototype if you like that. It's basically choice. – Keith Oct 18 '17 at 22:21
  • 1
    @Keith yes there are now classes https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes – charlietfl Oct 18 '17 at 22:23
  • 4
    @charlietfl You've not really understood what I've said.. note the `syntax sugar`, and is the reason why in both cases `typeof` returns `function`.. I've been using classes for a while now, I know the syntax exists, but it's just a fancy wrapper around normal functional prototype. – Keith Oct 18 '17 at 22:27
  • @Keith but taken the statement literally , and semantics aside, it is incorrect since there are classes. The fact they are wrappers isn't really relevant to the question and is more likely to confuse than help – charlietfl Oct 18 '17 at 22:30
  • 3
    @charlietfl It's totally relevant, as the OP wanted to know why in both cases typeof returns function. I've now answered that question!!.. Do you have a better answer for why both return `function`? – Keith Oct 18 '17 at 22:32

2 Answers2

4

A class is a constructor technically. Any object with a [[ Construct ]] internal method is considered one. All constructors are functions, but not all functions are constructors.

Functions in Javascript can be of many kinds. We have normal functions, arrow functions, class, methods, async functions, async arrow functions, generators, async generators and possibly in the future generator arrow functions.

Out of all these functions, the only ones who can construct something are class and normal functions. None other of these have a [[ Construct ]] internal method.

There are some semantic differences between normal functions and classes as constructors and as callable functions:

  • Only classes have derived constructors (which have a slightly different construction model).
  • Classes can't be called, only instantiated through new.
  • Classes have a super binding (which part of it is related to 1).
  • The prototype of the class (not the prototype property) is the super constructor when there's an extends clause.
  • The prototype property is not writable in classes, it is writable for normal functions.

Some other things that might be different from class but can be done with normal functions:

  • class code is strict mode by default.
  • class uses methods in their prototype. For normal functions as constructors they are typically also regular functions. This mean you can't construct new objects from class methods.
  • class methods in the prototype are not enumerable. For normal functions as constructors they are typically defined with = and those make the properties enumerable.

Other relevant information:

  • Classes are not instantiated until they reach the class declaration/expression. Top level function declarations are initialized right at the start of the function call and are accessible through out the whole scope.
  • constructor(){ } in class is the only method definition that actually evaluates to a constructor. Methods are not constructors.
MinusFour
  • 13,913
  • 3
  • 30
  • 39
2

What @Keith said is quite true, and it is, for some odd reason, very hard for JS new-comers to grasp, consider this code:

Old School

With the old school way, things get syntactically messy:

function _Thing() {}

function _Person(name, age, from) {
    this.name = name;
    this.age = age;
    this.from = from;
}

_Person.prototype = Object.create(_Thing.prototype);
_Person.prototype.constructor = _Person;//so easy to mess this up!

_Person.prototype.makeOlder = function () {
    this.age++;
};
_Person.prototype.toString = function () {
    return this.name;
};
_Person.FLORIDA = 1;
_Person.NEW_YORK = 2;


var _p = new _Person('rafael cepeda', 23, _Person.FLORIDA);
console.log(_p, _p instanceof _Person, _p instanceof _Thing);//_Person { name: 'rafael cepeda', age: 23, from: 1 } true true

New School

The ES6 way provides a very intuitive feeling for OOP programmers:

class Thing {}

class Person extends Thing {
    constructor(name, age, from) {
        super();
        this.name = name;
        this.age = age;
        this.from = from;
    }

    makeOlder() {
        this.age++;
    }

    toString() {
        return this.name;
    }

    static get FLORIDA() { return 1; }
    static get NEW_YORK() { return 2; }
}

var p = new Person('rafael cepeda', 23, Person.FLORIDA);
console.log(p, p instanceof Person, p instanceof Thing);//Person { name: 'rafael cepeda', age: 23, from: 1 } true true

Notice the parallels between the ES6 style constructor and the old school constructor, take a look at the prototype method definitions; with the new way, you don't even have to write the word prototype (which scares js new-comers).

Because they are essentially the same thing, it is correctly coined syntactic sugar. After inspection of both constructors, it should be no surprise why both typeof's return function.

Rafael
  • 7,605
  • 13
  • 31
  • 46