ES6入门教程之let、const的使用方法

前端之家收集整理的这篇文章主要介绍了ES6入门教程之let、const的使用方法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

主要给大家介绍了关于ES6入门教程之let、const使用的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用ES6具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

一、前提

解决ES5中只有全局作用域和函数作用域,没有块级作用域而带来的不合理的场景。

let基本用法

用法和var 一样,只是let声明的变量只有在let命令所在的代码块有效

  1. {
  2.  let a = 10;
  3.  var b = 1;
  4. }
  5.  
  6. // ReferenceError: a is not defined.
  7. // 1

可以看出var 声明的变量在代码块之外也是可以调用,而let声明的则调用报错。所以let 声明只在它声明的当前代码块中才能调用

变量提升

在使用 var 的时候会出现 “变量提升”的现象,即变量可以在声明之前使用,值为undefined。let 改变了这种现状,但是必须先声明在使用,如果在声明之前使用则会出现报错。如下:

  1. // var 的情况
  2. console.log(foo); // 输出undefined
  3. var foo = 2;
  4.  
  5. // let 的情况
  6. console.log(bar); // 报错ReferenceError
  7. let bar = 2;

暂时性死区

只要块级作用域内部存在 let 或者 const 命令,它所声明的变量就“绑定”在这个区域,不会受外部影响。且暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。如下:

  1. var tmp = 123;
  2.  
  3. if (true) {
  4.  tmp = 'abc'; // ReferenceError
  5.  let tmp;
  6. }

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

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

  1. if (true) {
  2.  // TDZ开始
  3.  tmp = 'abc'; // ReferenceError
  4.  console.log(tmp); // ReferenceError
  5.  
  6.  let tmp; // TDZ结束
  7.  console.log(tmp); // undefined
  8.  
  9.  tmp = 123;
  10.  console.log(tmp); // 123
  11. }

注意:

++使用let声明变量时,只要变量在还没有声明完成前使用,就会报错。上面这行就属于这个情况,在变量x的声明语句还没有执行完成前,就去取x的值,导致报错”x 未定义“。++

不允许重复声明

let 不允许在同一个作用域内声明同一个变量,如下:

  1. // 报错
  2. function func() {
  3.  let a = 10;
  4.  var a = 1;
  5. }
  6.  
  7. // 报错
  8. function func() {
  9.  let a = 10;
  10.  let a = 1;
  11. }

或者如下:

  1. function func(arg) {
  2.  let arg;
  3. }
  4. func() // 报错
  5.  
  6. function func(arg) {
  7.  {
  8.  let arg;
  9.  }
  10. }
  11. func() // 不报错

块级作用域

上面也提到过在es5中没有块级作用域的概念,只有函数作用域和全局作用域,那么就带来了一些问题,如下:

  1. var tmp = new Date();
  2.  
  3. function f() {
  4.  console.log(tmp);
  5.  if (false) {
  6.  var tmp = 'hello world';
  7.  }
  8. }
  9.  
  10. f(); // undefined
  11.  
  12. 外层声明被内层声明所覆盖,内层使用的是外层的声明,内层变量提升导致 undefinded

第二种:计数循环全局泄露,如下:

  1. var s = 'hello';
  2.  
  3. for (var i = 0; i < s.length; i++) {
  4.  console.log(s[i]);
  5. }
  6.  
  7. console.log(i); // 5
  8.  
  9. 常见的面试题,最后输出不是预料中的 1 2 3 4 5 而全部是 5

ES6的块级作用域,实际上就是let 新增的,如下:

  1. function f1() {
  2.  let n = 5;
  3.  if (true) {
  4.  let n = 10;
  5.  }
  6.  console.log(n); // 5
  7. }
  8.  
  9. 内外层的 n 互不干扰

ES6中 允许作用域任意嵌套,并且互不干扰,如下:

  1. 内外层可以同名
  2.  
  3. {{{{
  4.  let insane = 'Hello World';
  5.  {let insane = 'Hello World'}
  6. }}}};
  7.  
  8. 或者
  9.  
  10. {{{{
  11.  {let insane = 'Hello World'}
  12.  console.log(insane); // 报错
  13. }}}};

