前面的话

  尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀、简洁的代码,比如块作用域。随着ES6的推广,块作用域也将用得越来越广泛。本文是深入理解javascript作用域系列第四篇——块作用域

let

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

  上面这段是很熟悉的循环代码,通常是因为只想在for循环内部的上下文中使用变量i,但实际上i可以在全局作用域中访问,污染了整个作用域

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

  ES6改变了现状,引入了新的let关键字,提供了除var以外的另一种变量声明方式。let关键字可以将变量绑定到所在的任意作用域中(通常是{...}内部),实现块作用域

  1. {
  2. let i = 1;
  3. };
  4. console.log(i);//ReferenceError: i is not defined

  块级作用域实际上可以替代立即执行匿名函数(IIFE)

  1. (function(){
  2. var i = 1;
  3. })();
  4. console.log(i);//ReferenceError: i is not defined

  如果将文章最开始那段for循环的代码中变量i用let声明,将会避免作用域污染问题

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

  for循环头部的let不仅将i绑定到了for循环的块中,事实上它将其重新绑定到了循环的每一个迭代中,确保使用上一个循环迭代结束时的值重新进行赋值

  1. //与上一段代码等价
  2. {
  3. let j;
  4. for (j=0; j<10; j++) {
  5. let i = j; //每个迭代重新绑定
  6. console.log( i );
  7. }
  8. }

循环

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

  1. var a = [];
  2. for(var i = 0; i < 5; i++){
  3. a[i] = function(){
  4. return i;
  5. }
  6. }
  7. console.log(a[0]());//

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

  1. var a = [];
  2. for(var i = 0; i < 5; i++){
  3. a[i] = (function(j){
  4. return function(){
  5. return j;
  6. }
  7. })(i);
  8. }
  9. console.log(a[0]());//

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

  1. var a = [];
  2. for(let i = 0; i < 5; i++){
  3. a[i] = function(){
  4. return i;
  5. }
  6. }
  7. console.log(a[0]());//

重复声明

  let不允许在相同作用域内,重复声明同一个变量

  1. {
  2. let a = 10;
  3. var a = 1;//SyntaxError: Unexpected identifier
  4. }
  1. {
  2. let a = 10;
  3. let a = 1;//SyntaxError: Unexpected identifier
  4. }

提升

  使用let进行的声明不会在块作用域中进行提升

  1. {
  2. console.log(i);//ReferenceError: i is not defined
  3. let i = 1;
  4. };

const

  除了let以外,ES6还引入了const,同样可以用来创建块作用域变量,但其值是固定的(常量)。之后任何试图修改值的操作都会引起错误

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

  const声明的常量,也与let一样不可重复声明

  1. const message = "Goodbye!";
  2. const message = "Goodbye!";//SyntaxError: Identifier 'message' has already been declared

try

  try-catch语句的一个常见用途是创建块级作用域,其中声明的变量仅仅在catch内部有效

  1. {
  2. let a = 2;
  3. console.log(a); //
  4. }
  5. console.log(a); //ReferenceError: a is not defined

  在ES6之前的环境中,可以使用try-catch语句达到上面代码的类似效果

  1. try{
  2. throw 2;
  3. }catch(a){
  4. console.log( a ); //
  5. }
  6. console.log( a ); //ReferenceError: a is not defined
  1. //或者
  2. try{
  3. throw undefined;
  4. }catch(a){
  5. a = 2;
  6. console.log( a ); //
  7. }
  8. console.log( a ); //ReferenceError: a is not defined

