Search code examples
javascriptprototype-programming

Function variable added to global scope


I declared the function:

function makePerson() {
    this.first = 'John';
    this.last = 'Oliver';
    fullName = function(){
        return this.first + this.last;
    }
}

Did not instantiate it but called this function.

makePerson()

Now I am able to access first, last and fullName in global access.

Can someone explain me why it happens.

Note: Rather than calling, I instantiated it and checked. It is not in global and is accessible within function/class/object scope.


Solution

  • These are the normal semantics of the this keyword in a function. this may be evaluated in several ways, depending on how you call the function. Let's say we have the function f which body contains the this keyword :

    1. In f(a,b) (standard function call syntax) this is bound to the global JavaScript Object, which means that if you add properties to this in the function body, you actually add them to global scope.
    2. In anObject.f(a,b) (method call syntax), this is bound to anObject.
    3. In new f(a,b) (constructor call syntax), this is bound to the object being constructed.

    this can be a source of confusion, and as soon as a function body contains this, the function stops being first-class. For that reason, I recommend you to avoid using this as much as you can, as does Douglas Crockford.

    If you want to make a factory function (which I strongly recommend for the reason above), you may do it that way :

    function makePerson() {
        var person = {
            first: 'John',
            last: 'Oliver'
        };
        person.fullName = function(){
            return person.first + person.last;
        };
        return person;
    }
    

    If you still want to make a constructor, convention dictates that the name be capitalized :

    function Person() {
        this.first = 'John';
        this.last = 'Oliver';
        this.fullName = function(){
            return this.first + this.last;
        };
    }
    

    Finally, there can be good reasons to use the this keyword, and that is prototypical inheritance. However, I find the constructor syntax to be misleading in that regard. Fortunately, now we have Object.create:

    var personPrototype = {
        fullName: function () {
            return this.first + this.last;
        }
    };
    function makePerson(first,last) {
        var person = Object.create(personPrototype);
        person.first = first;
        person.last = last;
        return person;
    }
    

    As a last warning, here is an example of how using this can lead to unanticipated constraints and confusion :

    var cn = makePerson("Chuck","Norris");
    // works fine
    console.log(cn.fullName());
    // does not work, fullName is not a first-class function. You cannot detach it.
    var fullName = cn.fullName;
    console.log(fullName());