0

I would like to better understand the scope chain the hopefully closure better and so the following code:

function greet(whattosay){

    return function(name) {
        whattosay = "not hi"; //change the hi message
        console.log(whattosay + ' ' + name);
        function insideAnon() {
            console.log(whattosay);
        }

    }


}
var sayHi = greet('Hi'); //get in return the anon function
sayHi("John"); //print not hi John on the console

I have recently learned that every "variable environment" is actually an array or an object with properties, and so each function has a reference to it's parent's function variable environment object/array. But my question is, what exactly is the scope chain?(I know that it is supposedly going "down" up until the global level), My current perception (Not sure) is that each child has it's parent and grandparent (and so on) variable environment references inside of it, and so it first check it's parent's variable environment object, if a variable is not there it looks at it's grandparent's reference and so on. Or is it more like - Check the parent variable environment object reference, if not there that parent checks his parent's reference and so on. I HOPE i was very clear at what I was trying to say - How it really goes down the "chain".

RunningFromShia
  • 590
  • 6
  • 20
  • 1
    Possible duplicate of [How do JavaScript closures work?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Olavi Sau Nov 02 '15 at 17:28
  • Sorry if it might seem to you alike(Even though not to me), my question focuses more on the scope chain than closures... – RunningFromShia Nov 02 '15 at 17:31
  • 1
    It always goes up. The innermost function sees everything, and the outermost function sees only the declarations declared in the outermost function. – Olavi Sau Nov 02 '15 at 17:34
  • I know that, I asked how it sees it; does it have a reference to each var environment object, and it searches in each one of them in an organized order, or is it more like a chain - one parent delivers the other information. – RunningFromShia Nov 02 '15 at 17:37
  • It searches each scope one by one.(the first match is used). – Olavi Sau Nov 02 '15 at 17:41

2 Answers2

0

You can get references about scope chains from this question:

Scope Chain in Javascript

Community
  • 1
  • 1
Charlie
  • 22,886
  • 11
  • 59
  • 90
0

Each function creates a scope object that contains the arguments for that function and the local variables defined in that function.

Since Javascript uses lexical scoping, that means that a given piece of code can access variables defined within the current function or within any parent function. Javascript makes this work by maintaining a chain of scope objects so each scope has a reference to its parent scope.

When a given piece of code accesses a variable like:

foo = 1;

Javascript, looks in the current scope object to see if something named foo exists there. If so, that variable is used. If not, it gets the reference to the parent scope, checks that scope for something named foo and continues this process up the parent chain until it gets to the global scope and thus can go no further.

So, in this example:

function one() {
    var foo = 2;

    function two() {
        var fee = 3;

        function three() {
            foo = 1;
        }
        three();
    }
    two();
}
one();

The function one() will execute and define foo and two in its scope. It will then call two() which will execute and define fee and three in its scope. It will then call three() which will execute and attempt to change the value of foo. It will first look in the scope object belonging to three, but it will not find anything named foo there so it will go to the parent scope of three which will be the two scope object. It will not find a variable named foo in that scope object so it will go to the parent object of two which will be the scope object of one. There it will find a variable named foo so it will change the value of that variable.


On thing that is different about Javascript scope objects compared to something like a C++ stack frame is that they can continue to live after the function that created them has finished executing. This is a very common structure in Javascript and is often referred to as a closure. Here's a simple example of that:

function initializeCntr() {
     var cntr = 0;
     document.getElementById("test").addEventListener("click", function(e) {
         ++cntr;
         document.getElementById("clickCnt").innerHTML = cntr;
     });
}

initializeCntr();

In this short code example, there are three scopes present, the global scope (that contains the initializeCntr symbol), the initializeCntr scope that contains the cntr variable and the scope that belongs to the anonymous function that is set as the event handler.

When you call initializeCntr(), it creates a function scope object that contains the variable cntr. It then runs the addEventListener() method and passes a reference to the inline anonymous event handler for addEventListener(). The initializeCntr() method then finishes execution. But, because the inline anonymous function passed as the event handler contains a reference to the cntr variable in the initializeCntr scope object, that scope object is NOT garbage collected even though initializeCntr() has finished executing. Instead, it is kept alive because of the lasting reference to the cntr variable in it. When that click event handler is then called sometime in the future, it can use that cntr variable. In fact, the initalizeCntr scope will be kept alive as long as the event handler is active. If the event handler is removed or the DOM object it is attached to is removed, then and only then would the initializeCntr scope object be eligible for garbage collection and eventually get freed.

Some JS implementations are smart enough to not necessarily retain the entire scope object and everything in it, but instead to only retain the elements of the scope object that are specifically referenced in child scopes that are still active. So, if there were other variables next to cntr that were not used in the event handler, those other variables could be freed.

FYI, this longer lasting scope is called a closure. Closures are very useful concepts in Javascript and something not available in a language like C++ (because they rely on garbage collection).

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • What do you mean "continue the process"? Let's say the parent scope didn't find it, does it return back to the child a reference to his parent's scope(therefore grandparent of the child) and then the child looks there? – RunningFromShia Nov 02 '15 at 17:41
  • @user2081462 - Each scope just contains its own symbols and a reference to the parent scope. Javascript ONLY searches up the parent chain. It never searches down. Child scoped symbols cannot be referenced from a parent. Parent scopes symbols can be referenced from a child because of the search UP the parent chain. See the scoping example I added to my answer. – jfriend00 Nov 02 '15 at 17:43
  • The final scope is the "container object" window for browser, if it doesn't find it there, it returns undefined. – Olavi Sau Nov 02 '15 at 17:43
  • @OlaviSau - The top level scope to be searched is the global scope. In a browser, that is the `window` object. In something like node.js, it is a specific `global` object. – jfriend00 Nov 02 '15 at 17:44
  • @jfriend00 Yeah, I think there was a definition for that "global object". Don't remember it right now. – Olavi Sau Nov 02 '15 at 17:46
  • So when a child looks at it's parent scope can't find the var it looks for there, javascript will just know how to keep looking up the chain? it will look at the paren't parent scope ref and so on until it finds a result(if not then return not defined)? – RunningFromShia Nov 02 '15 at 17:56
  • @user2081462 - yes, that's how it works. It searches each step up the parent chain starting with the current scope and working upwards. Be careful with the "returns undefined" part of what you said. Both `foo = 1;` in strict mode and `var x = foo` in any mode when `foo` is not defined anywhere will throw a reference error, not just give you `undefined`. – jfriend00 Nov 02 '15 at 19:45