es6杂记

es6杂记

let 和 const

let

  1. 仅在代码块里有效

    {
      let a = 10;
      var b = 1;
    }
    
    a // ReferenceError: a is not defined.
    b // 1
    
  2. for循环比价适合用let

    你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

  3. 不存在变量提升

  4. 暂时性死区 temporal dead zone TDZ

    var tmp = 123;
    if (true) {
      tmp = 'abc'; // ReferenceError
      let tmp;
    }
    

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

    typeof如果跟了let在后面,会报错,如果没有let,只会是undefined

    隐蔽TDZ

    function bar(x = y, y = 2) {
      return [x, y];
    }
    
    bar(); // 报错
    

    上面代码中,调用bar函数之所以报错(某些实现可能不报错),是因为参数x默认值等于另一个参数y,而此时y还没有声明,属于”死区“。如果y的默认值是x,就不会报错,因为此时x已经声明了。

    function bar(x = 2, y = x) {
      return [x, y];
    }
    bar(); // [2, 2]
    

    另外,下面的代码也会报错,与var的行为不同。

    // 不报错
    var x = x;
    
    // 报错
    let x = x;
    // ReferenceError: x is not defined
    
  5. let不允许在相同作用域内,重复声明同一个变量。

    function func(arg) {
      let arg; // 报错
    }
    
    function func(arg) {
      {
        let arg; // 不报错
      }
    }
    
    // 报错
    function func() {
      let a = 10;
      var a = 1;
    }
    
    // 报错
    function func() {
      let a = 10;
      let a = 1;
    }
    

const

  1. const声明一个只读的常量。一旦声明,常量的值就不能改变。(一般大写)

  2. 必须给初值

  3. 与let一样,仅在代码块里有效

  4. 也存在TDZ

  5. 不允许重复声明

  6. 本质

    const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动

    对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。

    但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

全局变量与顶层对象脱钩

var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1

let b = 1;
window.b // undefined

变量的解构赋值

数组的解构赋值

  1. 基本用法

    let [a, b, c] = [1, 2, 3];
    

    一些例子

    完全解构
    let [foo, [[bar], baz]] = [1, [[2], 3]];
    foo // 1
    bar // 2
    baz // 3
    
    let [ , , third] = ["foo", "bar", "baz"];
    third // "baz"
    
    let [x, , y] = [1, 2, 3];
    x // 1
    y // 3
    
    let [head, ...tail] = [1, 2, 3, 4];
    head // 1
    tail // [2, 3, 4]
    
    let [x, y, ...z] = ['a'];
    x // "a"
    y // undefined
    z // []
    

    如果解构不成功,变量的值就等于undefined。

    不完全解构
    
    let [x, y] = [1, 2, 3];
    x // 1
    y // 2
    
    let [a, [b], d] = [1, [2, 3], 4];
    a // 1
    b // 2
    d // 4
    
  2. 默认值

    let [foo = true] = [];
    foo // true
    
    let [x, y = 'b'] = ['a']; // x='a', y='b'
    let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
    

    判断是否===undefined

    let [x = 1] = [undefined];
    x // 1
    
    let [x = 1] = [null];
    x // null
    

对象的解构赋值

  1. 基本语法

    let { foo, bar } = { foo: "aaa", bar: "bbb" };
    foo // "aaa"
    bar // "bbb"
    

    对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

    let { bar, foo } = { foo: "aaa", bar: "bbb" };
    foo // "aaa"
    bar // "bbb"
    
    let { baz } = { foo: "aaa", bar: "bbb" };
    baz // undefined
    

字符串的解构赋值

  1. 基本语法

    const [a, b, c, d, e] = 'hello';
    a // "h"
    b // "e"
    c // "l"
    d // "l"
    e // "o"	
    
    let {length : len} = 'hello';
    len // 5
    

函数解构赋值

