浅谈ES6

作者: lMadman | 来源:发表于2017-05-08 14:36 被阅读0次

    <b>1.var、let、const声明变量,有什么区别?</b>

    <b>(1)作用域:</b>
    <b>var</b> 声明的变量不用多说,我们之前写js都是用这个来声明,但很少有人理解它的作用域,可以这样来说,var声明的变量属于<b>function scope(方法作用域)</b>,可以简单的这样理解:如果一个变量用var定义且只在方法体中被声明过,那么这个变量就是局部变量,反之便是全局变量。可这样有时候并不是我们想要的,比如:

    var a = 0;
    if (a < 5){
      var b = 'Madman';
      console.log(a);  //0
      console.log(b); //Madman
    }
    console.log(a); //0
    console.log(b); //Madman
    

    我们发现,这四个都能打印出来对应的值。a 就不用多说了, b虽然被定义在 if 语句中,但是使用 var 定义,并没有在方法体内,所以 b 也是全局变量,然而我们只是想在这里被使用一次。ES6为了弥补这一不足,引入了 let 以及 const 。

    <b>let 和 const :</b> 这两个在 ES6 中同样定义变量,但是它们属于 <b>block scope(块级作用域)</b>,这个其实很好理解,如果上面例子中的 b 使用 let \ const 来定义,那么最后一个 console 会报 not defined 。因为 if 循环算是一个块级区域。

    <b>(2)重复声明:</b>
    var 可以重复声明同一个变量名,而 let 和 const 在同一个作用域下,只能被声明一次。

    var a = 'Madman';
    var a = '疯子';
    let b = '李小呆';
    let b = '哈哈哈';  //  错误
    const c = 'php';
    if(a == 'Madman'){
      const c = 'java';
    }
    console.log(c);  // php
    

    上面例子中我们可以看到,在同一个作用域下不能用 let 和 const 声明相同名称的变量,所以在全局中使用 let 声明第二次 b 的时候,会报错;而我用 const 定义了两次变量 c ,但是它们不在同一个作用域下,故是两个变量。

    <b>(3)重新赋值</b>
    说一下 let 和 const 的区别,let 声明的变量是可以重新赋值的 ,而 const 声明的变量不可以重新赋值。
    当然,如果只是单纯这样说的话表达的不是很明白,举个例子吧:

    let a = 'Madman';
    a = '李小呆'; 
    const b = '哈哈哈';
    b = '呵呵呵';  //错误!不可以被重复赋值
    

    当然,const 声明的变量只是没办法重新赋值,但有一种情况却是可以:

    const person = {
      name : 'Madman',
      age : 23
    }
    person = {
      name : '李小呆'
    }   //错误
    person.age = 18 ;
    console.log(person);   //{name : 'Madman', age : 18} 
    //可以看出,person对象的 age 属性被成功的修改。
    

    person 是一个对象,对象是一种引用类型的值,当我给它赋值一个新的对象的时候,其实这个指针就指向了新的引用地址;而如果我们只是改变对象里的属性的话,这个对象本身的引用地址并没有发生变化。
    如果连对象的属性都不想让它变化,那就使用const Madman = Object.freeze(person)

    <b>2.let 和 const 经常会被用在哪些地方?</b>

    <b>(1)for 循环</b>
    在接触 ES6 之前呢,我们经常用到的 for 循环都是通过 var 来定义循环的次数的,比如:

    for ( var v = 0; v<10 ; v++){
      console.log(v);
    }
    

    很明显,上面代码输出的结果是0到9;那么我们如果使用setTimeout(function(){})模拟一下ajax请求;

    for ( var v = 0; v<10 ; v++){
      console.log(v);
      setTimeout(function(){
        console.log(`v:${v}`);
      })
    }
    

    此时,我们看到被 var 定义的变量 v 在 for 循环之后被打印了十次;可我们想让它输出像上面一样的结果,而并非 for 执行完之后再去执行setTimeout里面的语句;
    那么,我们把 var 改成 let 试试:



    可以看到,结果如我们所愿,为什么呢?
    其实非要讲真正的原理我也不是很理解,但你可以这样理解,被let 定义的变量 v ,此时属于块级作用域,它只在一个 for 循环块中有效,所以每次结束这个块时,它都会等setTimeout执行完并输出v。

    <b>(2)变量提升</b>
    我们先来看一段代码:

    <script>
      console.log(color);  //undefined
      var color = 'blue';
    </script>
    

    这里为什么是undefined? 熟悉的人会知道在 js 中会有变量提升这以说法,那么什么是<b>变量提升?</b>

    • JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。
    • JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。
    • JavaScript 只有声明的变量会提升,初始化的不会。

    说了这么多,什么意思呢?其实上面的代码就相当于:

    var color;  //定义的变量被提升到代码的最顶部
    console.log(color);  //这个时候输出,js 能找到color 这个变量,但是这个变量没被初始化值,所以是undefined
    color = 'blue';  //声明被提升到了代码的顶部,但是初始化仍在console 后面。
    

    那么,如果换成 let 或者 const 呢?

    console.log(userName);
    let userName = 'Madman';
    

    为什么?我们来看看gitHub上的解释:



    通俗来说,这种现象叫做hoist,在 var 中有,同样在 let/const 中也有。

    就和上面所提及到的一样,在声明代码之前使用后面用 var 声明的变量会返回一个 undefined,这个值是默认的在初始化的时候赋进去的。

    但是如果是在声明之前使用后面会用 let/const 声明的变量会抛出一个错误。这个因为变量在声明代码之前是不可用的(没有被初始化)。进入作用域和使用作用域的值得这段时期就叫做时间死区(Temporal Dead Zone)。

    注解:
    时间死区(Temporal Dead Zone): 在进入一个scope之后,let/const也会有一个hoist,这个过程和var 一样,区别是 var 在hoist之后,被初始化为了 undefined,但是let/const没有初始化,直到真正声明它的地方。

    <b>3.箭头函数</b>

    ES6 推出的箭头函数有四个特点:

    • 简明的语法;
    const arr1 = [5,8,10,12,15];
    const arr2 = arr1.map(function (arr) {
        return arr*2;
    });
    console.log(arr2);
    const arr3 = arr1.map((arr) => { //箭头函数
        return arr*2;
    });
    console.log(arr3);
    const arr4 = arr1.map(arr => { //箭头函数,单个参数可以不要那一对括号
        return arr*2;
    });
    console.log(arr4)
    const arr5 = arr1.map((arr,i) => { //箭头函数,多个参数用逗号分割
        return `${i} : ${arr *2}`;
    });
    console.log(arr5);
    
    • 可以隐士返回;
    const arr1 = [5,8,10,12,15];
    const arr2 = arr1.map((arr) => {
      return arr*2;  //  像这种带有return 的被称为显示返回
    })
    const arr3 = arr1.map((arr) => arr*2);
    //这中把代码写在一行,不写return 以及去掉 '{}' 的被称为隐式返回;
    
    • 箭头函数都是匿名函数
    function sayName(name){
      alert(`hi,${name}`);
    }
    sayName('Madman'); //很显然,这是一个命名函数
    
    //那如何用箭头函数来实现呢?一般我们把箭头函数赋给一个变量
    const sayHi = name => alert(`hi,${name}`);
    sayHi('Madman');
    
    const a = 0;
    const hh = a => {
                    if(a<5) {
                        alert(a);
                    }
                }
     hh(a);
    //其实这样看起来怪怪的 -O-
    
    • this 的理解;
    const madman = {
                name : 'Madman',
                hobbies :['睡觉','吃饭','打豆豆'],
                printHobbies :function () {
                    this.hobbies.map(function(hobby){ //这里的this会指向madman
                       console.log(`${this.name} love ${hobby}`); //这里的this会指向windows对象
                    });
                }
            };
    madman.printHobbies()
    

    来看一下控制台的结果:


    可以发现,this.name 并没有被打印出来。那么我们来试试箭头函数:
    const madman = {
                name : 'Madman',
                hobbies :['睡觉','吃饭','打豆豆'],
                printHobbies :function () {
                    this.hobbies.map((hobby) =>{
                       console.log(`${this.name} love ${hobby}`);
                    });
                }
            };
    madman.printHobbies();
    

    来看一下控制台的结果:



    为什么呢?
    <b>因为箭头函数没有自己的 this 值,它的 this 值是继承它的父作用域。</b>

    <b>4.参数默认值</b>

    之前,我们一般调用方法的时候会给参数一个默认值,比如:

    function multiply(a,b){
      a = a || 3;
      b = b || 5;
      return a * b;
    }
    

    那么,我们来看一下ES6是如何给参数赋默认值的;

    function multiply(a = 3, b = 5){ //是不是很简单明了且具有可读性
      return a * b;
    }
    multiply();  //15
    multiply(1,1);  //1
    multiply(2);  //10
    multiply(undefined,2);  //6 ,这里底层是通过判断typeof === 'undefined' ? 默认值 || 其他
    

    相关文章

      网友评论

          本文标题:浅谈ES6

          本文链接:https://www.haomeiwen.com/subject/amlmtxtx.html