ES5-ES8

发布时间 2023-11-17 16:53:50作者: 忙着可爱呀~

2、ES6特性

1)箭头函数

  。简化函数的写法

   1)const foo = function foo(arr,num) {      
        console.log('foo:常规函数')
     }


    2)const foo = (arr,num) => {
        console.log('foo:箭头函数')
      }

3)
const foo = (arr,num) => console.log('foo:箭头函数')

4)const foo = arr => {
         console.log('foo:箭头函数')
       }

  。this作用域

箭头函数的this从执行上下文中执行,常规函数中,this通常指最近的函数。

2)Promise

promise解决了“著名的回调地狱”问题,虽然它引入了更复杂的问题(在ES8中可以通过更高级的构造函数 async 解决)

 

componentDidMount () {
    setInterval(() => {
      this.timer()
    }, 1000);
    const wait = () => new Promise((resolve) => {
        setTimeout(resolve,2000)
      })
    wait().then(() => {
      console.log('2秒后输入')
      return wait()
    })
    .then(() => {
      this.a ()
    })
    .then(() => {
      this.b()
    })
  }
  a () {
    setTimeout(() => {
        console.log('6秒后输出')
      }, 2000)
  }
  b () {
    setTimeout(() => {
      console.log('7秒后输出')
    }, 1000)
  }

。主要用途:

  解决异步编程带来的回调地狱问题

  把promise简单理解为一个容器,存放着某个未来才会结束的事件(通常是一个异步操作)的结果。

  通过promise对象来获取异步操作消息,处理各种异步操作

。特点:

  。对象的状态不受外界影响

    promise对象代表一个异步操作,有三种状态,pending(进行中)、fulfilled(已成功)、rejected(失败),只有异步操作的结果可以决定当前是哪种状态,任何其它操作都无法改变这个状态

  。一旦状态改变就不会再变,任何时候都快得到这个结果   

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

。缺点:

  。无法取消promise,一旦新建他就会立即执行,中途无法取消

  。如果不设置回调函数,promise内部抛出的错误,不会反应到外部

  。当处于pending状态时,无法得知目前进展到哪一阶段(刚刚开始还是即将完成)

。基本使用

  promise为一个构造函数,需要 new 来实例化

let p = new Promise(function (resolve, reject){
   if(/*异步操作成功*/){
       resolve(value);
   } else {
       reject(error);
   }
})

  promise 接收一个函数作为参数,该函数两个参数,resolve 和 reject ,由JS引擎提供

  。resolve作用是将 promise 状态从pending 变成 resolveed  ,在异步操作成功时调用,返回异步操作的结果,作为参数传递出去

  。reject作用是将promise状态从pending变成rejected,在异步操作失败时报错,作为参数传递出去

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

p.then(function(val){
    // success...
},function(err){
    // error...
})

。示例

  。当一段时间过后,promise状态变为resolved触发then方法绑定的回调函数

function timeout (s){
    return new Promise((resolve, reject){
        setTimeout(result,ms, 'done');
    })
}
timeout(100).then(val => {
    console.log(val);
})

 。 promise新建后立即执行

componentDidMount () {
      let p = new Promise(function(resolve, reject){
        console.log(1);
        resolve();
      })
      p.then(()=>{
          console.log(2);
      })
      console.log(3);
      // 1
      // 3
      // 2     
  }
componentDidMount () {
      this.f ()
    }
    
    f() {
      let atrr = new Promise(function(resolve, reject){
          resolve()
      })
      atrr.then(() => {
        console.log(this.func ([2,2,2]))  //6
      })
    }

    func ([a,b,c]) {
      return a + b + c
    }
异步加载图片:
function f(url){
    return new Promise(function(resolve, reject){
        const img = new Image ();
        img.onload = function(){
            resolve(img);
        }
        img.onerror = function(){
            reject(new Error(
                'Could not load image at ' + url
            ));
        }
        img.src = url;
    })
}

  。resolve函数和reject函数的参数为resolve函数或reject函数:
  p1的状态决定了p2的状态,所以p2要等待p1的结果再执行回调函数。