解构赋值的用途

  1. 可以交换变量

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

    函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。

    // 返回一个数组
    
    function example() {
      return [1, 2, 3];
    }
    let [a, b, c] = example();
    
    // 返回一个对象
    
    function example() {
      return {
        foo: 1,
        bar: 2
      };
    }
    let { foo, bar } = example();
    
  3. 函数参数的定义

    解构赋值可以方便地将一组参数与变量名对应起来。

  4. 提取 JSON 数据

    let jsonData = {
      id: 42,
      status: "OK",
      data: [867, 5309]
    };
    
    let { id, status, data: number } = jsonData;
    
    console.log(id, status, number);
    // 42, "OK", [867, 5309]
    
  5. 函数参数的默认值

  6. 输入模块的指定方法

    const { SourceMapConsumer, SourceNode } = require("source-map");
    

字符串的扩展

  1. includes(), startsWith(), endsWith()

    includes():返回布尔值,表示是否找到了参数字符串。

    startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。

    endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

    这三个方法都支持第二个参数,表示开始搜索的位置。

    let s = 'Hello world!';
    
    s.startsWith('world', 6) // true
    s.endsWith('Hello', 5) // true
    s.includes('Hello', 6) // false
    
  2. repeat()

    'x'.repeat(3) // "xxx"
    'hello'.repeat(2) // "hellohello"
    'na'.repeat(0) // ""
    

    小数会被取整

  3. 拼接 ,变量用$

数值的扩展

  1. Number.isFinite(), Number.isNaN()

    注意:

    Number.isFinite()对于非数值一律返回false, Number.isNaN()只有对于NaN才返回true,非NaN一律返回false。

  2. Number.parseInt(), Number.parseFloat()

    // ES5的写法
    parseInt('12.34') // 12
    parseFloat('123.45#') // 123.45
    
    // ES6的写法
    Number.parseInt('12.34') // 12
    Number.parseFloat('123.45#') // 123.45
    
  3. Number.isInteger()用来判断一个数值是否为整数。

    Number.isInteger(25) // true
    Number.isInteger(25.0) // true
    Number.isInteger(25.1) // false
    

    如果参数不是数值,Number.isInteger返回false。

    Number.isInteger('15') // false
    

    如果数值的精度超过这个限度,第54位及后面的位就会被丢弃,这种情况下,Number.isInteger可能会误判。

