当前位置:嗨网首页>书籍在线阅读

07-函数、闭包和静态作用域

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

7.6 函数、闭包和静态作用域

截止目前,只针对块进行了学习,块有助于理解静态作用域,特别是当对块进行了缩进以后。而对于函数,因为可以在一个地方定义,在另一个地方调用,这就意味着可能要费些周折才能理解它们的作用域。

在“传统”程序中,可能会把所有函数都定义在全局作用域内,而在函数中避免去访问全局变量(作者推荐的方式),甚至不用思考函数可以访问什么作用域。

然而,在现代JavaScript开发中,通常会把函数定义在需要使用的地方。将它们赋给变量和对象属性、添加到数组中、当做参数传给函数、作为函数的返回值,甚至有时候连名字也省掉了。

有一个十分常见的场景:故意将某个函数定义在一个指定的作用域中,并明确地指出它对该作用域所具备访问权限,通常称这种形式为闭包(可以认为封闭了函数的作用域)。看一个闭包的例子:

let globalFunc;                         // 未定义的全局函数
{
    let blockVar = 'a';                 // 块作用域变量
    globalFunc = function() { 
        console.log(blockVar);
    }
}
globalFunc();                            // 打印"a" 

globalFunc 在块内被赋值:该块(以及它的父作用域,即全局作用域)构成了一个闭包。不论在哪里调用 globalFunc ,它都有权限访问闭包内的变量。

这里面隐含了一层重要的含义:当调用 globalFunc 时,尽管程序已经退出了变量 blockVar 的作用域,它仍然有权限访问它。而通常情况下,某个作用域退出后,该作用域中声明的变量会安全地消亡。在这里例子中,JavaScript注意到函数被定义在指定作用域内(并且这个函数可以在该作用域外被引用),所以该函数会持有该作用域的访问权限。

在闭包内定义的函数不但可以影响闭包的生命周期,它还允许访问一些正常情况下无法访问到的信息。来看个例子:

let f;                                  // 未定义的函数
{     
    let o = { note: 'Safe' };
    f = function() {
        return o; 
    } 
}
let oRef = f();
oRef.note = "Not so safe after all!";

通常情况下,作用域之外的信息会受到严格的访问限制。而函数比较特殊,因为它提供了一个绿色通道,让原本封闭的作用域可以被外界访问。在接下来的章节中,大家会看到这个特性的重要性。