块级作用域的出现可以让以下立即执行函数的写法不必要,如下:

  1. // IIFE 写法
  2. (function () {
  3.  var tmp = ...;
  4.  ...
  5. }());
  6.  
  7. // 块级作用域写法
  8. {
  9.  let tmp = ...;
  10.  ...
  11. }

块级作用域和函数声明

在ES5中,函数只能在顶层作用域和函数作用域中声明,不能在块级作用域中声明,但是浏览器为了兼容性,还是可以在块级作用域中声明,理论上在ES6中 块级作用域中声明的函数,在外部调用会报错,考虑环境的问题,应当避免在块级作用域中声明函数,如果需要也应当写成函数表达式的方式,而不是函数声明语句,如下:

  1. // 函数声明语句
  2. {
  3.  let a = 'secret';
  4.  function f() {
  5.  return a;
  6.  }
  7. }
  8.  
  9. // 函数表达式
  10. {
  11.  let a = 'secret';
  12.  let f = function () {
  13.  return a;
  14.  };
  15. }

const

const声明的是一个常量 如下:

  1. const PI = 3.1415;
  2. PI // 3.1415
  3.  
  4. PI = 3;
  5. // TypeError: Assignment to constant variable.

声明之后如果在赋值,将会报错,同时因为声明的是常量,即const声明后即要赋值不然也会报错
const 和 let 相同,声明也只在当前的块级作用域生效。同样也不会声明提升,也存在暂时死区,只能在声明之后使用,且和 let 一样不得重复声明,不能重新赋值。

重要:

const 所不能改变的并不是值,而是变量指向的那个内存地址所保存的值不能变动,对于简单类型(数值、字符串、布尔值),值就保存在变量所指向的内存地址中,因此等同于常量。而对于复合类型(数组、对象),变量指向的内存地址,保存的只是一个指向实际数据的指针,const 只能保证这个指针是固定的(即总指向一个固定的地址)。至于它指向的数据结构则是不能控制的 ,如下:

  1. const foo = {};
  2.  
  3. // 为 foo 添加一个属性,可以成功
  4. foo.prop = 123;
  5. foo.prop // 123
  6.  
  7. // 将 foo 指向另一个对象,就会报错
  8. foo = {}; // TypeError: "foo" is read-only
  9.  
  10. 常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,
  11. 即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加属性

或者

  1. const a = [];
  2. a.push('Hello'); // 可执行
  3. a.length = 0; // 可执行
  4. = ['Dave']; // 报错
  5.  
  6. 常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错

如果真的想将声明对象冻结,不能在改变 则应该使用object.freeze()

  1. const foo = Object.freeze({});
  2.  
  3. // 常规模式时,下面一行不起作用;
  4. // 严格模式时,该行会报错
  5. foo.prop = 123;
  6.  
  7. 对象也可以冻结
  8.  
  9. var constantize = (obj) => {
  10.  Object.freeze(obj);
  11.  Object.keys(obj).forEach( (key, i) => {
  12.  if ( typeof obj[key] === 'object' ) {
  13.  constantize( obj[key] );
  14.  }
  15.  });
  16. };

ES6 声明变量的六种方法

1. function
2. var
3. let
4. const
5. import 
6. class

顶层对象的属性

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

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

global 对象

ES5 的顶层对象,本身也是一个问题,因为它在各种实现里面是不统一的。

  1. 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。

  2. 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。

  3. Node 里面,顶层对象是global,但其他环境都不支持

同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this变量,但是有局限性。

  1. 全局环境中,this会返回顶层对象。但是,Node 模块和 ES6 模块中,this返回的是当前模块。

  2. 函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined。

  3. 不管是严格模式,还是普通模式,new Function('return this')(),总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全策略),那么eval、new Function这些方法都可能无法使用。


猜你在找的JavaScript相关文章