javascript 作用域——函数作用域(一)

70 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 6 天,点击查看活动详情

javascript 作用域——函数作用域

函数中的作用域

javascript 具有函数作用域,意味着每声明一个函数都会为其自身创建一个气泡。而每一个气泡都是一个作用域。

function foo() {
  // ...一些代码
  var c = 0;
  function bar() {
    // ... 一些代码

    console.log(c);
  }

  bar();
}

foo();

上面的代码当中,我们创建了两个函数作用域,一个是 foo 函数,一个是 bar 函数。而bar函树作用域被foo函数作用域所包围。当我们从全局作用域当中想要回去函数作用域当中的变量的时候,会产生错误。

函数作用域的含义是指:属于这个函数的全部变量都可以在整个函数的范围内使用及复用,并且在嵌套的作用域当中也可以使用。这种设计方式可以充分的利用 javascript 变量可以根据需要改变值类型的动态特性。

但是与此同时,如果不细心处理那些可以在整个作用域范围内被访问的变量,可能会带来意想不到的问题。

隐藏内部实现

对函数的传统使用方法是先声明函数,然后再向函数体添加代码。但是,我们可以反过来思考,我们先书写代码,然后利用函数的作用域来隐藏一部分代码,然后暴露某些特定的 api 实现模块化的作用。

function doSomething(a) {
  return a + doSomeElse(a);
}

function doSomeElse(a) {
  return a - 1;
}

var b = 10;

console.log(doSomething(b)); // 19

上面的代码当中,我们定义了函数doSomething()doSomeElse(),在doSomething()当中调用doSomeElse()进行计算,然后将计算结果与形参a进行相加,最后返回结果。但是这样的代码显然是不合理的,我们完全没有必要对外暴露doSomeElse()这个函数,因为他接收的参数可以通过doSomething()来获取,因此我们可以将doSomeElse()这个函数隐藏起来,这样就可以更好的把握函数的作用域。

function doSomething(a) {
  function doSomeElse(a) {
    return a - 1;
  }
  return a + doSomeElse(a);
}

var b = 10;

console.log(doSomething(b)); // 19

将函数doSomeElse()doSomething()当中隐藏起来,结果还是一样,但是这样我们可以更加合理的设计一些私有化的函数。

规避冲突

“隐藏”作用域当的函数与变量,还可以规避一些变量的命名冲突,两个标识符可能具有相同的名字但是用途却不一样,无意间肯造成命名冲突。冲突会导致变量的值被意外的修改。

  • 全局命名空间

变量冲突的一个电信例子存在于全局作用域当中,当程序加载了多个第三方库时,如果第三方库没有妥善的进行变量的隐藏,很有可能会造成全局作用域的变量污染。例如jQuery库会暴露$来作为暴露出来的公共 API,而库当中的需要暴露出来的函数都挂载到$上面,这样就不会造成全局当中同名的标识符被覆盖的问题。

  • 模块管理

另外一种规避变量标识符冲突的办法和现代的模块机制很接近,就是从众多的模块管理器当中挑选一个来使用。使用这些工具,任何库都无需将标识符加入到全局作用域当中,而是通过依赖管理器的机制将库的标识符显式的导入到另外一个特定的作用域中。