Tân
Tân

Reputation: 1

How to classify class, function and function property in javascript?

I've 3 objects like these:

class Person {
    constructor(name, age) {
        this._name = name;
        this._age = age;
    }
}

let Add = function (a, b) {
    return a + b
};

let Math = {
    multiply: function (x, y) {
        return x * y
    }
};

As you can see, Person is a class, Add and Math.multiply are functions.

My question: How to classify class and functions in this case?

My question comes from: Person looks like a function, like this:

let Person = function (name, age) {
    this._name = name;
    this._age = age;
};

Also, there are no problems if I declare an object to get new instance of Add function:

let result = new Add(2, 3); // this is allowed although it just needn't

new operator says:

The new operator creates an instance of a user-defined object type or of one of the built-in object types that has a constructor function.

All of 3 cases, Person, Add and Math.multiply are constructors. So:

let person = new Person('Hermione', 18); // allowed
let result = new Add(2, 3); // allowed
result = new Math.multiply(2, 2); // allowed

Then, because all of them are constructors, it's so difficult to classify class and function (for me).

Is there a way to achieve that?

Upvotes: 3

Views: 460

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074595

I think your question stems from quite understandable confusion: Despite the class syntax, JavaScript doesn't have classes as distinct from functions like some class-based OOP languages do (Java, C#, C++). class syntax creates a function and associated properties on the object referenced by that function's prototype property. It's not a separate thing. See below the bar for more.

Further, JavaScript didn't originally make any distinction between normal functions and constructor functions; it was purely a matter of how you used used them (e.g., via new or calling them directly). As of ES2015 which introduced both class syntax and arrow functions, the language is moving toward distinguishing different kinds of functions (the ones created via class will throw an error if you call them without new; arrow functions will throw an error if you do call them via new).

If your goal is to look at Person in code and know whether it was created with class or function without calling it, the only way to do that is to convert it to a string and look at the result. The specification requires that Function.prototype.toString return a string that...

...must have the syntax of a FunctionDeclaration, FunctionExpression, GeneratorDeclaration, GeneratorExpression, ClassDeclaration, ClassExpression, ArrowFunction, MethodDefinition, or GeneratorMethod depending upon the actual characteristics of the object.

So for instance, if I've used class Foo { }, then Foo.toString() has to return a class declaration or expression, whereas if I've used function Foo { } instead, it must return a function declaration or expression. So you could work it out with a regular expression.

In a comment you've asked zerkms

But in javascript I can use Add and Math.multiply as classes. Is it better if I can use a function like a class? No, it isn't.

It completely depends on how Add and X.multiply (I really wouldn't shadow the built-in Math object) are defined: It may well make sense to call them via new. It's not uncommon for an object property to be a reference to a constructor function:

let Nifty = {
    Stuff: class {
        constructor(name) {
            this.name = name;
        }
    }
};
let x = new Nifty.Stuff("Coolness");
console.log(x.name); // "Coolness"

or

// Better not to do this, but it's allowed
let Nifty = {
    Stuff: function(name) {
        this.name = name;
    }
};
let x = new Nifty.Stuff("Coolness");
console.log(x.name); // "Coolness"

Re class creating functions: That's literally what it does:

class Foo {
}
console.log(typeof Foo); // "function"

In fact, this:

class Foo {
}

roughly translates to

let Foo = function() {
    if (!(this instanceof Foo)) { // This check isn't quite right, but it's close
        throw new TypeError("Class constructor Foo cannot be invoked without 'new'");
    }
};

and

class Foo {
    constructor(name) {
        this.name = name;
    }
    sayHello() {
        console.log(`Hi, my name is ${name}!`);
    }
}

roughly translates to

let Foo = function(name) {
    if (!(this instanceof Foo)) { // This check isn't quite right, but it's close
        throw new TypeError("Class constructor Foo cannot be invoked without 'new'");
    }
    this.name = name;
};

Foo.prototype.sayHello = function sayHello() {
        console.log("Hi, my name is " + name + "!");
    }
};

Upvotes: 8

Related Questions