本系列是在平时阅读、学习、实际项目中有关于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. <input>/<textarea>输入框设置默认提示文字(隐藏式)

    html代码如下: <tr>    <td>签   名:</td>    <td><input type="text" nam ...

  2. Vue/React如何优雅的一劳永逸的注册路由及组件

    原文链接: 本人掘金文章  假如图片看不清晰可前往掘金原文预览 官方文档: 组建注册 路由注册 未优化版: 在Vue官方文档 中,我们通过  Vue.component('MyComponentNam ...

  3. open, creat - 用来 打开和创建 一个 文件或设备

    SYNOPSIS 总览 #includ e <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int o ...

  4. postgresql相关sql集锦

    1.类似于oracle的listagg->string_agg SELECT area_county,)total FROM project_info GROUP BY area_county ...

  5. 19.go语言基础学习(下)——2019年12月16日

    2019年12月16日16:57:04 5.接口 2019年11月01日15:56:09 5.1 duck typing 1. 2. 接口 3.介绍 Go 语言的接口设计是非侵入式的,接口编写者无须知 ...

  6. [BZOJ] 聚会

    问题描述 Y 岛风景美丽宜人,气候温和,物产丰富.Y 岛上有 N 个城市,有 N-1 条城市间的道路连接着它们.每一条道路都连接某两个城市.幸运的是,小可可通过这些道路可以走遍 Y岛的所有城市. 神奇 ...

  7. 【ElicitSearch】启动流程

    一.集群启动流程 1.选举主节点 许多节点启动,集群干的第一件事儿就是选主,之后的的流程由主节点触发. 先确定唯一的.大家公认的主节点:再想办法把最新的及其原数据复制到选举的主节点上. 选主是对Bul ...

  8. c#Main()方法,java 是小写main

    main 方法,staitc 静态关键首字母大写,区分大小写,java 是main小写,返回值 ,vodi,int参数:可选static void Main(string[] args){ }

  9. JS自定义随机键盘

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 【HDOJ6628】permutation 1(dfs)

    题意:求1到n的排列中使得其差分序列的字典序为第k大的原排列 n<=20,k<=1e4 思路:爆搜差分序列,dfs时候用上界和下界剪枝 #include<bits/stdc++.h& ...