深入理解javascript作用域系列第四篇
前面的话
尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀、简洁的代码,比如块作用域。随着ES6的推广,块作用域也将用得越来越广泛。本文是深入理解javascript作用域系列第四篇——块作用域
let
- for (var i= 0; i<10; i++) {
- console.log(i);
- }
上面这段是很熟悉的循环代码,通常是因为只想在for循环内部的上下文中使用变量i,但实际上i可以在全局作用域中访问,污染了整个作用域
- for (var i= 0; i<10; i++) {
- console.log(i);
- }
- console.log(i);//10
ES6改变了现状,引入了新的let关键字,提供了除var以外的另一种变量声明方式。let关键字可以将变量绑定到所在的任意作用域中(通常是{...}内部),实现块作用域
- {
- let i = 1;
- };
- console.log(i);//ReferenceError: i is not defined
块级作用域实际上可以替代立即执行匿名函数(IIFE)
- (function(){
- var i = 1;
- })();
- console.log(i);//ReferenceError: i is not defined
如果将文章最开始那段for循环的代码中变量i用let声明,将会避免作用域污染问题
- for (let i= 0; i<10; i++) {
- console.log(i);
- }
- console.log(i);////ReferenceError: i is not defined
for循环头部的let不仅将i绑定到了for循环的块中,事实上它将其重新绑定到了循环的每一个迭代中,确保使用上一个循环迭代结束时的值重新进行赋值

- //与上一段代码等价
- {
- let j;
- for (j=0; j<10; j++) {
- let i = j; //每个迭代重新绑定
- console.log( i );
- }
- }

循环
下面代码中,由于闭包只能取得包含函数中的任何变量的最后一个值,所以控制台输出5,而不是0

- var a = [];
- for(var i = 0; i < 5; i++){
- a[i] = function(){
- return i;
- }
- }
- console.log(a[0]());//5

当然,可以通过函数传参,来保存每次循环的值

- var a = [];
- for(var i = 0; i < 5; i++){
- a[i] = (function(j){
- return function(){
- return j;
- }
- })(i);
- }
- console.log(a[0]());//0

而使用let则更方便,由于let循环有一个重新赋值的过程,相当于保存了每一次循环时的值

- var a = [];
- for(let i = 0; i < 5; i++){
- a[i] = function(){
- return i;
- }
- }
- console.log(a[0]());//0

重复声明
let不允许在相同作用域内,重复声明同一个变量
- {
- let a = 10;
- var a = 1;//SyntaxError: Unexpected identifier
- }
- {
- let a = 10;
- let a = 1;//SyntaxError: Unexpected identifier
- }
提升
使用let进行的声明不会在块作用域中进行提升
- {
- console.log(i);//ReferenceError: i is not defined
- let i = 1;
- };
const
除了let以外,ES6还引入了const,同样可以用来创建块作用域变量,但其值是固定的(常量)。之后任何试图修改值的操作都会引起错误

- if (true) {
- var a = 2;
- const b = 3;
- a = 3;
- b = 4;// TypeError: Assignment to constant variable
- }
- console.log( a ); // 3
- console.log( b ); // ReferenceError: b is not defined

const声明的常量,也与let一样不可重复声明
- const message = "Goodbye!";
- const message = "Goodbye!";//SyntaxError: Identifier 'message' has already been declared
try
try-catch语句的一个常见用途是创建块级作用域,其中声明的变量仅仅在catch内部有效
- {
- let a = 2;
- console.log(a); // 2
- }
- console.log(a); //ReferenceError: a is not defined
在ES6之前的环境中,可以使用try-catch语句达到上面代码的类似效果

- try{
- throw 2;
- }catch(a){
- console.log( a ); // 2
- }
- console.log( a ); //ReferenceError: a is not defined


- //或者
- try{
- throw undefined;
- }catch(a){
- a = 2;
- console.log( a ); // 2
- }
- console.log( a ); //ReferenceError: a is not defined