const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => reject(new Error('fail')), 3000)
})

const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => resolve(p1), 1000)
})

p2
  .then(result => console.log(result))
  .catch(error => console.log(error))
// Error: fail

  。调用resolvereject不会结束Promise参数函数的执行,除了return:

new Promise((resolve, reject){
    resolve(1);
    console.log(2);
}).then(r => {
    console.log(3);
})
// 2
// 1

new Promise((resolve, reject){
    return resolve(1);
    console.log(2);
})
// 1

 。Promise.prototype.then()

作用是为Promise添加状态改变时的回调函数,then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。
then方法返回一个新Promise实例,与原来Promise实例不同,因此可以使用链式写法,上一个then的结果作为下一个then的参数
getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // ...
});

Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

getJSON('/posts.json').then(function(posts) {
  // ...
}).catch(function(error) {
  // 处理 getJSON 和 前一个回调函数运行时发生的错误
  console.log('发生错误!', error);
});

如果 Promise 状态已经变成resolved,再抛出错误是无效的

const p = new Promise(function(resolve, reject) {
  resolve('ok');
  throw new Error('test');
});
p
  .then(function(value) { console.log(value) })
  .catch(function(error) { console.log(error) });
// ok

promise抛出一个错误,就被catch方法指定的回调函数捕获,下面三种写法相同

// 写法一
const p = new Promise(function(resolve, reject) {
  throw new Error('test');
});
p.catch(function(error) {
  console.log(error);
});
// Error: test

// 写法二
const p = new Promise(function(resolve, reject) {
  try {
    throw new Error('test');
  } catch(e) {
    reject(e);
  }
});
p.catch(function(error) {
  console.log(error);
});

// 写法三
const p = new Promise(function(resolve, reject) {
  reject(new Error('test'));
});
p.catch(function(error) {
  console.log(error);
});

  一般来说,不要在then方法里面定义Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。

// bad
promise
  .then(function(data) {
    // success
  }, function(err) {
    // error
  });

// good
promise
  .then(function(data) { //cb
    // success
  })
  .catch(function(err) {
    // error
  });

。Promise.prototype.finally()

 finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。

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

  finally不接收任何参数,与状态无关,本质上是then方法的特例

promise
.finally(() => {
  // 语句
});

// 等同于
promise
.then(
  result => {
    // 语句
    return result;
  },
  error => {
    // 语句
    throw error;
  }
);

上面代码中,如果不使用finally方法,同样的语句需要为成功和失败两种情况各写一次。有了finally方法,则只需要写一次。
finally方法总是会返回原来的值。

// resolve 的值是 undefined
Promise.resolve(2).then(() => {}, () => {})

// resolve 的值是 2
Promise.resolve(2).finally(() => {})

// reject 的值是 undefined
Promise.reject(3).then(() => {}, () => {})

// reject 的值是 3
Promise.reject(3).finally(() => {})

。Promise.all()

  用于将多个 Promise 实例,包装成一个新的 Promise 实例,参数可以不是数组,但必须是Iterator接口,且返回的每个成员都是Promise实例。 

const p = Promise.all([p1, p2, p3]);

p的状态由p1p2p3决定,分成两种情况。

  1. 只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
  2. 只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
// 生成一个Promise对象的数组
const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
  return getJSON('/post/' + id + ".json");
});

Promise.all(promises).then(function (posts) {
  // ...
}).catch(function(reason){
  // ...
});

上面代码中,promises是包含 6 个 Promise 实例的数组,只有这 6 个实例的状态都变成fulfilled,或者其中有一个变为rejected,才会调用Promise.all方法后面的回调函数。

