js做用域

词法做用域

定义与查找

词法做用域就是定义在词法阶段的做用域,简单来讲词法做用域是由你在写代码时将变量和块做用域写在哪里来决定的,所以大部分状况下当词法分析器处理代码时会保持做用域不变javascript

function foo(a) {
  var b = a * 2;
  function bar(c) {
    console.log(a, b, c)
  }
  bar(b * 3)
}
foo(2) // 2, 4, 12

此例中一共由三个逐级嵌套的做用域:java

  1. 包含这整个全剧做用域,其中只有一个标识符:foo
  2. 包含着foo所建立的做用域,其中有三个标识符:a、bar和b
  3. 包含着bar所建立的做用,其中只有一个标识符:c

做用域查找过程编程

  1. 当引擎执行console.log(a, b, c)声明时,它首先会从最内层的bar()函数做用域开始查找,在这里找到了c
  2. 由于没法找到a和b,所以会到再上一层的foo()做用域去查找

做用域查找会在找到第一个匹配的标识符时中止
不管函数在哪里被调用,也不管它如何被调用,它的词法做用域都只由函数被声明时所处的位置决定编程语言

函数做用域

函数做用域指的是属于这个函数的所有变量均可以在整个函数的范围内使用及复用,包括嵌套的做用域,这种设计方案很是有用。函数

隐藏内部实现

在软件设计中,应该最小限度地暴露必要内容,而将其余内容都隐藏起来,这个原则在如何在如何选择做用域来包含变量和函数也一样适用,例如:设计

var b;
function one(a) {
  b = a + another(a)
  console.log(b)
}
function another(a) {
  return a*2
}

one(2) // 6

在这段代码中,给予外部函数b和another访问权限不只没有必要,并且可能会被以非预期的方式使用,所以更加合理的设计会将这些内容隐藏在one()内部,例如:code

function one(a) {
  function another(a) {
    return a*2
  }
  var b
  b = a + another(a)
  console.log(b)
}
one(2) //6

这样设计b和another()都没法从外部被访问,功能和最终效果都没有受影响,可是设计上将具体内容私有画ip

当即执行行数表达式

经过前面的介绍已经知道,在任意代码片断外部添加包装函数,能够将内部变量和函数定义隐藏起来,外部做用域没法访问包装函数内部的任何内容。例如:作用域

var a = 0
function ex() {
  var a = 1
  console.log(a) // 1
}
ex();
console.log(a)// 0

虽然这样能够解决一部分问题,可是并不理想,会将ex这个变量污染全局做用域,而且须要调用才能运行其中的代码,javascript提供了解决问题的方案:当即执行函数表达式(IIFE)io

var a = 0;
(function () {
  var a = 1
  console.log(a) //1
})();
console.log(a) //0

此时就不会有函数名泄漏到全局做用域,而且会自动执行,同时外部的做用域也没法直接访问当即执行函数内的变量

块做用域

事实上javascript在ES6以前并无块做用域的概念,可是其余不少编程语言都支持块做用域,ES6以前javascript循环:

for (var i=0; i<3; i++) {
  console.log(i) //0, 1, 2
}
console.log(i) //3

虽然咱们的代码看起来i只会在for循环内部使用,可是很不幸,i会被泄漏到全局的做用域中,污染全局做用域,即便这并是咱们本意,可是在ES6改变了现状,引入了新的let关键字,提供了除var之外的另外一种变量声明方式,let能够将变量绑定到所在的任意做用域中,即为其声明的变量隐式地劫持了所在的做用域

for (let i=0; i<3; i++) {
  console.log(i) //0, 1, 2
}
console.log(i) // i is not defined

以上内容是我的的一点总结,若是有错误或不严谨的地方,欢迎批评指正,若是喜欢,欢迎点赞收藏

相关文章
相关标签/搜索