本系列是在平时阅读、学习、实际项目中有关于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
    })(); // es6
    (function(){
    if(false) {
    let temp = 1;
    }
    console.log(temp); // Uncaught ReferenceError: temp is not defined
    })();

    从代码中我们可以很清晰看到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
    })(); (function() {
    if(true) {
    let temp = 1;
    var temp = 2; // Uncaught SyntaxError: Identifier 'temp' has already been declared
    }
    })(); (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);
});
} // 伪代码
var fnArr;
fnArr = [];
{
var i;
i = 0; if(i < 3) {
fnArr.push(function() {
console.log(i);
})
}
i++;
if(i < 3) {
fnArr.push(function() {
console.log(i);
});
}
i++;
...
}

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

var fnArr = [];
for(let i = 0; i < 3; i++) {
fnArr.push(function() {
console.log(i);
});
} // 伪代码
var fnArr;
fnArr = [];
{
let i;
i = 0; if(i < 3) {
let i = i;
fnArr.push(function() {
console.log(i);
})
}
i++;
if(i < 3) {
let i = i;
fnArr.push(function() {
console.log(i);
});
}
i++;
...
}

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

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

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

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

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

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

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

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

  4. let/const及块级作用域

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

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

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

  6. ES6学习笔记(1)- 块级作用域

    1. var声明变量和变量提升(Hoisting)机制的问题 在JS中通过var关键字声明的变量,无论在函数作用域中亦或是全局作用域中,都会被当成当前作用域顶部的变量,和就是所谓的提升机制(Hoist ...

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

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

  8. ES6 - Note1:块级作用域与常量

    在ES6以前,ES不支持块级作用域,只有全局作用域和函数作用域,所有变量的声明都存在变量声明提升. 1.let 关键字 声明一个块级变量,只在一个代码块中有效,如果在块外面访问便会报错,如下所示: { ...

  9. javascript之模拟块级作用域

    在java.C++等语言中,变量i在会在for循环的语句块中定义,循环一旦结束,变量i就会被销毁.可是在javaScript中,从定义开始,就可以在函数内部随处访问.比如 function outpu ...

随机推荐

  1. 在终端中使用vim命令修改某些文件,会提示文件只读模式,可以执行以下命令强制写入

    在末行模式中输入以下命令 :w !sudo tee % 回车后可能需要输入密码

  2. php 调用接口

    1.一般常用方法 file_get_contents(): 今天调用了一个反人类的接口,接口是get方式传输,里面有一个参数是当前时间,没错,不是时间戳,是当前格式化的时间:2017-8-9 11:1 ...

  3. imeiimsi生成规则

    添加SMI 和 IMSI修改  添加模拟器名修改(MEmu_ 修改成其他的名字,不支持批量修改)   IMSI第十位:7代表是145卡,6代表186卡,3代表156,0代表130,其他的可以自己找 预 ...

  4. 完美解决win10家庭版本系统无法远程连接问题

    版权声明:本文转载.原文: https://blog.csdn.net/rainmaple20186/article/details/80913191 近期接入同一局域网的服务器,发现在连接的时候,报 ...

  5. LeetCode第一次刷题

    感觉自身编程水平还是差很多,所以刷刷题 LeetCode貌似是一个用的人比较多的题库,下面是第一题 给数组和目标和求需要元素的下标 public class Solution { public int ...

  6. Linux安装配置rabbitmq

    Step1:安装erlang 1)下载erlang wget http://www.rabbitmq.com/releases/erlang/erlang-19.0.4-1.el7.centos.x8 ...

  7. java中数组实现的错误

    作为一个刚学java的小白 真是错误百出 下面就是一个大神会非常不屑的一个小错误 数组在初始化的时候仅仅是定义了一个数组,并未其中的内容初始化. 附上错误代码 : class student{publ ...

  8. 入学java的第一天

    登录http://www.oracle.com,下载JDK(J2SE) JDK 1.0,1.1,1.2,1.3,1.4 1.5(JDK5.0) 支持注解.支持泛型 1.6(JDK6.0)Server2 ...

  9. 523. Continuous Subarray Sum

    class Solution { public: bool checkSubarraySum(vector<int>& nums, int k) { unordered_map&l ...

  10. python 日常 摘要

    正负无穷float(‘inf’): Python中可以用表示正负无穷:float("inf"), float("-inf") 不等式: 当涉及 > 和 & ...