学习《ECMAScript6入门》提取记录

一直没有系统地学习JS。这次谷歌刚好找到了一本还不错的书,学习ES6语法,顺带提升一下JS的基础知识。

let 和 const 命令

Let 命令:
  • 不存在变量提升:

    • let定义后才能使用,如果在之前有引用,会报错。
    • var则不会报错,只会提示:undefined
  • 暂时性死区:

    这个和上面的一样,在声明前如果引用,会报错。

  • 不能重复声明:

    在同一作用域内只能声明一次。

块级作用域:

这里对作用域有了新的认识:

比如上面的for循环,每循环一次,就是一个独立的作用域。还包括IF语句,也是一个独立的作用域。

  • let的作用域:
    • var为全局作用域,如果在块级作用域里var定义,会泄露到全局作用域。
    • let只在作用域内有效。不会泄露。

什么是立即执行函数表达式(IIFE)

通常想要定义好的函数表达式马上执行,需要在声明后调用,;如果想立即执行:

1
2
3
> (function(){/* code */}());
> (function(){/* code */})();
>

>

可以像这样用括号从最外面包起来。函数这会立即执行。

关于Javascript的函数声明和函数表达式:
  • 块级作用域与函数声明

    如果在作用哉里声明,会被提升到作用哉前面,并被当全局函数。

    所以:尽量减少在块级作用域里写函数声明。要也是尽量写成函数表达式。

  • 在ES5时代,如果拥有块级变量呢?

    可以参考这篇博客:JavaScript的作用域和块级作用域概念理解

    原理:

    • 在一个函数中定义的变量,当这个函数调用完后,变量会被销毁

    所以:

    1
    2
    3
    (function (){
    //内容
    })();

    这里面运行的东西和声明的变量就属于块级的了!

Const
  • const声明一个只读的常量。一旦声明,常量的值就不能改变。
  • const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
  • const的作用域与let命令相同:只在声明所在的块级作用域内有效。
  • const声明的常量,也与let一样不可重复声明。

变量的解构赋值

  • 数组的解构赋值

    和ruby和赋值模式差不多,但这里只是以数组的形式出现在赋值的时候:

    1
    2
    3
    4
    let [a, b, c] = [1, 2, 3];
    let [head, ...tail] = [1, 2, 3, 4];
    head // 1
    tail // [2, 3, 4]
  • 默认值:

    1
    2
    3
    let [x = 1] = [undefined];
    x // 1
    let [x = 1, y = x] = [2]; // x=2; y=2

    这里意思是先对比变量和最右边的数是否====严格相等,如果不是就执行左边的赋值。

  • 对象ObJ也可以被用来这样赋值。(其中有一些)

  • 字符串也可以这样:

    1
    2
    3
    4
    5
    6
    const [a, b, c, d, e] = 'hello';
    a // "h"
    b // "e"
    c // "l"
    d // "l"
    e // "o"
  • 作用:

    • 交换变量的值

      1
      2
      3
      4
      let x = 1;
      let y = 2;
      [x, y] = [y, x];
    • 从函数返回多个值

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      // 返回一个数组
      function example() {
      return [1, 2, 3];
      }
      let [a, b, c] = example();
      // 返回一个对象
      function example() {
      return {
      foo: 1,
      bar: 2
      };
      }
      let { foo, bar } = example();
    • 函数参数的定义 && 函数参数默认值

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      jQuery.ajax = function (url, {
      async = true,
      beforeSend = function () {},
      cache = true,
      complete = function () {},
      crossDomain = false,
      global = true,
      // ... more config
      } = {}) {
      // ... do stuff
      };
    • 提取 JSON 数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      let jsonData = {
      id: 42,
      status: "OK",
      data: [867, 5309]
      };
      let { id, status, data: number } = jsonData;
      console.log(id, status, number);
      // 42, "OK", [867, 5309]
字符串
  • 字符串模板:

    1
    `my name is ${name}.` #类似ruby的模板。
函数定义
  • 默认值惰性传值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let x = 99;
    function foo(p = x + 1) {
    console.log(p);
    }
    foo() // 100
    x = 100;
    foo() // 101

    上面代码中,参数p的默认值是x + 1。这时,每次调用函数foo,都会重新计算x + 1,而不是默认p等于 100。

  • name 属性

    函数的name属性,返回该函数的函数名。

  • 箭头函数

    1
    2
    3
    4
    5
    6
    7
    // 正常函数写法
    [1,2,3].map(function (x) {
    return x * x;
    });
    // 箭头函数写法
    [1,2,3].map(x => x * x);
    • this的作用域:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      function Timer() {
      this.s1 = 0;
      this.s2 = 0;
      // 箭头函数
      setInterval(() => this.s1++, 1000);
      // 普通函数
      setInterval(function () {
      this.s2++;
      }, 1000);
      }
      var timer = new Timer();
      setTimeout(() => console.log('s1: ', timer.s1), 3100);
      setTimeout(() => console.log('s2: ', timer.s2), 3100);
      // s1: 3
      // s2: 0

      上面代码中,Timer函数内部设置了两个定时器,分别使用了箭头函数和普通函数。前者的this绑定定义时所在的作用域(即Timer函数),后者的this指向运行时所在的作用域(即全局对象)。所以,3100 毫秒之后,timer.s1被更新了 3 次,而timer.s2一次都没更新。