ES6初体验——(1)let和const命令

  前言:

  参考书籍:ECMAScript 6 入门    链接: http://es6.ruanyifeng.com/  阮一峰老师,书中示例详尽,此处只做简单梳理和理解,仅作督促自己学习使用

  1、let命令,用来声明变量。用法类似于 var,但是所声明的变量,只在let命令所在的代码块内有效。而ES5中,是没有块级作用域的概念的。

var a = [];
for (var i = 0; i < 10; i++) {//i由var定义,属于全局变量,i只定义了一次,每次循环,i的值递增,for循环执行完毕,i的值变成10,所以输出10
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10
var a = [];
for (let i = 0; i < 10; i++) {//i由let定义,只在当轮循环有效,即每一轮循环的i都是重新声明的,
  a[i] = function () {        //由于JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算
    console.log(i);
  };
}
a[6](); // 6
a[3](); // 3

  for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

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

  var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined,(这是因为预解析的缘故)。但是由let声明的变量则不存在变量提升现象,即不被预解析,它要求变量必须在声明语句之后才可以使用,否则会抛出错误。

console.log(foo); // Uncaught ReferenceError: foo is not defined    始终没有声明过就直接使用会报错
console.log(foo); // 输出undefined         先使用再声明,输出undefined(由var定义的变量)
var foo = 2;
foo = 2;
console.log(foo); //2     此处没有报错,反而输出了2,是因为此处的foo没有由var声明,则被默认为window下的一个属性
console.log(window.foo);//2

  暂时性死区:只要块级作用域内存在let命令(不管它的位置在前在后),它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响(外部是否定义过这个变量已经和这个区域无关了)。一旦在这个区域内,let声明不是在最前面,即先使用后才由let声明,则会报错。

if (true) {
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError      //事实上,在代码执行的时候,如果报错了,会阻塞后面的语句执行,所以,把这两句注释掉,后面的语句才会正常执行

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

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

  let不允许在相同作用域内,重复声明同一个变量。因此,不能在函数内部重新声明参数。

  2、块级作用域

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

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

  第二种场景,用来计数的循环变量泄露为全局变量,循环变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。

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

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

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

  块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)(即匿名函数自执行)不再必要了。(原意是为了不定义全局变量,所以放在一个匿名函数自执行里面)。

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

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

  3、const命令

  const声明一个只读的常量,在声明时,要立即初始化该变量,即给该变量赋值,否则会报错。由const声明的变量,一旦声明,其值就不能改变。

  在刚刚探讨的其他方面,const与let是相同的。

  本质:const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针。如果真的想将对象冻结,应该使用Object.freeze方法。

const foo = {};

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

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only

  4、顶层对象的属性

  顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。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

  

  

  

  

  

posted @ 2017-11-25 21:13  近距离  阅读(282)  评论(0编辑  收藏  举报