注意:如果Promise的参数中定义了catch方法,则rejected后不会触发Promise.all()catch方法,因为参数中的catch方法执行完后也会变成resolved,当Promise.all()方法参数的实例都是resolved时就会调用Promise.all()then方法。

  如果参数里面都没有catch方法,就会调用Promise.all()的catch方法。

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// Error: 报错了

。Promise.resolve()

将现有对象转换成 Promise 对象。

const p = Promise.resolve($.ajax('/whatever.json'));

。Promise.reject()

  返回一个rejected状态的Promise实例。

const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))

p.then(null, function (s) {
  console.log(s)
});
// 出错了

 注意,Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与Promise.resolve方法不一致。

const thenable = {
  then(resolve, reject) {
    reject('出错了');
  }
};

Promise.reject(thenable)
.catch(e => {
  console.log(e === thenable)
})
// true

3)Generators

生成器是一种特殊的函数,能够暂停输入,稍后回复,而且允许其他代码在此期间运行。

代码本身决定了它必须等待,以便让其他代码“按照队列”顺序运行,而且保留了“当等待”完成时恢复操作的权利。所有的这些都通过一个简单的关键字  yield  来完成,当一个生成器包含该关键字,代码将暂停执行,生成器可以包含多个 yield 关键字,因此可以暂停很多次,并且通过 *function()来标识。

 。注:

 。生成器运行中双向通信

 。持久的 while 循环,程序不会被冻结

componentDidMount () {
    function *cal(arr) {                 //1   calc = cal(3)
      var i = 2 * (yield (arr / 2));   
      var n = yield (i)
      console.log(i)                   //16   calc.next(8)
      console.log(n)                   //15
      return (i +n +arr)

    }
    const calc = cal(3)
    calc.next()
    calc.next(8)
    calc.next(15)
  }

4)let和const

var是传统的函数作用域

let是新的声明变量的方法,拥有块级作用域;这意味着在 for 循环中、if 语句内或者 plain 块中使用 let 声明的变量不会“逃出”所在的块,而var则会被提升到函数定义;

const和let相似,只是值不可更改且要初始化。

let特点:

。不存在变量提升

// var 
console.log(v1); // undefined
// 由于变量提升 代码实际如下
var v1;
console.log(v1)
v1 = 2;

// let 
console.log(v2); // ReferenceError
let v2 = 2;

。不允许重复声明

let 和 const 在相同作用域下,都不能重复声明同一变量,并且不能在函数内重新声明参数

// 1. 不能重复声明同一变量
// 报错
function f1 (){
    let a = 1;
    var a = 2;
}
// 报错
function f2 (){
    let a = 1;
    let a = 2;
}

// 2. 不能在函数内重新声明参数
// 报错
function f3 (a1){
    let a1; 
}
// 不报错
function f4 (a2){
    {
        let a2
    }
}

const特点:

声明一个只读的常量

。const声明后无法修改值

const PI = 3.1415926;
PI = 3; 
// TypeError: Assignment to constant variable.

。const声明时必须赋值

const a ; 
// SyntaxError: Missing initializer in const declaration.

。const声明的常量,let不能重复声明

const PI = 3.1415926;
let PI = 0;  
// Uncaught SyntaxError: Identifier 'PI' has already been declared

 

5)classes类

JavaScript内部实现继承的语法糖

ES6中的class可以看作只是一个语法糖,大部分功能都可以用ES5实现,并且,类和模块的内部,默认就是严格模式,不需要使用use strict指定运行模式。

componentDidMount () {               
    class Person {
      constructor(name) {
        // super(name)父类中不写,在子类中必须写
        this.name = name
      }
      hello() {
        return 'Hello, I am ' + this.name + '.'
      }
    }

    class Actor extends Person {                    //extends继承
      hello() {
        return super.hello() + ' I am an actor.'   //super,继承父类的方法和对象
      }
    }
    var tomCruise = new Actor('Tom Cruise')
    console.log(tomCruise.hello())     //Hello, I am Tom Cruise. I am an actor.
  }
