archerU / notes

博客笔记 预计写七个系列:JavaScript深入系列、JavaScript专题系列、数据结构和算法系列、设计模式系列、React系列、Webpack 系列、前端开发日常优化方案

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

JavaScript深入系列之作用域链

archerU opened this issue · comments

函数作用域

任何声明在某个作用域内的变量,都将附属于这个作用域。在 JavaScript 语言中只有函数作用域。

隐藏内部实现

function doSomething(a) {
    b = a + doSomethingElse(a * 2);
    console.log(b * 3);
}   

function doSomethingElse(a) {
    return a - 1;
}
var b;
doSomething(2); 

// 15
function doSomething(a) {
    function doSomethingElse(a) {
        return a - 1;
    }
    var b;
    b = a + doSomethingElse(a * 2);
    console.log(b * 3);
}
doSomething(2); 

// 15

bdoSomethingElse(...) 都无法从外部被访问,而只能被 doSomething(...) 所控制。功能性和最终效果都没有受影响,但是设计上将具体内容私有化了。这便是函数作用域的作用。

立即执行函数表达式(IIFE)

var a = 2;
function foo() {
    var a = 3;
    console.log(a); // 3
}
foo();
console.log(a); //2

虽然隐藏内部实现可以解决一些问题,但是并不理想。首先,必须声明一个具名函数foo(),意味着foo这个名称本身“污染”了所在的作用域。其次,必须显式地通过函数名foo()调用这个函数才能运行其中的代码。

做如下改进:

var a = 2;
(function foo() {
    var a = 3;
    console.log(a); // 3
})();
console.log(a); //2 

函数被包含在一对 ()括号内部,因此成为一个表达式,通过在末尾加上另外一个 ()括号可以立即执行这个函数。

IIFE(Immediately Invoked Function Expression)的另外一个非常普遍的进阶用法是把它们当作函数调用并传递参数进去。用于解决如下问题:

undefined = true; // 给其他代码挖了一个大坑!绝对不要这么做!

(function IIFE(undefined) {
    var a;
    if (a === undefined) {
        console.log("Undefined is safe here!")
    }
})();
// Undefined is safe here!

IIFE还可以用于倒置代码的运行顺序,将需要运行的函数放在第二位,在IIFE执行之后当作参数传递进去。这种模式在 UMD(Universal Module Definition)项目中被广泛使用。

var a = 2;
(function IIFE(def) {
    def(window);
})(function def(global) {
    var a = 3;
    console.log(a); //3 
    console.log(global.a); // 2
});