ECMAScript6-let与const命令详解

着力用法

const也是用来声称变量,可是申明的是一个只读的常量。一旦评释,常量的值就不可能改变。

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

浏览器结果图片 1

下边代码评释改变常量的值会报错。

const宣示的变量不得变动值,那代表,const如若表明变量,就必须立刻开端化,不可能留到今后赋值。

const foo;
// SyntaxError: Missing initializer in const declaration

浏览器结果图片 2

上面代码表示,对于const来说,只注解不赋值,就会报错。

const的作用域与let一声令下相同:只在申明所在的块级功效域内一蹴而就。

if (true) {
  const MAX = 5;
}

MAX // Uncaught ReferenceError: MAX is not defined

浏览器结果图片 3

const指令注解的常量也是不升级,同样存在暂时性死区,只好在表明的地点前面使用。

if (true) {
  console.log(MAX); // ReferenceError
  const MAX = 5;
}

浏览器结果图片 4

上边代码在常量MAX宣示从前就调用,结果报错。

const阐明的常量,也与let一样不可重复声明。

var message = "Hello!";
let age = 25;

// 以下两行都会报错
const message = "Goodbye!";
const age = 30;

浏览器结果

图片 5

图片 6

对于复合类型的变量,变量名不指向数据,而是指向数据所在的地方。
const命令只是有限匡助变量名指向的地方不变,并不保障该地址的数目不变,所以,将一个目的评释为常量必须更加小心。

const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError:  Assignment to constant variable.

浏览器结果
图片 7

上边代码中,常量foo储存的是一个地址,这么些地址指向一个对象。不可变的只是以此地点,即不能把foo本着另一个地方,但目的自我是可变的,所以照旧得以为其足够新属性。

骨干用法

参考

let 和 const 命令

块级效率域与函数申明

  • 允许在块级成效域内申明函数。
  • 函数评释类似于var,即会进步到全局功用域或函数成效域的尾部。
  • 并且,函数申明还会升级到所在的块级成效域的头顶。

块级成效域

块级成效域,没有重回值。

全局对象的质量

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

window.a = 1;
a //1

a = 2;
window.a //2

浏览器结果图片 8

地点代码中,全局对象的特性赋值与全局变量的赋值,是一样件事。(对于Node.js来说,这一条只对REPL环境适用,模块环境中,全局变量必须出示表明成global对象的习性。)那种规定被市委JavaScript语言的一大标题。因为很不难不知不觉就创设了全局变量。
ES6为了改变那一点,一方面规定,为了维持包容性,var命令和function命令表明的全局变量,如故是全局对象的习性;另一方面规定,let命令、const命令和class指令评释的全局变量,不属于全局对象的性质。也就是说,从ES6开端,全局变量将稳步与顶层对象的特性脱钩。

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

let b = 1;
window.b // undefined

浏览器结果图片 9

地点代码中,全局变量avar命令表明,所以它是大局对象的属性;全局变量blet一声令下申明,所以它不是大局对象的属性,重临undefined

暂行死区(TDZ)

如果块级功能域内设有let命令,它所申明的变量就“绑定”(binding)这么些区域,不再受外部的震慑。

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}

浏览器中的结果图片 10

地点代码中,存在全局变量tmp,但是块级作用域内let又声称了一个片段变量tmp,导致后者绑定这几个块级成效域,所以在let扬言变量前,对tmp赋值会报错。

ES6明确规定,若是区块中存在letconst命令,这么些区块对那几个命令注明的变量,从一开始就形成了封门效用域。凡是在申明之前就动用那几个变量,就会报错。

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

if (true) {
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ结束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
} 

浏览器结果
图片 11
图片 12

图片 13

地方代码中,在let指令申明变量tmp事先,都属于变量tmp的“死区”。

“暂时性死区”也代表typeof不再是一个任何平安的操作。

typeof x; // ReferenceError
let x;

浏览器结果图片 14

地方代码中,变量x使用let一声令下注脚,所以在申明以前,都属于x的“死区”,只要用到该变量就会报错。因而,typeof运作时就会抛出一个ReferenceError

作为相比较,尽管一个变量根本未曾被声称,使用typeof相反不会报错。

typeof undeclared_variable // "undefined"

浏览器结果图片 15