classes继承
componentDidMount () {               
    class P {
      constructor (x,y) {
        this.x = x
        this.y = y
      }
      toDemo () {
        return (
          this.x + this.y
        )
      }
    }
    let a = new P(1,2)
    console.log(a.toDemo())   //3
  }

注意:class不存在变量提升,ES6中的类不存在变量提升

new P ();   // ReferenceError
class P{...};

class的name属性:

  name属性总是返回紧跟在class后的类名

class P {}
P.name;  // 'P'

constructor ()方法:

在使用 new 实例化类时被调用

  constructor()是类的默认方法,通过 new 实例化时自动条用执行,一个类必须有一个 constructor()方法,否则会默认添加一个空的 constructor(),默认返回实例化对象(this)

class P { ... }
// 等同于
class P {
    constructor(){ ... }
}

类的实例对象:

与ES5一样,ES6的类必须使用 new 实例化,否则报错

class P { ... }
let a = P (1,2);     // 报错
let b = new P(1, 2); // 正确

  与ES5一样,实例的属性除非显示定义在其本身,(即定义在 this 对象上),否则都是定义在原型上(即定义在 class 上)

class P {
    constructor(x, y){
        this.x = x;
        this.y = y;
    }
    toString(){
        return '(' + this.x + ', ' + this.y + ')';
    }
}
var point = new Point(2, 3);

point.toString() // (2, 3)

point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false 
point.__proto__.hasOwnProperty('toString') // true
// toString是原型对象的属性(因为定义在Point类上)

私有方法和私有属性:

由于Es6不提供,只能变通实现:

。1.使用命名加以区别,如变量名前加 _ ,但是不保险,外面也可以调用到

class P {
    // 公有方法
    f1 (x) {
        this._x(x);
    }
    // 私有方法
    _x (x){
        return this.y = x;
    }
}

。2.将私有方法移除模块,再在类内部调用 call 方法

componentDidMount () {               
    class P {
      f1(x) {
        return f2.call(this, x);
      }
    }
    function f2(x) {
      return this.y = x;
    }

    let a = new P()
    console.log(a.f1(1))  //1

  }

。3使用 symbol 为私有方法命名

componentDidMount () {               
    const a1 = Symbol('a1');
    const a2 = Symbol('a2');
    class P {
      // 公有方法
      f1(x) {
        return this[a1](x);
      }
      // 私有方法
      [a1](x) {
        return this[a2] = x;
      }
    }


    let a = new P()
    console.log(a.f1(5))  //5

  }

 

 

 

 

 

 

 

 

 

6)模块化

在ES5之前至少有三个模块化标准,这分裂了整个社区

。AMD

。RequireJS

。CommonJS

ES5制定了统一的模块化标准

导入模块

import ...from..
import * from 'mymodule'
import React from 'react'
import { React, Component } from 'react'
import React as MyLibrary from 'react'

导出模块

export default...
export var foo = 2
export function bar() { /* ... */ }

7)模板字符串

模板字符串是创建字符串的新方法

const arr = `22222`
  const brr = `模板字符串:${arr}`
  console.log(brr)  //
模板字符串:22222

const arr = `模板字符串:${this.foo() ? 'true' : 'false'}`
    console.log(arr)  //true

  }
  foo () {
    return true
  }

8)参数默认值

foo (index = 1, key = 10) {
    return (index + key)
  } 

console.log(`参数默认值:${this.foo()}`)  //参数默认值:11

9)拓展运算符

