详细学习链接: http://es6.ruanyifeng.com/#docs/let

let命令

基本用法

ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

  1. 'use strict';
  2. {
  3. let a = 10;
  4. var b = 1;
  5. }
  6. a // 报错,ReferenceError: a is not defined.
  7. b // 1

不存在变量提升

let不像var那样会发生“变量提升”现象。所以,变量一定要在声明后使用,否则报错。

  1. 'use strict';
  2. console.log(foo); // 输出undefined
  3. console.log(bar); // 报错,ReferenceError: bar is not defined.
  4. var foo = 2;
  5. let bar = 2;

暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称TDZ)。

  1. 'use strict';
  2. if (true) {
  3. // TDZ开始
  4. tmp = 'abc'; // 报错,ReferenceError: tmp is not defined.
  5. console.log(tmp); // 报错,ReferenceError: tmp is not defined.
  6. let tmp; // TDZ结束
  7. console.log(tmp); // undefined
  8. tmp = 123;
  9. console.log(tmp); // 123
  10. }

不允许重复声明

let不允许在相同作用域内,重复声明同一个变量。

  1. 'use strict';
  2. // 报错,TypeError: Duplicate declaration "a".
  3. function test() {
  4. let a = 10;
  5. var a = 1;
  6. }
  7. // 报错,TypeError: Duplicate declaration "a".
  8. function test() {
  9. let a = 10;
  10. let a = 1;
  11. }

因此,不能在函数内部重新声明参数。

  1. 'use strict';
  2. function func(arg) {
  3. let arg; // 报错,TypeError: Duplicate declaration "arg"
  4. }
  5. function func(arg) {
  6. {
  7. let arg; // 不报错
  8. }
  9. }

块级作用域

为什么需要块级作用域?

ES5只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。

第一种场景,内层变量可能会覆盖外层变量。

  1. 'use strict';
  2. var tmp = new Date();
  3. function f(){
  4. console.log(tmp);
  5. if (false){
  6. var tmp = "hello world";
  7. }
  8. }
  9. f() // undefined

上面代码中,函数f执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。

第二种场景,用来计数的循环变量泄露为全局变量。

  1. 'use strict';
  2. var s = 'hello';
  3. for (var i = 0; i < s.length; i++){
  4. console.log(s[i]);
  5. }
  6. console.log(i); // 5

上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。

ES6的块级作用域

let实际上为JavaScript新增了块级作用域。

  1. 'use strict';
  2. function f1() {
  3. let n = 5;
  4. if (true) {
  5. let n = 10;
  6. }
  7. console.log(n); // 5
  8. }

上面的函数有两个代码块,都声明了变量n,运行后输出5。这表示外层代码块不受内层代码块的影响。如果使用var定义变量n,最后输出的值就是10。

允许块级作用域的任意嵌套

  1. 'use strict';
  2. {{{{{
  3. let insane = 'Hello World'
  4. }}}}}

外层作用域无法读取内层作用域的变量

  1. 'use strict';
  2. {{{{
  3. {
  4. let insane = 'Hello World'
  5. }
  6. console.log(insane); // 报错,ReferenceError: insane is not defined.
  7. }}}}

内层作用域可以定义外层作用域的同名变量

  1. 'use strict';
  2. {{{{
  3. let insane = 'outside';
  4. {
  5. let insane = 'inside';
  6. console.log(insane); // inside
  7. }
  8. console.log(insane); // outside
  9. }}}}

取代立即执行匿名函数(IIFE)

  1. 'use strict';
  2. // IIFE写法
  3. (function () {
  4. var tmp = 'hello world!';
  5. }());
  6. console.log(tmp); // 报错,ReferenceError: tmp is not defined.
  7. // 块级作用域写法
  8. {
  9. let tmp = 'hello world!';
  10. }
  11. console.log(tmp); // 报错,ReferenceError: tmp is not defined.

函数本身的作用域,在其所在的块级作用域之内

  1. 'use strict';
  2. function f() {
  3. console.log('outside');
  4. }
  5. (function () {
  6. if(false) {
  7. // 重复声明一次函数f
  8. function f() {
  9. console.log('inside');
  10. }
  11. }
  12. f();
  13. }());