上面代码中,undeclared_variable是一个不设有的变量名,结果再次来到“undefined”。所以,在未曾let之前,typeof运算符是漫天安全的,永远不会报错。现在那点不树立了。那样的布置是为着让我们养成非凡的编程习惯,变量一定要在宣称之后选用,否则就报错。

有些“死区”相比隐蔽,不太不难发觉。

function bar(x = y, y = 2) {
  return [x, y];
}

bar(); // 报错

浏览器结果图片 16

地点代码中,调用bar函数之所以报错(某些完结可能不报错),是因为参数x默认值等于另一个参数y,而此时y还没有声明,属于”死区“。若是y的默许值是x,就不会报错,因为那时候x已经宣示了。

function bar(x = 2, y = x) {
  return [x, y];
}
bar(); // [2, 2]

浏览器结果图片 17

除此以外,下边的代码也会报错,与var的一言一动分化。

// 不报错
var x = x;

// 报错
let x = x;
// ReferenceError: x is not defined

浏览器结果图片 18

地点代码报错,也是因为临时死区。使用let申明变量时,只要变量在还不曾申明已毕前应用,就会报错。上面那行就属于那个情况,在变量x的宣示语句还没有履行到位前,就去取x的值,导致报错”x
未定义“。

ES6
规定临时死区和letconst语句不出新变量提高,紧如果为着削减运作时不当,防止在变量阐明前就利用那些变量,从而导致预期之外的一举一动。那样的错误在
ES5 是很宽泛的,现在有了那种规定,幸免此类错误就很简单了。

一句话来说,暂时性死区的武当山真面目就是,只要一进入当前效率域,所要使用的变量就已经存在了,可是不得获取,唯有等到表明变量的那一行代码出现,才足以获得和采纳该变量。

let命令介绍

let指令,用来声称变量。它的用法类似于var,
可是所申明的变量,只在let一声令下所在的代码块内有效。
浏览器中的结果 图片 19

位置代码在代码块之中,分别用letvar宣示了四个变量。然后在代码块之外调用那三个变量,结果let声称的变量报错,var宣示的变量重回了科学的值。那声明,let声称的变量只在它所在的代码块有效。下面代码在代码块之中,分别用letvar注明了三个变量。然后在代码块之外调用那五个变量,结果let宣示的变量报错,var扬言的变量重返了正确的值。这标志,let宣称的变量只在它所在的代码块有效。

let 与 const 相同点和区分

1:let指令用来声称变量,用法类似于var,不过所表明的变量。
const声称一个只读的常量,一旦讲明,常量的值就不可能更改。
const担保的是内存地址不得改变。常量(内存地址保存的是值),复合类型的数据(内存地址保存的是指针)
2:两者都不设有变量提高。
3:两者都有短时死区(TDZ)。
4:两者都不允许再度申明。
5:两者为JavaScript新增了块级成效域。两者功用域,只在阐明所在的块级效用域有效。

ES6的块级功能域

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

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

浏览器结果图片 20

地点的函数有五个代码块,都声称了变量n,运行后输出5。那代表外层代码块不受内层代码块的熏陶。要是三遍都采用var概念变量n,最终输出的值才是10。

浏览器结果图片 21

ES6 允许块级效用域的人身自由嵌套。

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

地方代码应用了一个五层的块级功能域。外层效用域不能读取内层功用域的变量。

{{{{
  {let insane = 'Hello World'}
  console.log(insane); // 报错
}}}};

浏览器结果图片 22

内层成效域可以定义外层成效域的同名变量。

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

块级功效域的产出,实际上使得得到广泛应用的马上实施函数表明式(IIFE)不再需求了。

// IIFE 写法
(function () {
  var tmp = ...;
  ...
}());

// 块级作用域写法
{
  let tmp = ...;
  ...
}

let实用举例

for循环的计数器

for (let i =0; i < 10; i++) {}
console.log(i) // ReferenceError: i is not defined

浏览器中的结果图片 23

地点代码中,计数器i只在for循环体内一蹴而就,在循环体外引用就会报错。

上面的代码固然利用var, 最终输出的是10

var  a  =   [];
for  (var  i  =  0;  i  <  10;  i++)  {
  a[i]  =   function ()  {
    console.log(i);
  };
}
a[6](); // 10

浏览器中的结果 图片 24