你可以通过扩展运算符 ... 扩展数组,对象或者是字符串。

    const arr = {a:'a',b:'b',c:'c'}
    const brr = {...arr}     //可以这样复制对象
    console.log(brr)
    const arr = [1,2,3,4,5]   
    console.log([...arr, 10, 1, 5]) //[1, 2, 3, 4, 5, 10, 1, 5]  可以这样创建一个新数组
    const arr = [1,2,3,4,5]
    const brr = [...arr]        //可以这样复制一个数组
    console.log(brr) //[1, 2, 3, 4, 5]
    const arr = 'hello'
    const brr = {...arr}   //可以这样拓展字符串为对象
    console.log(brr)   //{0: "h", 1: "e", 2: "l", 3: "l", 4: "o"}
    const arr = 'hello'
    const brr = [...arr]   //可以这样拓展字符串为数组
    console.log(brr)   //["h", "e", "l", "l", "o"]

这个运算符非常有用。最重要的就是可以以一种十分简单的方式为一个函数传递数组形式的参数:

const f = (foo, bar) => {}
const a = [1, 2]
f(...a)

以前你可以使用 f.apply(null, a) 达到同样的效果,但是它不是很易读。

 10)解构赋值

  按照一定模式从 数组/对象 中提取值,对变量进行赋值,被称为解构

。数组结构

let a = 1;
let b = 2;
let c = 3;


//ES6  从数组中提取值,按照对应位置对变量进行赋值
let [a, b, c] = [1, 2, 3];

 

let [a, [[b], c]] = [1, [[2], 3]];
console.log(a, b, c); // 1, 2, 3

let [ , , c] = [1, 2, 3];
console.log(c);       // 3

let [a, , c] = [1, 2, 3];
console.log(a,c);     // 1, 3

let [a, ...b] = [1, 2, 3];
console.log(a,b);     // 1, [2,3]

let [a, b, ..c.] = [1];
console.log(a, b, c); // 1, undefined, []

1)注意点:

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

let [a] = [];     // a => undefined
let [a, b] = [1]; // a => 1 , b => undefined

。当右边模式大于左边,也可以解构成功

let [a, b] = [1, 2, 3];
console.log(a, b); // 1, 2

。两边模式不同,报错

let [a] = 1;
let [a] = false;
let [a] = NaN;
let [a] = undefined;
let [a] = null;
let [a] = {};

2)指定解构的默认值:

基础用法:

let [a = 1] = [];      // a => 1
let [a, b = 2] = [a];  // a => 1 , b => 2

特殊情况:

let [a = 1] = [undefined]; // a => 1
let [a = 1] = [null];      // a => null

右边模式对应的值,必须严格等于undefined,默认值才能生效,而null不严格等于undefined

。对象解构赋值

与数组解构不同的是,对象解构不需要严格按照顺序取值,而只要按照变量名去取对应名的值,若取不到对应属性名的值,则为undefined

  基础用法:

let {a, b} = {a:1, b:2};  // a => 1 , b => 2
let {a, b} = {a:2, b:1};  // a => 2 , b => 1
let {a} = {a:3, b:2, c:1};// a => 3
let {a} = {b:2, c:1};     // a => undefined

注意点:

let {a:b} = {a:1, c:2}; 
// error: a is not defined
// b => 1

对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
上面代码中,a 是匹配的模式,b才是变量。真正被赋值的是变量b,而不是模式a

  对象解构也支持嵌套解构:

let obj = {
    a:[ 1, { b: 2}]
};
let {a, a: [c, {b}]} = obj;
// a=>[1, {b: 2}], b => 2, c => 1

  指定解构的默认值:

let {a=1} = {};        // a => 1
let {a, b=1} = {a:2};  // a => 2, b => 1

let {a:b=3} = {};      // b => 3
let {a:b=3} = {a:4};   // b = >4
// a是模式,b是变量 牢记

let {a=1} = {a:undefined};  // a => 1
let {a=1} = {a:null};   // a => null
// 因为null与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

。数值和布尔值的解构赋值

结构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转化为对象,由于undefined和null无法转化为对象,所以对他们结构会报错

// 数值和布尔值的包装对象都有toString属性
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true

let { prop: x } = undefined; // TypeError
let { prop: y } = null;      // TypeError