上面代码在ES5中运行,会得到“inside”,但是在ES6中运行,会得到“outside!”。这是因为ES5存在函数提升,不管会不会进入 if代码块,函数声明都会提升到当前作用域的顶部,得到执行;

而ES6支持块级作用域,不管会不会进入if代码块,其内部声明的函数皆不会影响到作用域的外部。

块级作用域外部,无法调用块级作用域内部定义的函数

  1. 'use strict';
  2. let f;
  3. {
  4. let a = 'secret';
  5. let b = 'publish';
  6. f = function () {
  7. return a;
  8. };
  9. function p() {
  10. return b;
  11. }
  12. }
  13. f(); // "secret"
  14. p(); // 报错,ReferenceError: p is not defined.

其它

ES5的严格模式规定,函数只能在顶层作用域和函数内声明,其他情况(比如if代码块、循环代码块)的声明都会报错。

ES6由于引入了块级作用域,这种情况可以理解成函数在块级作用域内声明,因此不报错,但是构成区块的大括号不能少,否则还是会报错。

  1. 'use strict';
  2. // ES5
  3. 'use strict';
  4. if (true) {
  5. function f() {} // 报错
  6. }
  7. // ES6
  8. // 不报错
  9. 'use strict';
  10. if (true) {
  11. function f() {}
  12. }
  13. // 报错,SyntaxError: Unexpected token.
  14. 'use strict';
  15. if (true)
  16. function f() {}

const命令

声明只读的常量

  1. 'use strict';
  2. const PI = 3.1415;
  3. PI // 3.1415
  4. PI = 3; // 报错,TypeError: "PI" is read-only.

声明时必须立即初始化

  1. 'use strict';
  2. const foo; // 报错,SyntaxError: missing = in const declaration.

与let命令相同

  • 只在声明所在的块级作用域内有效
  • 声明不提升
  • 存在暂时性死区,只能在声明的位置后面使用
  • 不可重复声明

只保证变量名指向的地址不变,并不保证该地址的数据不变

对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个对象声明为常量必须非常小心。

  1. 'use strict';
  2. const foo = {};
  3. foo.prop = 123;
  4. foo.prop // 123
  5. foo = {} // TypeError: "foo" is read-only

上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。

跨模块常量

const声明的常量只在当前代码块有效。如果想设置跨模块的常量,可以采用下面的写法。

  1. // constants.js 模块
  2. export const A = 1;
  3. export const B = 3;
  4. export const C = 4;
  5. // test1.js 模块
  6. import * as constants from './constants';
  7. console.log(constants.A); // 1
  8. console.log(constants.B); // 3
  9. // test2.js 模块
  10. import {A, B} from './constants';
  11. console.log(A); // 1
  12. console.log(B); // 3

其它

ES5只有两种声明变量的方法:var命令和function命令。ES6除了添加let和const命令,后面章节还会提到,另外两种声明变量的方法:import命令和class命令。所以,ES6一共有6种声明变量的方法。

全局对象的属性

全局对象是最顶层的对象,在浏览器环境指的是window对象,在Node.js指的是global对象。ES5之中,全局对象的属性与全局变量是等价的。

  1. window.a = 1;
  2. a // 1
  3. a = 2;
  4. window.a // 2

上面代码中,全局对象的属性赋值与全局变量的赋值,是同一件事。(对于Node来说,这一条只对REPL环境适用,模块环境之中,全局变量必须显式声明成global对象的属性。)

这种规定被视为JavaScript语言的一大问题,因为很容易不知不觉就创建了全局变量。

ES6为了改变这一点,一方面规定,var命令和function命令声明的全局变量,依旧是全局对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于全局对象的属性。

  1. var a = 1;
  2. // 如果在Node的REPL环境,可以写成global.a
  3. // 或者采用通用方法,写成this.a
  4. window.a // 1
  5. let b = 1;
  6. window.b // undefined

上面代码中,全局变量a由var命令声明,所以它是全局对象的属性;全局变量b由let命令声明,所以它不是全局对象的属性,返回undefined。