地方代码中,变量ivar命令注脚的,在全局范围内都灵验,所以全局惟有一个变量i。每两遍巡回,变量i的值都会爆发变动,而循环内被赋给数组a的函数内部的console.log(i),里面的i针对的就是全局的i。也就是说,所有数组a的积极分子内部的i,指向的都是同一个i,导致运行时输出的是最终一轮的i的值,也就是10

如若选用let,
阐明的变量仅在块级效能域内有效,最后输出的是6

var  a  =   [];
for  (var  i  =  0;  i  <  10;  i++)  {
  a[i]  =   function ()  {
    console.log(i);
  };
}
a[6](); // 6

浏览器结果图片 25

上边代码中,变量ilet声明的,当前的i只在本轮循环有效,所以每一遍巡回的i实际都是一个新的变量,所以最终输出的是6。你可能会问,要是每一轮循环的变量i都是重复注解的,那它怎么领悟上一轮循环的值,从而统计出本轮循环的值?那是因为
JavaScript
引擎内部会记住上一轮循环的值,开始化本轮的变量i时,就在上一轮循环的基础上进展测算。

另外,for循环还有一个尤其之处,就是设置循环变量的那部分是一个父成效域,而循环体内部是一个独立的子效用域。

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
// abc
// abc
// abc

浏览器结果 图片 26

位置代码不易运行,输出了3次abc。这表明函数内部的变量i与循环变量i不在同一个功效域,有独家独立的功效域。

先总结

先计算区别,再各自讲演

不设有变量进步

var命令会爆发变量提升情形,即变量可以在声明从前运用,值为undefined。那种场馆多有点少是有些奇怪的,根据一般的逻辑,变量应该在声明语句之后才足以利用。

为了校订那种景观,let一声令下改变了语法行为,它所阐明的变量一定要在宣称后接纳,否则报错。

// var 的情况
console.log(foo); // 输出undefined
var foo = 2;

// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2; 

浏览器结果图片 27

上面代码中,变量foovar一声令下声明,会发生变量提高,即脚本开首运行时,变量foo早就存在了,可是从未值,所以会输出undefined。变量barlet一声令下评释,不会发生变量进步。那意味在申明它前面,变量bar是不存在的,那时如若用到它,就会抛出一个张冠李戴。

前言

《ECMAScript入门》是一本开源的JavaScript语言教程,周详介绍ECMAScript6新引入的语法特性。
let和const命令,是首先章开始介绍,也是相比基础的文化。我在读书之后,把它总括记录下来,以便自己从此复习查看。
以下代码,于Chrome57 DevTools运行
node为6.3版本

不允许再一次声明

let不相同意在同等效果域内,重复申明同一个变量。
浏览器结果
图片 28

图片 29

图片 30

为此,不能在函数内部重新评释参数。

function func(arg) {
  let arg; //在chrome浏览器下,不报错。使用node执行,会报错。
}

function func(arg) {
  {
    let arg;//在chrome浏览器下,不报错。使用node执行,也不报错。
  }
}

浏览器环境和node执行情况

图片 31

图片 32

怎么须要块级效率域?

ES5 只有全局效能域和函数成效域,没有块级功用域,那带来很多不客观的光景。

首先种情景,内层变量可能会覆盖外层变量。

var tmp = new Date();

function f() {
  console.log(tmp);
  if (false) {
    var tmp = 'hello world';
  }
}

f(); // undefined

浏览器结果图片 33

上面代码的原意是,if代码块的外表使用外层的tmp变量,内部使用内层的tmp变量。但是,函数f施行后,输出结果为undefined,原因在于变量提高,导致内层的tmp变量覆盖了外围的tmp变量。

其次种情况,用来计数的循环变量败露为全局变量。

var s = 'hello';

for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}

console.log(i); // 5

浏览器结果图片 34

上边代码中,变量i只用来决定循环,可是循环甘休后,它并从未熄灭,走漏成了全局变量。

跨模块常量

下面说过,const表明的常量只在当下代码块有效。固然想设置跨模块的常量,可以运用上面的写法。

// constants.js 模块
export const A = 1;
export const B = 3;
export const C = 4;

//test1.js 模块
import * as constans 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

那里实在选择了Module(模块)的导入导出功能。未来会讲到。

const命令