。函数参数的解构赋值

function fun ([a, b]){
    return a + b;
}
fun ([1, 2]); // 3

指定默认值解构:

function fun ({a=0, b=0} = {}){
    return [a, b];
}
fun ({a:1, b:2}); // [1, 2]
fun ({a:1});      // [1, 0]
fun ({});         // [0, 0]
fun ();           // [0, 0]

function fun ({a, b} = {a:0, b:0}){
    return [a, b];
}
fun ({a:1, b:2}); // [1, 2]
fun ({a:1});      // [1, undefined]
fun ({});         // [undefined, undefined]
fun ();           // [0, 0]

。应用

交换变量的值:

let a = 1,b = 2;
[a, b] = [b, a]; // a =>2 , b => 1 

函数返回多个值:

// 返回一个数组
function f (){
    return [1, 2, 3];
}
let [a, b, c] = f(); // a=>1, b=>2, c=>3

// 返回一个对象
function f (){
    return {a:1, b:2};
}
let {a, b} = f();    // a=>1, b=>2

快速对应参数:

function f([a, b, c]) {...}
f([1, 2, 3]);

function f({a, b, c}) {...}
f({b:2, c:3, a:1});

提取JSON数据:

function f([a, b, c]) {...}
f([1, 2, 3]);

function f({a, b, c}) {...}
f({b:2, c:3, a:1});

遍历Map结构:

??
const m = new Map(); m.set('a':1); m.set('b':2); for ([k, v] of m){ console.log(k + ' : ' + v); } // 获取键名 for (let [k] of m){...} // 获取键值 for (let [,k] of m){...}

输入模块指定的方法:用于按需加载模块中需要用到的方法

const {log, sin, cos} = require('math');

11)for...of...循环

2009年的 ES5 引入了 forEach() 循环。虽然很好,但是不能像 for 那样中途跳出循环。

ES2015 引入了 for-of 循环,结合了 forEach 的简洁和跳出循环的能力。

//iterate over the value
for (const v of ['a', 'b', 'c']) {
  console.log(v);
}
//get the index as well, using `entries()` entries 这个方法返回一个 [key, value] 形式的包含对象自身所有属性及值的数组,数组也可用

 12)set和map数据结构

  。set

  介绍:

  set数据结构类似数组,单所有成员的值唯一。

  set本身为一个构造函数,用来生成一个set数据结构,使用add方法来添加新成员

