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

let命令

基本用法

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

'use strict';
{
let a = 10;
var b = 1;
} a // 报错,ReferenceError: a is not defined.
b // 1

不存在变量提升

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

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

暂时性死区

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

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

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

'use strict';
if (true) {
// TDZ开始
tmp = 'abc'; // 报错,ReferenceError: tmp is not defined.
console.log(tmp); // 报错,ReferenceError: tmp is not defined. let tmp; // TDZ结束
console.log(tmp); // undefined tmp = 123;
console.log(tmp); // 123
}

不允许重复声明

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

'use strict';
// 报错,TypeError: Duplicate declaration "a".
function test() {
let a = 10;
var a = 1;
} // 报错,TypeError: Duplicate declaration "a".
function test() {
let a = 10;
let a = 1;
}

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

'use strict';
function func(arg) {
let arg; // 报错,TypeError: Duplicate declaration "arg"
} function func(arg) {
{
let arg; // 不报错
}
}

块级作用域

为什么需要块级作用域?

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

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

'use strict';
var tmp = new Date(); function f(){
console.log(tmp);
if (false){
var tmp = "hello world";
}
} f() // undefined

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

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

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

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

ES6的块级作用域

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

'use strict';
function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}

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

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

'use strict';
{{{{{
let insane = 'Hello World'
}}}}}

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

'use strict';
{{{{
{
let insane = 'Hello World'
}
console.log(insane); // 报错,ReferenceError: insane is not defined.
}}}}

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

'use strict';
{{{{
let insane = 'outside';
{
let insane = 'inside';
console.log(insane); // inside
}
console.log(insane); // outside
}}}}

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

'use strict';
// IIFE写法
(function () {
var tmp = 'hello world!';
}());
console.log(tmp); // 报错,ReferenceError: tmp is not defined. // 块级作用域写法
{
let tmp = 'hello world!';
}
console.log(tmp); // 报错,ReferenceError: tmp is not defined.

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

'use strict';
function f() {
console.log('outside');
}
(function () {
if(false) {
// 重复声明一次函数f
function f() {
console.log('inside');
}
} f();
}());

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

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

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

'use strict';
let f;
{
let a = 'secret';
let b = 'publish';
f = function () {
return a;
}; function p() {
return b;
}
}
f(); // "secret"
p(); // 报错,ReferenceError: p is not defined.

其它

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

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

'use strict';
// ES5
'use strict';
if (true) {
function f() {} // 报错
} // ES6
// 不报错
'use strict';
if (true) {
function f() {}
} // 报错,SyntaxError: Unexpected token.
'use strict';
if (true)
function f() {}

const命令

声明只读的常量

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

声明时必须立即初始化

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

与let命令相同

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

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

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

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

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

跨模块常量

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

// constants.js 模块
export const A = 1;
export const B = 3;
export const C = 4; // test1.js 模块
import * as constants from './constants';
console.log(constants.A); // 1
console.log(constants.B); // 3 // test2.js 模块
import {A, B} from './constants';
console.log(A); // 1
console.log(B); // 3

其它

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

全局对象的属性

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

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

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

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

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

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

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

走进EC6的let和const命令的更多相关文章

  1. es6学习笔记(1) let和const命令详解

    let和const命令: Es6新增了let命令,声明变量,但与var不一样的,只在let命令所在的代码块内有效(如for循环之外let声明的变量就不再有效).并且let不像var那样会发生" ...

  2. let和const命令//////////////////////z

    let和const命令 let命令 块级作用域 const命令 全局对象的属性 let命令 基本用法 ES6新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的 ...

  3. ES6之let(理解闭包)和const命令

    ES6之let(理解闭包)和const命令 最近做项目的过程中,使用到了ES6,因为之前很少接触,所以使用起来还不够熟悉.因此购买了阮一峰老师的ES6标准入门,在此感谢阮一峰老师的著作. 我们知道,E ...

  4. ECMAScript 6入门 - let和const命令

    详细学习链接: http://es6.ruanyifeng.com/#docs/let let命令 基本用法 ES6新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命 ...

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

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

  6. ES6 之 let和const命令 Symbol Promise对象

    ECMAScript 6入门 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了. (2016年6月,发布了小幅修订的<ECMASc ...

  7. ECMAScript6-let和const命令

    ▓▓▓▓▓▓ 大致介绍 ES6是下一代的JavaScript语言的标准,目标是让JavaScript可以用来编写大型的复杂程序,成为企业级开发语言,要查看浏览器对ES6的支持程度可以用阮一峰大佬写的工 ...

  8. ECMAScript6-let与const命令详解

    前言 <ECMAScript入门>是一本开源的JavaScript语言教程,全面介绍ECMAScript6新引入的语法特性. let和const命令,是第一章开始介绍,也是比较基础的知识. ...

  9. let和const命令

    let命令 1.let用来声明变量,类似于var,但只在代码块内有效. { let a = 1; var b = 2; } console.log(a); //a is not defined con ...

随机推荐

  1. What is Mocking?

    Mocking is primarily used in unit testing. An object under test may have dependencies on other (comp ...

  2. Google Xpath Helper

    下载方法: 1. 访问http://chrome-extension-downloader.com/ 2. 把https://chrome.google.com/webstore/detail/xpa ...

  3. apache 返回的状态码304

    博客转载:http://baike.baidu.com/link?url=jhw62dpK66WD7EQFKWEhVQs_jPeFKIUegnA6 如果客户端发送了一个带条件的GET 请求且该请求已被 ...

  4. C++之类成员所占内存大小问题总结

    1.空类所占字节数为1,可见代码如下 #include <iostream> using namespace std; class Parent { }; class Child:publ ...

  5. 2017.4.18 静态代码分析工具sonarqube+sonar-runner的安装配置及使用

    配置成功后的代码分析页面: 可以看到对复杂度.语法使用.重复度等等都做了分析,具体到了每一个方法和每一句代码. 四种使用方式: sonarqube + sonar-runner sonarqube + ...

  6. HTML5 Canvas 动态勾画等速螺线

    等速螺线亦称阿基米德螺线,得名于公元前三世纪希腊数学家阿基米德.阿基米德螺线是一个点匀速离开一个固定点的同时又以固定的角速度绕该固定点转动而产生的轨迹.在此向这位古代最伟大的数学家致敬.用Canvus ...

  7. Laravel之Elixir

    一.Elixir安装和设置 1.安装node.js 2.安装Gulp 作为全局NPM 包 npm install --global gulp 3.最后,在新安装的Laravel 根目录下,你会发现有一 ...

  8. shell2

    例一:数组选择 #!/bin/sh menu=("Apple" "Grape" "Orange") PS3="喜欢哪个" ...

  9. 数据库设计--数据流图(DFD)

    1.数据流图的定义 数据流图(DFD)是结构化分析方法中使用的工具,它以图形的方式描绘数据在系统中流动和处理的过程, 因为它仅仅反映系统必须完毕的逻辑功能.所以它是一种功能模型. 在结构化开发方法中. ...

  10. [LeetCode] Combinations——递归

    Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. For exampl ...