本系列是在平时阅读、学习、实际项目中有关于es6中的新特性、用发的简单总结,目的是记录以备日后温习;本系列预计包含let/const、箭头函数、解构、常用新增方法、Symbol、Set&Map、Proxy、reflect、Class、Module、Iterator、Promise、Generator、async/await

let/const为我们带来了什么?

let

  1. 约束变量提升

    (function foo() {
    console.log(a);
    let a = 1;
    })(); // Uncaught ReferenceError: a is not defined

    总结下来就是一句: 在变量使用之前,必须先要声明,变量声明永远在使用之前。

  2. 带来了块级作用域
    // es5
    (function(){
    if(false) {
    var temp = 1;
    }
    console.log(temp); // undefined
    })();
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> es6</span>
    (<span style="color: #0000ff;">function</span><span style="color: #000000;">(){
    </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">false</span><span style="color: #000000;">) {
    let temp </span>= 1<span style="color: #000000;">;
    }
    console.log(temp); </span><span style="color: #008000;">//</span><span style="color: #008000;"> Uncaught ReferenceError: temp is not defined</span>
    })();</pre>

    从代码中我们可以很清晰看到es6的let的块级作用域,那么块级作用域有什么应用呢?举个例子:

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

    如果没有仔细分析,执行的结果是不是有些出乎意料呢? 是的,我们本意在for循环内部使用的变量i被泄露成了全局变量,而且在for循环的每一次循环,变量i并没有被重新声明,实际上数组fnArr中保存的每一个函数中引用的都是同一个变量i,所以才导致了现在的结果,那怎么让代码按照我们最初的想法运行呢?来看es5中常用的解法

    var fnArr1 = [];
    for(var i = 0; i < 5; i++) {
    (function(j) {
    fnArr1.push(function() {
    console.log(j);
    });
    })(i)
    }
    fnArr1[0](); //
    fnArr1[1](); //
    fnArr1[2](); //
    fnArr1[3](); //
    fnArr1[4](); //
    console.log(i); //

    看起来是解决了,这里实际上用到了闭包的方法,fnArr1中每一项函数引用的j都是当前循环时i的一个副本,这样就解决了前面的问题,但是还有一个问题: 变量i仍然隐式得泄露到了全局

    var fnArr1 = [];
    for(let i = 0; i < 5; i++) {
    fnArr1.push(function() {
    console.log(i);
    });
    }
    fnArr1[0](); //
    fnArr1[1](); //
    fnArr1[2](); //
    fnArr1[3](); //
    fnArr1[4](); //
    console.log(i); // Uncaught ReferenceError: i is not defined

    OK,问题解决了,仅仅是将’var‘替换成了let,这就是let带来的便利。

  3. 产生暂时性死区&禁止重复声明
    // 什么是禁止重复声明呢? 先不给书面解释,来看一个es5中经常的写法
    (function() {
    var temp = 1;
    var temp = 2;
    var temp = function() {
    return 1;
    };
    })();

    上面这段代码执行没有任何问题,最终temp被赋值为一个函数

    (function() {
    let temp = 1;
    var temp = 2; // Uncaught SyntaxError: Identifier 'temp' has already been declared
    var temp = function() {
    return 1;
    };
    })();

    在第三行时就抛出了一个错误:temp已经被声明,是的,let声明过的变量,是不允许再次被声明的,再给几个例子巩固一下:

    (function() {
    var temp = 2;
    var temp = function() {
    return 1;
    };
    let temp = 1; // Uncaught SyntaxError: Identifier 'temp' has already been declared
    })();
    (</span><span style="color: #0000ff;">function</span><span style="color: #000000;">() {
    </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">true</span><span style="color: #000000;">) {
    let temp </span>= 1<span style="color: #000000;">;
    </span><span style="color: #0000ff;">var</span> temp = 2; <span style="color: #008000;">//</span><span style="color: #008000;"> Uncaught SyntaxError: Identifier 'temp' has already been declared</span>

    }

    })();

    (function() {

    if(true) {

    let temp = 1;

    function temp() { // Uncaught SyntaxError: Identifier 'temp' has already been declared

    return 1;

    }

    }

    })();

    看出来了吗?只要是在let声明所在的作用域,就不允许再次声明同名变量(包括函数声明)

    var foo = 1;
    if(true) {
    foo = 2; // Uncaught ReferenceError: foo is not defined
    let foo;
    }

    看到let的’霸道‘了吧?只要在let所在的作用域,同名的变量就会被let占有,不允许重复声明,同时也要遵守let的规则

  4. 全局变量不再作为window对象的属性
    var foo = 1;
    (function() {
    bar = 2;
    })();
    window.foo; //
    window.bar; //

    是的,es5中,全局变量(包括意外泄露的)都将自动被添加为window对象的属性

    let foo = 1;
    
    window.foo; // undefined

    一切尽在不言中。。。