ECMAScript 6入门 - let和const命令的更多相关文章

  1. ECMAScript 6 之 let 和 const 命令

    1.let基本用法 1.1.声明变量 let声明的变量只在它所在的代码块有效. 1.2.不存在变量提升 var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined: let命令 ...

  2. ECMAScript6 入门-let与const命令

    块级作用域 1:let命令声明的变量只在let命令所在的代码块有效--简而言之 大括号既是代码块,也就是说存在块级作用域了. { let a =10; var b =1; } a // Referen ...

  3. ES6入门——let和const命令

    let和const命令 1.let命令 用法:类似于var,用来声明一个变量,区别是所声明的变量只在let命令所在的代码块内有效. let命令很适合用在for循环的计数器中,因为let声明的变量仅在作 ...

  4. es6语法入门let 和 const 命令

    let块级作用域 { let a = 10; var b = 1; } a // ReferenceError: a is not defined. b for循环的计数器,就很合适使用let命令(防 ...

  5. ECMAScript 6 入门

    ECMAScript 6 入门 东西真多哇 http://es6.ruanyifeng.com/#docs/module 目录 前言 ECMAScript 6简介 let和const命令 变量的解构赋 ...

  6. ES6入门之let和const命令

    前言 大家好,我是一只流浪的kk,当你看到这边博客的时候,说明你已经进入了ES6学习的领域了,从本篇博客开始,我将会将自己学习到ES6的相关知识进行整理,方便大家参考和学习,那么我将带你进入第一节的内 ...

  7. ES6 入门系列 - let 和 const 命令

    let命令 基本用法 ES6新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. { let a = ; ; } a // ReferenceEr ...

  8. ECMAScript 6 第一天 let和const命令

    ES6新增声明变量的方法let命令,const命令. (ES5只有两种声明变量的方法:var 命令和 function 命令.) let命令,用来声明变量. 与var声明变量不同于: 1.  let声 ...

  9. ECMAScript 6 入门学习笔记(一)——let和const

    一.let ①声明变量 let a = 1: ②只在所在代码块内有效,不影响块以外 ③不存在变量提升(不能先用后声明) ④暂时性死区 let声明的变量“绑定”这个区域,不受外部影响. let声明之前, ...

随机推荐

  1. Scrapy学习教程

    http://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html 在线学习教程: http://learnpythonthehardway ...

  2. 数据库查询优化器的艺术:原理解析与SQL性能优化

    数据库查询优化器的艺术 作者:李海翔 Oracle公司MySQL全球开发团队.资深专家 简单的浏览了一遍,由于以前没有接触过SQL优化这些知识,读起来还是非常吃力的,不过收获还是很大的. 作者通过对M ...

  3. IIS与ApplicationPool重启检测自动化解决方案

    IIS与ApplicationPool重启检测自动化解决方案 Friday, November 28, 2014 DA Hotfix Automatic IIS & Application P ...

  4. InputStream和Reader区别

    InputStream,OutputStream  前者为字节输入流,后者为字节输出流.Reader   Writer  前者为字符输入流,后者为字符输出流. 四个均为抽象类.fileInputStr ...

  5. WinMain函数详解(转载)

    略加增添与修改! 工具:VC++6.0       系统:win7 64位 在Windows应用程序中,我们可以认为 WinMain() 函数是程序的入口,WinMain()的原型如下: int WI ...

  6. mysqli报错(HY000/2002)

    Warning: mysqli::mysqli(): (HY000/2002): 没有那个文件或目录 解决:把localhost 换成127.0.0.1就好了.

  7. CodeForces 651B Beautiful Paintings 贪心

    A. Joysticks time limit per test 1 second memory limit per test 256 megabytes input standard input o ...

  8. Linux企业运维高效技巧心得及分享

    本博文出自51CTO博主 吴光科 的博客,有任何问题请进入博主页面互动讨论! 博文地址:http://wgkgood.blog.51cto.com/1192594/1641247 随着Linux在企业 ...

  9. 高通Android平台硬件调试之Camera篇

    之前一段时间有幸在高通android平台上调试2款camera sensor,一款是OV的5M YUV sensor,支持jpeg out,同时也支持AF,调试比较比较简单,因为别的项目已经在使用了, ...

  10. ADC驱动器或差分放大器设计指南

    作为应用工程师,我们经常遇到各种有关差分输入型高速模数转换器(ADC)的驱动问题.事实上,选择正确的ADC驱动器和配置极具挑战性.为了使鲁棒性ADC电路设计多少容易些,我们汇编了一套通用“路障”及解决 ...