深入理解javascript作用域系列第四篇——块作用域的更多相关文章

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

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

  2. 深入理解javascript作用域系列第四篇

    前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀.简洁的 ...

  3. 深入理解javascript函数系列第三篇——属性和方法

    × 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...

  4. 深入理解javascript函数系列第三篇

    前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数 ...

  5. javascript面向对象系列第四篇——选项卡的实现

    前面的话 面向对象的应用并非只是读几本书那么容易,需要有大量的工程实践做基础才能真正理解并学会使用它.本文将用面向对象的技术来制作一个简单的选项卡 图示说明 由图示结果看到,这是一个非常简单的选项卡. ...

  6. javascript面向对象系列第四篇——OOP中的常见概念

    前面的话 面向对象描述了一种代码的组织结构形式——一种在软件中对真实世界中问题领域的建模方法.本文将从理论层面,介绍javascript面向对象程序程序(OOP)中一些常见的概念 对象 所谓对象,本质 ...

  7. 深入理解javascript对象系列第三篇——神秘的属性描述符

    × 目录 [1]类型 [2]方法 [3]详述[4]状态 前面的话 对于操作系统中的文件,我们可以驾轻就熟将其设置为只读.隐藏.系统文件或普通文件.于对象来说,属性描述符提供类似的功能,用来描述对象的值 ...

  8. javascript运动系列第四篇——抖动

    × 目录 [1]原理介绍 [2]代码实现 [3]实例应用 前面的话 在运动系列中,前面分别介绍了匀速运动.变速运动和曲线运动.下面介绍一种特殊的运动形式——抖动 原理介绍 抖动其实是往复运动的一种特殊 ...

  9. javascript动画系列第四篇——拖拽改变元素大小

    × 目录 [1]原理简介 [2]范围圈定 [3]大小改变[4]代码优化 前面的话 拖拽可以让元素移动,也可以改变元素大小.本文将详细介绍拖拽改变元素大小的效果实现 原理简介 拖拽让元素移动,是改变定位 ...

随机推荐

  1. CSS伪类选择器

    一.CSS伪类选择器用于给某些选择器添加效果语法规则:选择器:伪选择器例:a:link {color: #FF0000} 未访问的链接 a:visited {color: #00FF00} 已访问的链 ...

  2. angular文件引入带来的绑定问题

    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script ...

  3. FreeMarker如何输出特殊含义字符

    $.#.{.}这几个字符在FreeMarker中有着特殊的含义,当需要在FreeMarker中输出这几个字符时,可采取如下办法: ${r"#{foo}"}.${r"#{& ...

  4. Add more security in Visual Studio 2012

    Compile flags: /GS: Stack protection from buffer overrun. /SDL: Subset of W3&W4 security warning ...

  5. 仿QQ列表左滑删除

    一直想写个仿QQ通讯列表左滑删除的效果,今天终于忙里偷闲,简单一个. 大概思路是这样的: 通过 ontouchstartontouchmoveontouchend 结合css3的平移. 不多说,直接上 ...

  6. 织梦cms、帝国cms、PHPcms优缺点解析

    php才是建站的主流,cms这类程序又是用的最多的,占据主流的cms主要就是织梦,帝国,phpcms这三种的,这三个程序都是开源程序.国内用户众多.   一.从美观性来说(以官方默认模版为准   ph ...

  7. 【转】【Linux】 临界区,互斥量,信号量,事件的区别

    原文地址:http://blog.itpub.net/10697500/viewspace-612045/ Linux中 四种进程或线程同步互斥的控制方法1.临界区:通过对多线程的串行化来访问公共资源 ...

  8. 读入一个c程序,并按字母表顺序分组打印变量名,每组前N个字符相同(TCPL 练习6-2)

    在建立结构tnode的过程中,我们没有预设门槛.这道题目就设置了门槛,必须根据前N个字符来进行分组,于是排除了长度小于N的变量,以便减轻负担. 因为要求对变量名分组打印,组别理所应当地应该按照至少是升 ...

  9. winform 子报表

    public void BindReport(string _invno,string _type)         {             if (!Is_Has_Express_No(_inv ...

  10. [Asp.net 开发系列之SignalR篇]专题六:使用SignalR实现消息提醒

    一.引言 前面一篇文章我介绍了如何使用SignalR实现图片的传输,然后对于即时通讯应用来说,消息提醒是必不可少的.现在很多网站的都有新消息的提醒功能.自然对于SignalR系列也少不了这个功能的实现 ...