ES6 let和count

有些话、适合烂在心里 提交于 2020-03-21 20:02:57

1、let命令用法:

  a、let用来声明变量,类似var,但用let声明的变量,只能在其代码块中引用,相当于私有变量,不会被外界所获取:

    function fn(){

      let a = 1

      console.log(a)      这里可以直接调用

    }

    console.log(a)  在函数外面访问输出就会报错

    以后在for循环中比较适合用let:

    var a = [];

    for (var i = 0; i < 10; i++)

      a[i] = function ();

        console.log(i)

      }

     }

   a[6]();这里会输出10

    用var声明的i相当于全局变量,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是10。

    把var换成let,最后输出的结果就是6

 

    还有在fou循环中,设置循环的部分是父作用域,在循环体内是子作用域:

    for ( let i = 0; i < 10; i++){

      let i = 'aaa';

      console.log(i)

    }

    最终输出10次'aaa',这是因为声明在不同块内,相互是不一样的。

  b、不存在变量提升了

    console.log(a)  输出结果是undefind

    var a = 1;

    console.log(b)  报错

    let b = 1;

    这是因为用var声明变量之前调用,因为变量提升的原因,即输出的时候,变量已经存在,但没有给a赋值,所以输出undefined,但用let声明变量只会在声明后存在,之前调用就会报错。

  c、暂时性死区

    let tem = 'abc';

    if(true){

      console.log(tem);

      let tem;

    }

    这是就会报错,因为如果在一个块中存在let一个变量,那在let这个变量之前,不能出现这个变量!ES6明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

    所以,在这个区域内使用tepyof就不太准确了。比如:

    tepyof x;

    let x;

    这时就会报错,而没有声明的变量反而不会报错:

    tepyof obj;   undefined

    所以一定要在声明变量再使用!!!

    let x = x;

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

    

    ES6 规定暂时性死区和letconst语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。这样的错误在 ES5 是很常见的,现在有了这种规定,避免此类错误就很容易了。

    总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。  

  d、不允许重复声明

    function fn(){

      let a = 1;

      var a = 2;(或者let a = 3;)

    }    报错

    function fn2 (arg){

      let arg = 2;

    }    报错

    这样的操作都会报错,在同一个作用域下,不允许重复声明一个变量,也不允许变量名和参数名相同

2、块级作用域

  以前只有全局作用域和函数作用域,现在增加了块级作用域,为什么增加块级作用域?

  原因一:内层变量会覆盖掉外层变量

    var time = new Date();

    function times () {

      console.log(time);

      if(false){

        var time = 'hello';

      }

    }

  times();  

  这时输出的是undefined;因为变量提升的原因,函数作用域中存在私有变量time,但没有赋值,所以就会覆盖掉全局变量。

  原因二:用来计数的循环变量泄漏成全局变量

  var str = 'hello';

  for (var i = 0; i < str.length; i++){

    console.log(str[i]);

  }

  console.log(i);

  在外层也会访问到变量i;这样i就变成来全局变量。

  let为javascript提供来块级作用域:

  function fn(){

    let n = 5;

    if(true){

      n = 10;

    }

    console.log(n);

  }

  这时输出的还是 5 ,虽然内层和外层都定义了n,但外层不受内层的影响。如果换成var,输出结果就是 10

  ES6允许块级任意嵌套:

  {{{{{let n = 1;}}}}}   这是5层块级作用域,外层的访问不到内层的;

  {{{

    console.log(n);

    {let n = 2;}

  }}}    这是就会报错。

  {{{

    let n = 1;

    {let n = 2}

  }}}   外层和内层允许存在相同的变量名,相互不受影响。

  块级作用域的出现,使得自执行函数(IIFE)不再必要了:

  IIFE:

  (function () {...})()

  块级作用域:

  {let...}

 

  do 表达式

 

  本质上,块级作用域是一个语句,将多个操作封装在一起,没有返回值。

 

  {
    let t = f();
    t = t * t + 1;
  }

 

  上面代码中,块级作用域将两个语句封装在一起。但是,在块级作用域以外,没有办法得到t的值,因为块级作用域不返回值,除非t是全局变量。

 

  现在有一个提案,使得块级作用域可以变为表达式,也就是说可以返回值,办法就是在块级作用域之前加上do,使它变为do表达式,然后就会返回内部最后执行的表达式的值。

 

  let x = do {
    let t = f();
    t * t + 1;
  };

 

  上面代码中,变量x会得到整个块级作用域的返回值(t * t + 1)。

 

3、const基本用法:

  const声明常量,一旦声明,其值将不能改变。所以也就意味着,一旦使用const声明变量就要及时赋值,不能先声明再赋值。

  a、const和let一样,只在声明的作用域中起作用。

  b、同样不提升,只能在声明后才能使用。

  c、同样不能重复声明。

4、本质

  const的本质就是引用地址不能变,但对于地址内部的信息是可以修改的,尤其是声明的对象和数组这样引用类型的:

  const arr = [];

  arr.lenght 可以执行;

  arr.push(23) 可以执行

  arr = ['abs']  报错

  const str = {};

  str.prop = 'abc' 可执行

  str = {}  指向另一个对象就会报错

  如果真的要冻结对象,需要用到 Object.freeze方法

  const str = Object.freeze({});

  str.prop = 'abc'  在严格模式下就会报错,在非严格模式下不起作用。

  除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。

  var constantize = (obj) => {

    Object.freeze(obj);

   Object.keys(obj).forEach( (key, i) => {

    if ( typeof obj[key] === 'object' ) {

      constantize( obj[key] );

    }

   });

  };

 

ES6除了以前的var和function声明变量外,新增了let和const声明变量,后面还有import和class,后期再补充。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!