一 做用域(执行环境)javascript
做用域:定义了变量和函数有权访问的其余数据,决定了他们各自的行为。--------《JS高级程序设计》4.2 html
好难理解啊~参考了参考尤克希的博客内容,大致上理解了做用域。 前端
做用域:规定了函数和变量的可用的有效的范围。这样的好处是,避免了命名冲突;肯定什么时候销毁他们,释放内存。这个做用域中全部的函数和对象,都保存在变量对象里。每一个做用域都有这样一个变量对象。可是咱们编写的代码是没法访问到这个对象的,解析器在处理数据时会在后台使用它。java
做用域分为两类:全局做用域和函数做用域。浏览器
全局做用域是最外围的一个做用域。根据 ECMAScript 实现所在的宿主环境不一样,表示做用域的对象也不同。在 Web 浏览器中,全局做用域是 Window 对象,所以全部全局变量和函数都是做为 window 对象的属性和方法建立的。当某一个做用域中全部的代码都执行完之后,做用域被销毁, 做用域里面的变量和函数,也随之销毁。(全局执行环境直到应用程序退出----例如关闭网页或者浏览器------这时才被销毁) ----------- 《JS高级程序设计》4.2 app
环境栈:每一个函数都有本身的做用域,当执行流进入一个函数时,函数的做用域就会被推入一个环境栈中。函数执行完毕后,这个函数的做用域被环境栈弹出,把控制权交还给以前的做用域。函数
在一个页面中,第一次载入JS代码时建立一个全局执行环境,当调用一个 JavaScript 函数时,该函数就会进入相应的执行环境。若是又调用了另一个函数(或者递归地调用同一个函数),则又会建立一个新的执行环境,而且在函数调用期间执行过程都处于该环境中。当调用的函数返回后,执行过程会返回原始执行环境。于是,运行中的 JavaScript 代码就构成了一个执行环境栈。(参考笨蛋的座右铭)。flex
举个例子,下面程序的环境栈以下图:ui
var cloth = 'shirt'; function f1() { var anotherCloth = 'pants'; function f2() { var drink = 'juice'; }
f2(); }
f1();
二 做用域链spa
当代码在一个做用域中执行时,会创造一个做用域链(scope chain)。做用域链的用途是,保证对执行环境有权访问的全部变量和函数的有序访问。做用域链的前端始终都是当前执行的代码所在环境的变量对象。做用域链的下一个变量对象,来自包含(外部)环境,而在下一个变量对象则来自下一个包含环境。这样一直延续到全局执行环境;全局执行环境始终都是做用域链的最后一个对象。
标识符解析是沿着做用域链一级级搜索标识符的过程。搜索过程始终都是从做用域链的前段开始,而后逐级的向后回溯,直到找到标识符为止(若是找不到标识符,一般会致使错误发生。)
-----《JS高级程序设计》4.2
举例来理解:
1 var color = 'blue'; 2 3 function changeColor() { 4 var anotherColor = "red" 5 6 function swapColors() { 7 var tempColor = anotherColor; 8 anotherColor = color; 9 color = tempColor; 10 11 // 这里能够访问 color、anotherColor 和 tempColor 12 } 13 14 // 这里能够访问 color 和 anotherColor。不能访问 tempColor 15 16 swapColors() 17 } 18 19 // 这里只能访问 color 20 21 changeColor() 22
上面代码在执行的时候有三个做用域:全局做用域、changeColor() 做用域和 swapColors() 做用域。他们的做用域链以下图:
做用域链的本质是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。
三 块级做用域
块级做用域,就是在 for、if 等里面定义的变量,在 for、if 执行完毕之后,这些变量也会被销毁。ES6 以前的版本,是没有块级做用域的。ES6 新增长了 let 和 const 关键字,就有了块级做用域。例以下面的代码:
1 if (true) { 2 var color = 'blue'; 3 } 4 5 alert(color); // 'blue' color 变量在 if 语句执行完之后并无被销毁if 语句执行完之后,还会在外面访问到 if 里面的 color变量。
1 if (true) { 2 let color = 'blue'; 3 } 4 5 alert(color); // color 变量在 if 语句执行完毕之后,被销毁,外部访问不到 if 语句块里面定义的 color 变量。
1 for (var i=0; i < 10; i++) { 2 var a = 1; 3 } 4 5 alert(i) // 10 6
7 for (const i=0; i < 10; i++) { 8 var a = 1; 9 } 10 11 alert(i) //
未解决的问题:
if 语句用 const 实现不了块级做用域,for 语句用 let 实现不了会计做用域。这个疑惑还要后续再查找资料补充。
补充结果:let 用在块做用域定义变量,而 const 在块做用域定义常量。即在块做用域中,一旦使用 const a = 1;那么,在块做用域中,就不能再给 a 赋值别的值了。由于,此时 a 已是一个常量了。