前面的话

  尽管函数作用域是最常见的作用域单元,也是现行大多数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作用域系列第四篇的更多相关文章

  1. 深入理解javascript作用域系列第四篇——块作用域

    × 目录 [1]let [2]const [3]try 前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用 ...

  2. 深入理解javascript作用域系列第三篇——声明提升(hoisting)

    × 目录 [1]变量 [2]函数 [3]优先 前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javasc ...

  3. 深入理解javascript作用域系列第三篇

    前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javascript作用域系列第三篇——声明提升(hois ...

  4. 深入理解javascript作用域系列第五篇——一张图理解执行环境和作用域

    × 目录 [1]图示 [2]概念 [3]说明[4]总结 前面的话 对于执行环境(execution context)和作用域(scope)并不容易区分,甚至很多人认为它们就是一回事,只是高程和犀牛书关 ...

  5. 深入理解javascript作用域系列第五篇

    前面的话 对于执行环境(execution context)和作用域(scope)并不容易区分,甚至很多人认为它们就是一回事,只是高程和犀牛书关于作用域的两种不同翻译而已.但实际上,它们并不相同,却相 ...

  6. 深入理解javascript函数系列第四篇——ES6函数扩展

    × 目录 [1]参数默认值 [2]rest参数 [3]扩展运算符[4]箭头函数 前面的话 ES6标准关于函数扩展部分,主要涉及以下四个方面:参数默认值.rest参数.扩展运算符和箭头函数 参数默认值 ...

  7. 深入理解javascript作用域系列第一篇——内部原理

    × 目录 [1]编译 [2]执行 [3]查询[4]嵌套[5]异常[6]原理 前面的话 javascript拥有一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量,这套规则被称为作用域.作用域 ...

  8. 深入理解javascript作用域系列第一篇

    前面的话 javascript拥有一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量,这套规则被称为作用域.作用域貌似简单,实则复杂,由于作用域与this机制非常容易混淆,使得理解作用域的原 ...

  9. 深入理解javascript作用域系列第二篇——词法作用域和动态作用域

    × 目录 [1]词法 [2]动态 前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极 ...

随机推荐

  1. GridControl详解(一)原汁原味的表格展示

    Dev控件中的表格控件GridControl控件非常强大.不过,一些细枝末节的地方有时候用起来不好找挺讨厌的.使用过程中,多半借助Demo和英文帮助文档.网上具体的使用方法也多半零碎.偶遇一个简单而且 ...

  2. 20155117王震宇 实验三 敏捷开发与XP实践 实验报告

    实验内容 XP基础 XP核心实践 相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程 2.完成实验.撰写实验报告,实 ...

  3. 洛谷 Transformations 方块转换

    Description 一块N x N(1<=N<=10)正方形的黑白瓦片的图案要被转换成新的正方形图案.写一个程序来找出将原始图案按照以下列转换方法转换成新图案的最小方式: 1:转90度 ...

  4. cookie知识点概述

    cookie是什么 这个讲起来很简单,了解http的同学,肯定知道,http是一个不保存状态的协议,什么叫不保存状态,就是一个服务器是不清楚是不是同一个浏览器在访问他,在cookie之前,有另外的技术 ...

  5. VC孙鑫老师第八课:你能捉到我吗?

    第一步,首先在对话框窗口上放上两个一模一样的按钮控件 第二步,由于是按钮响应鼠标移动上去的事件,因此需要重新派生按钮类: 第三步,在窗口类中声明并使用自定义按钮对象(记得在窗口类中包含自定义按钮类的头 ...

  6. fastDFS 命令笔记【转】

    端口开放 这是命令运行的前提 iptables -I INPUT -p tcp -m state –state NEW -m tcp –dport 22 -j ACCEPT iptables -I I ...

  7. Django 1.10文档中文版Part2

    目录 2.5 第一个Django app,Part 3:视图和模板 2.5.1 概览 2.5.2 编写更多的视图 2.5.3 编写能实际干点活的视图 2.5.4 404错误 2.5.5 使用模板系统 ...

  8. slf4j中的Logger 使用占位符{} 来传入参数记录日志信息

    首先要导入 slf4j包中的2个类 import org.slf4j.Logger;import org.slf4j.LoggerFactory; 再定义如下 private final static ...

  9. StringBuilder基本用法

    //StringBuilder用法 public class StringBuilderTest { public static void main(String[] args) { StringBu ...

  10. mysql 创建,授权,删除 用户

    1.创建用户 创建一个用户名是 lefunyun 密码是 X5A4FU8I0lKM21YPYUzP 账号 CREATE USER lefuyun@localhost IDENTIFIED BY 'X5 ...