对象的扩展

  1. 默认值

    function Point(x = 0, y = 0) {
      this.x = x;
      this.y = y;
    }
    
    const p = new Point();
    p // { x: 0, y: 0 }
    
  2. rest

  3. 箭头函数

    var f = () => 5;
    // 等同于
    var f = function () { return 5 };
    
    var sum = (num1, num2) => num1 + num2;
    // 等同于
    var sum = function(num1, num2) {
      return num1 + num2;
    };
    

    箭头函数有几个使用注意点。

    (1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

    (2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

    (3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

    (4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

数组的扩展

  1. Array.from(),会返回一个新数组

    let arrayLike = {
        '0': 'a',
        '1': 'b',
        '2': 'c',
        length: 3
    };
    
    // ES5的写法
    var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
    
    // ES6的写法
    let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
    

    Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。

    Array.from(arrayLike, x => x * x);
    // 等同于
    Array.from(arrayLike).map(x => x * x);
    
    Array.from([1, 2, 3], (x) => x * x)
    // [1, 4, 9]
    
  2. 数组实例的 includes()

    [1, 2, 3].includes(2)     // true
    [1, 2, 3].includes(4)     // false
    [1, 2, NaN].includes(NaN) // true	
    
  3. 使用 for of 来遍历数组中的值

    for (let index of ['a', 'b'].keys()) {
      console.log(index);
    }
    // 0
    // 1
    
    for (let elem of ['a', 'b'].values()) {
      console.log(elem);
    }
    // 'a'
    // 'b'
    
    for (let [index, elem] of ['a', 'b'].entries()) {
      console.log(index, elem);
    }
    // 0 "a"
    // 1 "b"
    

    可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

对象的扩展

  1. 属性的简洁表示法

    const foo = 'bar';
    const baz = {foo};
    baz // {foo: "bar"}
    
    // 等同于
    const baz = {foo: foo};
    
    const o = {
      method() {
        return "Hello!";
      }
    };
    
    // 等同于
    
    const o = {
      method: function() {
        return "Hello!";
      }
    };
    

Set 和 Map

Set

  1. ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

    const s = new Set();

    [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

    for (let i of s) {
    console.log(i);
    }
    // 2 3 5 4

    Set和Array的对比:

    1、Set不允许有重复值,但是Array可以
    
    2、Set计算里面的个数,是调用它的size方法,Array用的是length
    
    3、实例方法有 add、delete、has、clear
    
  2. 遍历

    let set = new Set(['red', 'green', 'blue']);
    
    for (let item of set.keys()) {
      console.log(item);
    }
    // red
    // green
    // blue
    
    for (let item of set.values()) {
      console.log(item);
    }
    // red
    // green
    // blue
    
    for (let item of set.entries()) {
      console.log(item);
    }
    // ["red", "red"]
    // ["green", "green"]
    // ["blue", "blue"]
    

    Set 结构的键名就是键值(两者是同一个值)

    可以省略values方法,直接用for...of循环遍历 Set。

    let set = new Set(['red', 'green', 'blue']);
    
    for (let x of set) {
      console.log(x);
    }
    // red
    // green
    // blue
    

    也可以用foreach

    set = new Set([1, 4, 9]);
    set.forEach((value, key) => console.log(key + ' : ' + value))
    // 1 : 1
    // 4 : 4
    // 9 : 9
    

    用途

    1. 扩展运算符和 Set 结构相结合,就可以去除数组的重复成员。

      let arr = [3, 5, 2, 2, 5, 5];
      let unique = [...new Set(arr)];
      // [3, 5, 2]
      
    2. 数组的map和filter方法也可以间接用于 Set 了

      let set = new Set([1, 2, 3]);
      set = new Set([...set].map(x => x * 2));
      // 返回Set结构:{2, 4, 6}
      
      let set = new Set([1, 2, 3, 4, 5]);
      set = new Set([...set].filter(x => (x % 2) == 0));
      // 返回Set结构:{2, 4}
      
    3. 结合filter筛选

      let a = new Set([1, 2, 3]);
      let b = new Set([4, 3, 2]);
      
      // 并集
      let union = new Set([...a, ...b]);
      // Set {1, 2, 3, 4}
      
      // 交集
      let intersect = new Set([...a].filter(x => b.has(x)));
      // set {2, 3}
      
      // 差集
      let difference = new Set([...a].filter(x => !b.has(x)));
      // Set {1}
      
    4. 将set结构的数据变成数组

      // 方法一
      let set = new Set([1, 2, 3]);
      set = new Set([...set].map(val => val * 2));
      // set的值是2, 4, 6
      
      // 方法二
      let set = new Set([1, 2, 3]);
      set = new Set(Array.from(set, val => val * 2));
      // set的值是2, 4, 6
      

Map

它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

注意,0和-0就是一个键,布尔值true和字符串true则是两个不同的键。另外,undefined和null也是两个不同的键。虽然NaN不严格相等于自身,但 Map 将其视为同一个键。

Map 和 对象的比较:

1、对象的key必须是字符串,但是Map的key可以是任何类型
2、map实例方法有 set、get、delete、has、clear
  1. 基本语法

    const m = new Map();
    const o = {p: 'Hello World'};
    
    m.set(o, 'content')
    m.get(o) // "content"
    
    m.has(o) // true
    m.delete(o) // true
    m.has(o) // false
    
  2. 可以接受一个数组

    const map = new Map([
      ['name', '张三'],
      ['title', 'Author']
    ]);
    
    map.size // 2
    map.has('name') // true
    map.get('name') // "张三"
    map.has('title') // true
    map.get('title') // "Author"
    
  3. 遍历

    遍历的顺序就是插入的顺序

    const map = new Map([
      ['F', 'no'],
      ['T',  'yes'],
    ]);
    
    for (let key of map.keys()) {
      console.log(key);
    }
    // "F"
    // "T"
    
    for (let value of map.values()) {
      console.log(value);
    }
    // "no"
    // "yes"
    
    for (let item of map.entries()) {
      console.log(item[0], item[1]);
    }
    // "F" "no"
    // "T" "yes"
    
    // 或者
    for (let [key, value] of map.entries()) {
      console.log(key, value);
    }
    // "F" "no"
    // "T" "yes"
    
    // 等同于使用map.entries()
    for (let [key, value] of map) {
      console.log(key, value);
    }
    // "F" "no"
    // "T" "yes"
    
  4. 快速转成数组

    Map 结构转为数组结构,比较快速的方法是使用扩展运算符(...)。

    const map = new Map([
      [1, 'one'],
      [2, 'two'],
      [3, 'three'],
    ]);
    
    [...map.keys()]
    // [1, 2, 3]
    
    [...map.values()]
    // ['one', 'two', 'three']
    
    [...map.entries()]
    // [[1,'one'], [2, 'two'], [3, 'three']]
    
    [...map]
    // [[1,'one'], [2, 'two'], [3, 'three']]
    

Promise

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

  1. 基本用法

    Promise对象是一个构造函数,用来生成Promise实例。

    const promise = new Promise(function(resolve, reject) {
      // ... some code
    
      if (/* 异步操作成功 */){
        resolve(value);
      } else {
        reject(error);
      }
    });
    

    Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

    resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

    reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

    Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

    promise.then(function(value) {
      // success
    }, function(error) {
      // failure
    });
    

    then方法可以接受两个回调函数作为参数。

    第一个回调函数是Promise对象的状态变为resolved时调用

    第二个回调函数是Promise对象的状态变为rejected时调用。

    二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

    简单的例子:

    function timeout(ms) {
      return new Promise((resolve, reject) => {
        setTimeout(resolve, ms, 'done');
      });
    }
    
    timeout(100).then((value) => {
      console.log(value);
    });
    
  2. promise.prototype

    promise
    .then(result => {···})
    .catch(error => {···})
    .finally(() => {···});
    

    如果该对象状态变为resolved,则会调用then方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误。另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。

       //使用promise封装耗时的操作
        function promiseTimeOut(time,str){
            return new Promise((yes,no)=>{
                setTimeout(() => {
                    yes(str)
                }, time);
            })
        }

        promiseTimeOut(2000,"..第一层..").then(data1=>{
            console.log(data1)

            return promiseTimeOut(2000,'..第二层..')
        }).then(data2=>{
            console.log(data2)

            return promiseTimeOut(2000,'..第三层..')
        }).then(data3=>{
            console.log(data3)

            return promiseTimeOut(2000,'..第四层..')
        }).then(data4=>{
            console.log(data4)
        })

async 函数

作用:

1.	能解决Promise获取值时then过多的问题
2.	通过同步的方式去调用异步的代码
3.	使得异步操作变得更加方便。

语法:

async 函数名称(){
	await 异步操作
	
	await 异步操作
}
     //使用promise封装耗时的操作
        function promiseTimeOut(time,str){
            var promise = new Promise((yes,no)=>{
                setTimeout(() => {
                    yes(str)
                }, time);
            })
            return promise
        }
        function printName(name){
            return name
        }
        async function printStepByStep(){
            const result1 = await promiseTimeOut(2000,'。。。第一层。。。')
            console.log(result1)
            const result2 = await printName("。。。小刘。。。")
            console.log(result2)
            const result3 = await promiseTimeOut(2000,'。。。第3层。。。')
            console.log(result3)
            const result4 = await promiseTimeOut(2000,'。。。第四层。。。')
            console.log(result4)
        }
        //调用异步函数
        printStepByStep()

注意:

1、我们用async定义的异步函数,必须要调用它,否则不起作用

2、如果await 后面调用的函数,返回的是promise对象,他会自动调用promise的then把结果拿出来,赋值给变量

3、await后面调用的函数里面,除了可以返回promise、也可返回普通的类型

posted on 2018-02-16 21:50  ouruixi  阅读(125)  评论(0编辑  收藏  举报

导航