const

  1. let所拥有的特性,const都有,同时const还有一条:const声明的变量必须进行初始化,并且不能再被重新赋值

    const temp = 1;
    temp = 2; // Uncaught TypeError: Assignment to constant variable.

    注意是不能被重新赋值,这样是比较准确的,其实const声明的变量是可以被修改的,当const声明的变量被初始化为复杂数据类型时,const声明的变量就是可变的,至于为什么,自己理解喽(变量标识符中保存的只是复杂数据类型内存地址而已。。。)

    const temp = {};
    temp.foo = 'aa'; // 这里没问题
    temp = {foo: 'aa'}; // 这里就会抛出异常

for循环中的变量声明

前面在记录let块级作用域的时候,我们使用了一个for循环的例子,这里我们不妨试着解析一下for循环的执行过程

var fnArr = [];
for(var i = 0; i < 3; i++) {
fnArr.push(function() {
console.log(i);
});
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 伪代码</span>
<span style="color: #0000ff;">var</span><span style="color: #000000;"> fnArr;
fnArr </span>=<span style="color: #000000;"> [];
{
</span><span style="color: #0000ff;">var</span><span style="color: #000000;"> i;
i </span>= 0<span style="color: #000000;">; </span><span style="color: #0000ff;">if</span>(i &lt; 3<span style="color: #000000;">) {
fnArr.push(</span><span style="color: #0000ff;">function</span><span style="color: #000000;">() {
console.log(i);
})
}
i</span>++<span style="color: #000000;">;
</span><span style="color: #0000ff;">if</span>(i &lt; 3<span style="color: #000000;">) {
fnArr.push(</span><span style="color: #0000ff;">function</span><span style="color: #000000;">() {
console.log(i);
});
}
i</span>++<span style="color: #000000;">;
...
}</span></pre>

这里可惜清晰得看到所有的i都是一个i。。。那使用了let以后呢?

var fnArr = [];
for(let i = 0; i < 3; i++) {
fnArr.push(function() {
console.log(i);
});
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 伪代码</span>
<span style="color: #0000ff;">var</span><span style="color: #000000;"> fnArr;
fnArr </span>=<span style="color: #000000;"> [];
{
let i;
i </span>= 0<span style="color: #000000;">; </span><span style="color: #0000ff;">if</span>(i &lt; 3<span style="color: #000000;">) {
let i </span>=<span style="color: #000000;"> i;
fnArr.push(</span><span style="color: #0000ff;">function</span><span style="color: #000000;">() {
console.log(i);
})
}
i</span>++<span style="color: #000000;">;
</span><span style="color: #0000ff;">if</span>(i &lt; 3<span style="color: #000000;">) {
let i </span>=<span style="color: #000000;"> i;
fnArr.push(</span><span style="color: #0000ff;">function</span><span style="color: #000000;">() {
console.log(i);
});
}
i</span>++<span style="color: #000000;">;
...
}</span></pre>

是不是看出点名堂?其实我们完全可以这样理解,在每一次循环中都重新声明了i,并且被赋值为外层i的当前值。(注意啊,这里只是伪代码,便于理解,实际中let i = i是会抛出异常的)

转载来源:https://www.cnblogs.com/innooo/p/10438947.html

let/const及块级作用域的更多相关文章

  1. ES6的 let const 以及块级作用域

    let声明变量 用法类似于var,但是所声明的变量只在let所在的代码块内有效. 1 . 在ES6环境下,let声明的变量不能在声明之前调用. 例: console.log(i); //会报错,这叫做 ...

  2. ES6系列之let/const及块级作用域

    本系列是在平时阅读.学习.实际项目中有关于es6中的新特性.用发的简单总结,目的是记录以备日后温习:本系列预计包含let/const.箭头函数.解构.常用新增方法.Symbol.Set&Map ...

  3. ES6-let、const和块级作用域

    1.介绍 总的来说,ES6是在ES2015的基础上改变了一些书写方式,开放了更多API,这样做的目的最终还是为了贴合实际开发的需要.如果说一门编程语言的诞生是天才的构思和实现,那它的发展无疑就是不断填 ...

  4. 开始学习es6(二) let 与 const 及 块级作用域

    1.var JavaScript中,我们通常说的作用域是函数作用域,使用var声明的变量,无论是在代码的哪个地方声明的,都会提升到当前作用域的最顶部,这种行为叫做变量提升(Hoisting) cons ...

  5. ES6入门一:块级作用域(let&const)、spread展开、rest收集

    let声明 const声明 块级作用域 spread/rest 一.let声明与块作用域 在ES6之前,JavaScript中的作用域基本单元就是function.现在有了let就可以创建任意块的声明 ...

  6. ES6 浅谈let与const 块级作用域之封闭空间(闭包)

    ES6新增了 let const 命令,用来声明变量.它的用法类似于 var  ,但是所声明的变量,只在 let const 命令所在的代码块内有效.  var const 不允许重复声明 用处: 可 ...

  7. ES6 let const 声明变量 块级作用域

    ES6 中除了使用 var 定义变量,还有let.const,定义变量. function getValue(condition){ console.log(typeof value2); // un ...

  8. 《浏览器工作原理与实践》<09>块级作用域:var缺陷以及为什么要引入let和const?

    在前面我们已经讲解了 JavaScript 中变量提升的相关内容,正是由于 JavaScript 存在变量提升这种特性,从而导致了很多与直觉不符的代码,这也是 JavaScript 的一个重要设计缺陷 ...

  9. ES6标准入门 第二章:块级作用域 以及 let和const命令

    一.块级作用域 1.为什么需要块级作用域? ES5中只有全局作用域和函数作用域,带来很多不合理的场景. (1)内层变量可能会覆盖外层变量: var tem = new Date(); function ...

随机推荐

  1. 正则表达式RegExp对象

    3.1 正则表达式对象的创建方式 字面量的方式   var patt = /匹配规则/修饰符;     / --> 边界的意思 new关键字     var patt = new RegExp( ...

  2. ajax图片上传(asp.net +jquery+ashx)

    一.建立Default.aspx页面 <%@ Page Language="C#" AutoEventWireup="true"  CodeFile=&q ...

  3. Spark2.0 Java实现将Hive运算结果保存到数据库

    package com.gm.hive.SparkHive; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; ...

  4. passwd - 密码文件

    描述 Passwd 是个文本文件, 它包含了一个系统帐户列表, 给出每个帐户一些有用的信息,比如用户 ID,组 ID, 家目录, shell,等. 通常它也包含了每个用户经过加密的密码. 它通常应该是 ...

  5. 2、Jmeter测试

    一.测试流程 1.添加本次测试计划 (右键-->添加-->Threads(Users)-->线程组) 2.设置线程数 (所谓线程数就是并发用户数) 3.在线程组内添加请求(右键--& ...

  6. oralce 汇编02

    Assembler Directives .align integer, padThe .align directive causes the next data generated to be al ...

  7. Linux ssh内置sftp配置说明

    centos7 环境下已验证 首先建立两个用户,用于sftp访问使用. eg: useradd -d /opt/sftp  -s /bin/nologin sftp 说明 -s /bin/nologi ...

  8. P2254 [NOI2005]瑰丽华尔兹

    链接P2254 [NOI2005]瑰丽华尔兹 首先有个很朴素的\(dp\),设\(f_{i,j,k}\)表示\(k\)时刻地点\(i,j\)的最长长度. 然后这样不能优化,考虑利用一段连续时间是同一个 ...

  9. bzoj5015 [Snoi2017]礼物 矩阵快速幂+二项式展开

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5015 题解 设 \(f_i\) 表示第 \(i\) 个朋友的礼物,\(s_i\) 表示从 \( ...

  10. 封装 pyinstaller -F -i b.ico excel.py

    安装pywin32,可以参考<怎么给python安装pywin32模块?> 一定要注意对应的python版本,否则不能安装.   5怎么给python安装pywin32模块?   2 用命 ...