本系列是在平时阅读、学习、实际项目中有关于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. python中的字典

    字典:由多个键及与其对应的键-值对组成,用:隔开,用花括号 括起来  phone_book={'Daming':'2202','Amy':'5462','Sam':'4785'} dict函数:

  2. int 和 Integer

    现状1+1=?,不加思索2.有一个数字要存储在程序里,不加思索int.那为什么java要弄一个Integer类型出来?有什么用?怎么用?差别在哪儿?度娘说java提供了两种数据类型,一种是值类型,一种 ...

  3. Linux安装jdk-8u161-linux-x64

    最基本的操作,有一些细节需要处理,这次主要列出来步骤,其实步骤在网上一搜就有,这里只是根据个人的操作进行一些整合和注意事项的提醒罢了. 1.卸载原先的java jdk 这一步的目的是,很多Linux版 ...

  4. 关于indexof和substring经常记不住的点

    indexof 找到的字符位置是 字符串从0位开始算起的. lastIndexOf也一样,http://localhost:8080/aaa,的lastIndexOf("/")是2 ...

  5. 2019微软Power BI 每月功能更新系列——Power BI 4月版本功能完整解读

    Power BI4月份的更新对整个产品进行了重大更新.此版本增加了基于DAX表达式定义视觉效果标题和按钮URL的功能.本月Power BI也新增了许多新的连接器,现在可以使用几种预览连接器,包括Pow ...

  6. idea 里自动下载私服jar一直不能下载下来

    idea 里自动下载私服jar一直不能下载下来,只生成了.lastUpdated文件,检查了setting.xml文件.网络,私服,均无问题,在idea中打开Terminal窗口,在所要更新的pom. ...

  7. (转)es6中object.create()和object.assign()

    今天学习javascript面向对象,在学习Obejct方法时了解到create方法,偶像想起之前使用的assign方法,顺带查找一番,感觉这篇博客讲解详细,遂转载. 先简单提一下装饰器函数,许多面向 ...

  8. android 事件绑定

    layout布局设计了页面,如何绑定事件,与用户进行交互需要在Activity中进行处理. 下面的layout,有两个按钮. <LinearLayout android:layout_width ...

  9. 利用iftop找出是谁占用了带宽

    第一步:安装EPEL源    yum install epel-release 第二部:安装iftop         yum install iftop 然后用iftop命令即可查看相关信息 ift ...

  10. Vue慕课网音乐项目随手记--node代理及数据抓取

    1.抓取数据 链接   https://y.qq.com/portal/playlist.html Parameters 通过上图能看到,qq音乐通过设置了refer和host来保护接口. 那么怎么才 ...