componentDidMount () {
      let a = new Set();
      [1,2,2,1,3,4,5,4,5,10,7].forEach(x=>a.add(x));
      console.log(a)   //{1, 2, 3, 4, 5, …}
        console.log([...a]) //[1, 2, 3, 4, 5, 10, 7]

for(let k of a){ console.log(k) }; // 1 2 3 4 5 }

  基础使用:

let a = new Set([1,2,3,3,4]);
[...a]; // [1,2,3,4]
a.size; // 4

// 数组去重
[...new Set([1,2,3,4,4,4])];// [1,2,3,4]
 componentDidMount () {
      let a = [5,1,6,4,8,7,8,5,1]
      a = [...new Set(a)]
      console.log(a)     //[5, 1, 6, 4, 8, 7]

      
    }

注意:

想 set 中添加值得时候不会进行类型转换,即 6 和 ‘6’ 是不同的

[...new Set([5,'5'])]; // [5, "5"]

属性和方法:

  属性:

    。set.prototype.constructor:构造函数,默认是set函数

    。set.prototype.size:返回set示例成员总数

  方法:

    。add(value):添加值,返回添加后的set

    。delete(value):删除某个值,返回一个布尔值,表示删除状态

    。has(value):返回一个布尔值,表示某个值是否为set成员

    。clear():清除所有成员,没有返回值

let a = new Set();
a.add(1).add(2); // a => Set(2) {1, 2}
a.has(2);        // true
a.has(3);        // false
a.delete(2);     // true  a => Set(1) {1}
a.clear();       // a => Set(0) {}

应用:

  。数组去重:

 

方法1:
componentDidMount () {
      let a = [5,1,6,4,8,7,8,5,1]
      a = [...new Set(a)]
      console.log(a)     //[5, 1, 6, 4, 8, 7]

      
    }

方法2:
componentDidMount () {
      
      let a = [6,2,3,2,6]
      a = new Set(a)
      a = Array.from(a)
      console.log(a)  //[6, 2, 3]
  
    }

  。遍历和过滤:

遍历:
componentDidMount () {

      let a = [6,2,3,2,6]
      a = new Set(a.map(x => x*3))
      console.log([...a])  //[18, 6, 9]
  
    }

过滤:
componentDidMount () {

      let a = [6,2,3,2,6]
      a = new Set(a.filter(x => (x%2 === 0)))
      console.log([...a])  //[6, 2]
  
    }

  。获取并集、交集、差集:

       let a = new Set([1,2,3]);
       let b = new Set([4,3,2]);


并集:
      let c1 = new Set([...a,...b])   //...a将数组/类对象转为用(,)分隔的参数序列
      console.log([...c1])  //[6, 2, 3, 9]
// 交集
      let c2 = new Set([...a].filter(x => b.has(x))); // set {2,3}

// 差集
      let c3 = new Set([...a].filter(x => !b.has(x))); // set {1}

  。遍历方法:

    。key():返回键名的遍历器

    。values():返回键值的遍历器

    。entries():返回键值对的遍历器

    。forEach():使用回调函数遍历每个成员

set 遍历顺序是插入顺序,当保存多个回调函数,只需按照顺序调用;但由于 set 结构没有键名,只有键值,所以 key() 和 values() 返回的是相同结果

let a = new Set(['a','b','c']);
for(let i of a.keys()){console.log(i)};   // 'a' 'b' 'c'
for(let i of a.values()){console.log(i)}; // 'a' 'b' 'c'
for(let i of a.entries()){console.log(i)}; 
// ['a','a'] ['b','b'] ['c','c']

并且还可以直接使用for ... of直接遍历 set

let a = new Set(['a','b','c']);
for(let k of a){console.log(k)};   // 'a' 'b' 'c'

forEach()与数组相同,对每个成员执行操作,且无返回值

let a = new Set(['a','b','c']);
a.forEach((v,k) => console.log(k + ' : ' + v));  //a:a 1:1 c:c

 13)proxy

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3、ES7新增特性

1 )求幂运算符(**)

let n = 4
console.log(n**3) //64

2)Array.prototype.includes()方法

该方法主要用于判断一个数组中是否包含某个指定的值,包含返回 true 不包含返回false

let n = [1,2,3,4]
        console.log(n.includes(2))  //true

。参数(text,index):text指定的值,index默认是0指定开始搜索的位置

。与indexOf()区别:

   1)返回值

        indexOf()返回的是值类型,includes()返回的是布尔型;在if条件判断中includes()要简单的多,而indexOf()需要多写一个条件判断

        

        let n = [1,2,3,4]
        console.log(n.includes(2))  //true
        console.log(n.includes(9))  //false
        console.log(n.indexOf(2))   //1
        console.log(n.indexOf(9))   //-1
        // ------------------------includes()
        if( n.includes(2) ) {
            console.log('存在:' + n.includes(2))  //存在:true
        } else {
            console.log('不存在:' + n.includes(9))  //不存在: false
        }
        //-----------------------indexOf()
        if( n.indexOf(2) == 1) {
            console.log('存在:' + n.indexOf(2))   //存在: 1
        } else {
            console.log('不存在:' + n.indexOf(9))  //不存在: -1
        }

  2)NaN的判断

     indexOf()无法判断

        let n = [NaN]
        console.log(n.includes(NaN))  //true  存在即判断为true
        console.log(n.indexOf(NaN))   //-1   即使存在也判断为-1

