本系列是在平时阅读、学习、实际项目中有关于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. 初学node遇到的问题(慢慢补充)

    一.看到菜鸟教程的Web模块运行client.js的时候遇到报错: E:\node\server>node client.js events.js:72throw er; // Unhandle ...

  2. react初学之render返回加括号的问题

    刚在学习react的初始阶段,跑了一段代码 var  Mydom = React.createClass({ render:function(){ return <div> <inp ...

  3. 同一个服务器部署两个Tomcat并用Nginx实现反向代理

    需求场景:由于服务器只有80端口可供外网访问,但需要部署两台tomcat来运行两个不同的项目,所以选择了nginx做反向代理 一个upstream tomcat_server对应一个  locatio ...

  4. php 品牌全车零件订购平台( 带采集数据 及 账号自动登陆【已绕过https证书加密】,php源码 ,QQ: 876635409 )

    php捷豹路虎 品牌全车零件订购平台  ( 带采集数据 及 账号自动登陆[已绕过https证书加密],php源码 ,QQ: 876635409 [由于咨询用户太多,请备注:汽车配件]) 一.php+m ...

  5. python 发送163邮件

    可能还需要使用 邮箱第三方客户端的授权码. 网易163免费邮箱相关服务器信息 from email import encoders from email.header import Header fr ...

  6. pycharm的快捷键

    一.编辑(Editing) Ctrl+Space 基本的代码完成(类.方法.属性) Ctrl+Alt+Space 快速导入任意类 Ctrl+Shift+Enter 语句完成 Ctrl+P 参数信息(在 ...

  7. SDL2.0.9源码分析

    1.首先 2.0.9编译so出来跟一直不一样,多了个hidapi  库 2.跟Tocy的对比,SDLmain 执行的路径不一样,一个是/src/main/android/SDL_android_mai ...

  8. React Native开发的一种代码规范:Eslint + FlowType

    [这篇随笔记录的很简单,没有涉及具体的Eslint规则解释以及FlowType的类型说明和使用等,只是链接了所需的若干文档] js开发很舒服,但是代码一多起来就参差不齐,难以阅读了.所以加上一些代码规 ...

  9. Oracle深入学习

    一.甲骨文公司介绍 甲骨文公司,是全球最大的企业级软件公司,总部位于美国加利福尼亚州的红木滩.1989年正式进入中国市场. 2013年,甲骨文已超越 IBM ,成为继 Microsoft 后全球第二大 ...

  10. 【mysql】Mha实现高可用数据库架构

    MySQL高可用平台需要达到的目标有以下几点: 1.数据一致性保证这个是最基本的同时也是前提,如果主备的数据的不一致,那么切换就无法进行,当然这里的一致性也是一个相对的,但是要做到最终一致性. 2.故 ...