深入理解javascript作用域系列第四篇的更多相关文章
- 深入理解javascript作用域系列第四篇——块作用域
× 目录 [1]let [2]const [3]try 前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用 ...
- 深入理解javascript作用域系列第三篇——声明提升(hoisting)
× 目录 [1]变量 [2]函数 [3]优先 前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javasc ...
- 深入理解javascript作用域系列第三篇
前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javascript作用域系列第三篇——声明提升(hois ...
- 深入理解javascript作用域系列第五篇——一张图理解执行环境和作用域
× 目录 [1]图示 [2]概念 [3]说明[4]总结 前面的话 对于执行环境(execution context)和作用域(scope)并不容易区分,甚至很多人认为它们就是一回事,只是高程和犀牛书关 ...
- 深入理解javascript作用域系列第五篇
前面的话 对于执行环境(execution context)和作用域(scope)并不容易区分,甚至很多人认为它们就是一回事,只是高程和犀牛书关于作用域的两种不同翻译而已.但实际上,它们并不相同,却相 ...
- 深入理解javascript函数系列第四篇——ES6函数扩展
× 目录 [1]参数默认值 [2]rest参数 [3]扩展运算符[4]箭头函数 前面的话 ES6标准关于函数扩展部分,主要涉及以下四个方面:参数默认值.rest参数.扩展运算符和箭头函数 参数默认值 ...
- 深入理解javascript作用域系列第一篇——内部原理
× 目录 [1]编译 [2]执行 [3]查询[4]嵌套[5]异常[6]原理 前面的话 javascript拥有一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量,这套规则被称为作用域.作用域 ...
- 深入理解javascript作用域系列第一篇
前面的话 javascript拥有一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量,这套规则被称为作用域.作用域貌似简单,实则复杂,由于作用域与this机制非常容易混淆,使得理解作用域的原 ...
- 深入理解javascript作用域系列第二篇——词法作用域和动态作用域
× 目录 [1]词法 [2]动态 前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极 ...
随机推荐
- JVM学习十:JVM之垃圾收集器及GC参数
接近两个月左右没有写博客,主要是因为小孩过来后,回家比较忙,现在小孩端午送回家了,开始继续之前的JVM学习之路,前面学习了GC的算法和种类,那么本章则是基于算法来产生实际的用途,即垃圾收集器. 一.堆 ...
- .net core 中 identity server 4 之Topic --定义API资源
想要让客户端能够访问API资源,就需要在Identity Server中定义好API的资源. Scope作用域:即API资源的访问范围限制. 作用域是一个资源 (通常也称为 Web API) 的标识符 ...
- react input 设置默认值
1.text类型 <input type="text" value={默认值} /> ,这种写法可以显示默认值,但不能对输入框进行编辑 正确写法: <input ...
- thinkphp 5.0 代码执行漏洞
https://github.com/vulhub/vulhub/blob/master/thinkphp/5-rce docker-compose -f /home/root/compose.yml ...
- angular项目文件概览
在Mac上打开终端,输入ng new b-app 如下: 然后在webstorm中打开 src文件夹 你的应用代码位于src文件夹中. 所有的Angular组件.模板.样式.图片以及你的应用所需的任 ...
- /proc文件夹介绍
Linux系统上的/proc目录是一种文件系统,即proc文件系统.与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过 ...
- Effective C++笔记(二):构造/析构/赋值运算
参考:http://www.cnblogs.com/ronny/p/3740926.html 条款05:了解C++默默编写并调用哪些函数 如果自定义一个空类的话,会自动生成默认构造函数.拷贝构造函数. ...
- java并发编程实战笔记---(第二章)线程安全:正确性
ThreadA__________ 同步 ______________ 异步 ___________ 异步 ThreadB__________ ____________ ...
- MyBatis3-与Spring MVC 4集成
继前一篇的例子http://www.cnblogs.com/EasonJim/p/7052388.html,已经集成了Spring框架,现在将改造成Spring MVC的项目,并实现如下功能: 1.不 ...
- Codeforces 798D - Mike and distribution(二维贪心、(玄学)随机排列)
题目链接:http://codeforces.com/problemset/problem/798/D 题目大意:从长度为n的序列A和序列B中分别选出k个下表相同的数要求,设这两个序列中k个数和分别为 ...