3)空值判断   

当数组有空值的时候,includes()会认为空的值是undefined。indexOf()不会

        let n = new Array(3)会将空值
        console.log(n.length)  //3
        console.log(n)  //[empty × 3]
        console.log(n.includes(undefined))  //true  
        console.log(n.indexOf(undefined))   //-1  

 4、ES8新特性

  主要新功能:

    。异步函数:Async Functions(Brian Terlson)

   。共享内存和Atomics(Lars T. Hansen)

  次要新功能:

    。Object.values / Object.entries

    。String padding

    。Object.getOwnPropertyDescriptors()

    。函数参数列表和调用中的尾逗号

1)异步函数(Async/await)

  概念:同步/异步函数

  。同步函数:当一个函数是同步执行时,那么当该函数被调用时不会立即返回,而是被挂载起来执行后面的操作,直到该函数所要做的事情全部做完才返回;

  。异步函数:当一个函数是异步执行时,该函数会立即返回,尽管该函数规定的操作任务还没有返回,该函数的所有操作做完了再执行该函数后面的操作;

  。同步/异步对线程的影响:

     1)当线程调用同步函数时:如果该函数没有立即完成规定的操作,则该未完成的函数操作会被线程挂载起来,执行该函数后面的语句(同时将CUP的使用权交给系统,让系统分配给其他线程使用),直到后面语句规定的操作完成才将该函数未完成的操作重新放到线            程中执行;

     2)当线程调用异步函数时:该函数会立即执行,规定的操作都执行完后,才会执行后面的语句;

          注:规定的操作即使没有及时完成,也依然会在线程中等待着执行,并不会被挂载起来

    async function asyncDemo () {
            const a = await new Promise((resolve) => {
                setTimeout(() => {
                    resolve('aa')
                    aa()
                },2000)
            })
            const b = await new Promise ((resolve) => {
                setTimeout(() => {
                    resolve('bb')
                    bb()
                },2000)
            })
            const c = await new Promise ((resolve) => {
                setTimeout(() => {
                    resolve('cc')
                    cc()
                },2000)
            })
        }
        function aa () {
            let a = [1,2,3,4]
            console.log('aa')
            for (key in a ) {
                console.log(key)
            }
        }
        function bb () {
            console.log('bb')
        }
        function cc () {
            console.log('cc')
        }
        asyncDemo()      // aa 0 1 2 3 bb cc
异步函数(1)
// async function foo() {
        //     // (1)
        //     var a =await new Promise((resolve) => {           //;这里执行完才会执行后面的操作,若不加await,则console.log(a)输出 Promise {<pending>}
        //         setTimeout(() => {
        //             resolve(1);
        //             console.log(0)  
        //         }, 2000);
        //     });
        //     console.log(a); // 第2秒时输出: 1

        //     // (2)
        //     try {                                                //;上一步操作执行后即执行该操作,该操作执行完后再执行后面的操作
        //         var b =await new Promise((resolve, reject) => {  //try...catch语句将能引发错误的代码放在try块中,并且对应一个响应,然后有异常被抛出
        //             setTimeout(() => {
        //                 reject(2);
        //             }, 1000);
        //         })
        //     } catch (e) {
        //         console.log(e); // 第3秒时输出: 2
        //     }

        //     // (3)
        //     // 函数暂停2秒后再继续执行
        //     var sleep =await new Promise((resolve) => {         //;上一步操作执行后即执行该操作 
        //         setTimeout(() => {
        //             resolve('sleep');
        //         }, 2000);
        //     });

        //     var c = 3;
        //     console.log(c); // 第5秒时输出: 3
        // }

        // foo();
        // 不使用async/await输出: Promise {<pending>} 、3 、(Uncaught (in promise) 2 )、0
        //使用async/await输出:0 1 2 3
异步函数(2)