JS Shorthand - Scope 2

It is intuitive to think that JavaScript code is executed line by line from top to bottom, but this is not entirely true.

console.log(a);//ReferenceError

 

a = 2 ;
var a;
console.log( a );//2

 

console.log( a );//undefined
var a = 2;

The right way to think about it is that all declarations, including variables and functions, are processed first before any code is executed .

When you see var a = 2;, you might think it's a statement. But JavaScript actually sees it as two declarations: var a; and a = 2;.

The first definition declaration is made during the compilation phase (that is, the variable declaration is applied to the corresponding scope).

The second assignment statement is left in place for the execution phase.

This process is as if variable and function declarations are "moved" to the top from where they appear in the code, and this process is called hoisting .

Another example is the following code, var foo is promoted, and when foo() is executed, foo is still undefined, and calling a function on undefined is naturally a TyepError.

foo(); // not ReferenceError, but TypeError! 
var foo = function bar() {
     // ... 
};
bar(); // ReferenceError, since bar is a named function expression, the bar identifier is only declared inside the function, which is actually equivalent to function(){var bar = ...self...}

Both variable declarations and function declarations are hoisted, and function declarations are hoisted before variable declarations:

foo(); // 1 
var foo; // Although it is declared before the foo function, the foo function is promoted first. When the compiler declares the foo variable, it finds that there is already a foo declared in the scope, so the variable foo will be ignored declaration, which is nice to avoid inadvertently overriding function declarations. 
function foo(){console.log(1 );}
bar(); // TypeError, note that only function declarations are promoted first, not function expressions. 
var bar = function (){ // ...}

 

Closure

Closures in js are ubiquitous, closures are a natural consequence of writing code based on lexical scope .

A closure is that when a function leaves the scope in which it was declared, the function still has access to the original parent's scope, as if the function was wrapped by the original parent's scope.

Take a look at this classic loop example to explain closures:

for (var i=1; i<=5; i++) {
    setTimeout( function timer() {
        console.log( i );//5个6
    }, i*1000 );
}

Solution one:

for (var i=1; i<=5; i++) {
    ( function () {
         var j = i;
        setTimeout( function timer() {
            console.log( j );
        }, j*1000 );
    })();
}
or
for (var i=1; i<=5; i++) {
    (function() {
        setTimeout( function timer() {
            console.log( j );
        }, j*1000 );
    })(i);
}

Solution two:

for (var i=1; i<=5; i++) {
    let j = i; // yes, block scope for closures! 
    setTimeout( function timer() {
        console.log( j );
    }, j*1000 );
}
for (let i=1; i<=5; i++) { // let points out that the variable is declared not only once during the loop, but will be declared every iteration, so there are 5 independent closures. 
    setTimeout( function timer() {
        console.log( i );
    }, i*1000 );
}

Use closures to implement the module pattern:

function Module(){
    var e = true;
    function helloE(name){
        var helloTxtE = "hello ";
        console.log(helloTxtE + name);
    }
    function helloC(name){
         var helloTxtC = "Hello" ;
        console.log(helloTxtC + name);
    }
    function changeLanguage(){
        e = !e;
        if (e) {
            publicApi.hello = helloE;
        }else{
            publicApi.hello = helloC;
        }
    }
    var publicApi = {
        hello: helloE,
        changeLanguage: changeLanguage
    };
    return publicApi;
}
var m = Module(); //If you want to implement a singleton, just use IIFE for Module 
m.hello( "zyong" ); //hello zyong
m.changeLanguage();
m.hello( "zyong"); //Hello zyong

Module dependency manager:

function HelloModule(){
    var e = true;
    function helloE(name){
        var helloTxtE = "hello ";
        console.log(helloTxtE + name);
    }
    function helloC(name){
         var helloTxtC = "Hello" ;
        console.log(helloTxtC + name);
    }
    function changeLanguage(){
        e = !e;
        if (e) {
            publicApi.hello = helloE;
        }else{
            publicApi.hello = helloC;
        }
    }
    var publicApi = {
        hello: helloE,
        changeLanguage: changeLanguage
    };
    return publicApi;
}
var ModuleManager = (function ModuleManager(){
    var modules = [];
    function define(name, deps, impl){
        for(let i=0; i<deps.length; i++){
            deps[i] = modules[deps[i]];
        }
        modules[name] = impl.apply(impl, deps);
    }
    function get(name){
        return modules[name];
    }
    var api = {
        define: define,
        get: get
    }
    return api;
})();
ModuleManager.define("helloModule", [], HelloModule);
var helloModule = ModuleManager.get("helloModule");
helloModule.hello("zyong");
helloModule.changeLanguage();
helloModule.hello("zyong");

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325096527&siteId=291194637