Acidic
Acidic

Reputation: 6282

Function expressions on global scope

After discovering TypeScript I've played around with the online compiler and the resulting JavaScript code made me wonder about function expressions.

A simple TypeScript class:

class Person {
    firstName: String = "John";
    lastName: String = "Doe";
}

Results in the following JavaScript code:

var Person = (function () {
    function Person() {
        this.firstName = "John";
        this.lastName = "Doe";
    }
    return Person;
})();

That made me wonder why they chose to go with self-executing function, when something simpler might have sufficed. What is the purpose of an inner function with a name identical to the variable?
And why didn't they go with something simpler, such as:

var Person = function() {
    this.firstName = "John";
    this.lastName = "Doe";
};

Or even:

function Person() {
    this.firstName = "John";
    this.lastName = "Doe";
}


As far as I can tell using function expressions on a global scope offers no advantages, only the disadvantage of not being able to call the function before it was declared.

Upvotes: 0

Views: 129

Answers (3)

basarat
basarat

Reputation: 276259

It helps with inheritance. It allows them to capture the base class with a rename to _super which helps with code generation e.g.:

class Foo{

}

class Bar extends Foo{

}

becomes :

var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
var Foo = (function () {
    function Foo() {
    }
    return Foo;
})();

var Bar = (function (_super) {
    __extends(Bar, _super);
    function Bar() {
        _super.apply(this, arguments);
    }
    return Bar;
})(Foo); // Notice base class is captured here

This is good practice in JS as well. For example, if you kept using Foo in this example instead of _super and you were to change the base class you would have a whole avenue of headaches which can be avoided.

Upvotes: 2

Ryan Cavanaugh
Ryan Cavanaugh

Reputation: 220944

You really don't want to be able to invoke a class before its declaration has executed. Consider this code:

class Person {
    static nameSeparator = ' ';

    public fullName: string;

    constructor(public firstName, public lastName) {
        this.fullName = firstName + Person.nameSeparator + lastName;
    }
}

And its generated form:

var Person = (function () {
    function Person(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.fullName = firstName + Person.nameSeparator + lastName;
    }
    Person.nameSeparator = ' '; // <-- Important!
    return Person;
})();

Do you want code that accidently runs before the indicated line to run with undefined behavior (in this case, Person.fullName is "JohnundefinedSmith"), or just fail?

In other cases, the class simply won't work at all:

class Person {
    constructor(public firstName, public lastName) {
        // Will fail until Person.prototype.getFullName gets set
        console.log('New person, name = ' + this.getFullName());
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

Upvotes: 1

qwertynl
qwertynl

Reputation: 3933

This allows for you to make some private variables.

In JS:

var Person = (function () {
    var firstName, lastName; //static private vars
    function Person(fName, lName) {
        firstName = fName;
        lastName = lName;
    }
    return Person;
})();

Upvotes: -1

Related Questions