Area 73 Blog

this is a description of my new blog created with Gatsbyjs


    Blog Post
    patterns/testing-prototype-inheritance / lexical-and-dynamic-scope

    Extracted from a Gist, a very nice explanation

    // It is important to declare your variables.
    
    (function() {
        var foo = 'Hello, world!';
        print(foo);  //=> Hello, world!
    })();
    print(foo);  // No way José !!
    
    // Because if you don't, the become global variables.
    
    (function() {
        foo = 'Hello, world!';
        print(foo)  //=> Hello, world!
    })();
    
    print(foo)  //=> WTF, it returns "Hello, world!"
    
    
    // When global variables sneak into your code they can cause problems.
    // Especially in applications with concurrency.
    
    var count = function() {
        for (i = 0; i < 10; i += 1) {
            print(i);
        }
    };
    
    count();  //=> 0 1 2 3 4 5 6 7 8 9
    
    var countSilently = function() {
        for (i = 0; i < 10; i += 1) {
            // don't print anything;
        }
    };
    
    // Both loops increment i at the same time, which causes strange behavior.
    window.setTimeout(countSilently, 10);
    window.setTimeout(count,         10);  //=> 2 3 7 8 9
    
    
    // You can use 'this' in method definitions to refer to attributes of the
    // method's object.
    
    var obj = {
        name: 'foo',
        introduce: function() {
            print(this.name);
        }
    };
    
    obj.introduce();  //=> foo
    
    // But 'this' does not follow the normal rules of scope in JavaScript. One
    // might expect 'this' to be available with the same value via closure in the
    // callback defined inside the method here.
    
    var obj = {
        name: 'foo',
        introduce: function() {
            window.setTimeout(function() {
                print(this.name);
            }, 3000);
        }
    };
    
    obj.introduce(); //=> *pause* undefined
    
    // In fact, this got bound to the global object in the callback. To get around
    // this, assign the object reference to a regular variable that will have the
    // same value inside the callback definition.
    
    var obj = {
        name: 'foo',
        introduce: function() {
            var that = this;
            window.setTimeout(function() {
                print(that.name);
            }, 3000);
        }
    };
    
    obj.introduce();  //=> *pause* foo
    
    
    // The keyword 'this' is actually dynamically assigned whenever a function is
    // invoked. When a function is invoked as a method, i.e. obj.method(), 'this'
    // is bound to 'obj'. But when a function is invoked by itself 'this' is bound
    // to the global object.
    
    var phrase = 'Hello, world!';
    var printPhrase() {
        print(this.phrase);
    }
    
    printPhrase();  //=> Hello, world!
    
    // This is true even of functions that were defined as a method.
    
    var obj = {
        name: 'foo',
        introduce: function() {
            print(this.name);
        }
    };
    
    // When the function is invoked without 'obj.' in front of it, 'this' becomes
    // the global namespace.
    
    var introduce = obj.introduce;
    introduce();  //=> undefined
    
    
    // Method invocation and function invocation are two of the invocation patterns
    // in JavaScript. A third is apply invocation, which gives us control over what
    // 'this' will be assigned to during function execution.
    
    introduce.apply(obj, null);  //=> foo
    
    // 'apply' is a method on Function. The first argument is the value that 'this'
    // will be bound to. Successive arguments to apply are passed as arguments to
    // the function that is being invoked.
    
    var chatty = function(repeatTimes) {
        var i;
        for (i = 0; i < repeatTimes; i += 1) {
            print(this.name + ' ');
        }
    }
    chatty.apply(obj, 3)  //=> foo foo foo
    
    
    // The fourth and final invocation pattern in JavaScript is constructor
    // invocation. This pattern was designed to provide a way to create new objects
    // that would appear familiar to programmers who are used to programming with
    // classes.
    
    var Cat = function(name) {
        this.name = name;
    };
    Cat.prototype = {
        query: function() {
            print(this.name + ' says, "meow"');
        }
    };
    
    // When a function is called with the 'new' keyword in front of it, a new
    // object is created and is bound to 'this' when the function runs. Special
    // constructor functions use this feature to customize new objects as they are
    // created.
    
    var whiskers = new Cat('whiskers');
    whiskers.query();  //=> whiskers says "meow"
    
    // When a new object is created with 'new', the prototype of the new object is
    // set to the prototype of the constructor function. So the new object inherits
    // all of the attributes of the constructor's prototype value. In this case,
    // new cat objects inherit the 'query' method from Cat.prototype.
    
    var nibbler = new Cat('nibbler');
    nibbler.query();  //=> nibbler says "meow"
    
    
    // If a constructor function is called without the 'new' keyword, it is invoked
    // with the ordinary function invocation pattern.
    
    var gotcha = Cat('gotcha!');
    gotcha.query();  //=> typein:165: TypeError: gotcha has no properties
    
    // So 'this' is assigned to the global object instead of to a newly created object. That means that any attributes assigned to the new object by the constructor function become global variables!
    
    print(name);  //=> gotcha!
    
    
    // Constructor invocation is pretty complicated and prone to disastrous global
    // variable creation. Here is a cleaner way to create new objects that inherit
    // from other objects.
    
    // This defines Object.create, a method that simplifies the behavior of the
    // 'new' keyword. This method was invented by Douglas Crockford.
    // http://javascript.crockford.com/prototypal.html
    if (typeof Object.create !== 'function') {
        Object.create = function(o) {
            var F = function() {};
            F.prototype = o;
            return new F();
        };
    }
    
    // Object.create(obj) returns a new object that inherits all of the attributes
    // of obj. The 'cat' prototype object here defines a 'clone' method that wraps
    // around Object.create to customize new 'cat' objects as they are created.
    
    var cat = {
        query: function() {
            print(this.name + ' says "meow"');
        },
        clone: function(name) {
            var newCat = Object.create(this);
            newCat.name = name;
            return newCat;
        }
    };
    
    var fluffy = cat.clone('fluffy');
    fluffy.query();  //=> fluffy says "meow"
    
    // In addition to inheriting 'query', new cats also inherit 'clone'.
    
    var fluffy2 = fluffy.clone('fluffy2');
    fluffy2.query();  //=> fluffy2 says "meow"
    
    // Methods and attributes are inherited, not copied. If you change the
    // definition of 'clone' on 'cat' at this point, the change will be reflected
    // in cat objects that have already been created.
    
    fluffy2.hasOwnProperty('clone')  //=> false
    fluffy.hasOwnProperty('clone')  //=> false
    cat.hasOwnProperty('clone')  //=> true

    Bibliography:
    https://gist.github.com/hallettj/64478