简介:ES6是JS的一种规范,也是JS的新特性

变量声明

1.let关键字

  • 特性:

    • 变量不能重复声明

      1
      2
      3
      4
      5
      6
      // 报错
      let star = '123'
      let star = '456'
      // 不报错
      var star = '123'
      var star = '456'
    • 在该处的块级作用域才生效

      if,else,while,for也是有相同的效果的

      1
      2
      3
      4
      5
      // 报错,但是使用var就不会报错
      {
      let star = "k"
      }
      console.log(star)
    • 不存在变量提升

    • 不影响作用域链:函数内部还是可以访问到外部的变量的【可以闭包】

      1
      2
      3
      4
      5
      6
      let k = "asd"
      function fn(){
      console.log(k)
      }
      fn()
      // output: asd
  • 经典案例

    1
    2
    3
    4
    5
    for(var i = 0; i < 3; i++){
    items[i].onClick = function(){
    items[i].style.background = 'pink'
    }
    }

    上面的代码就会导致错误,因为在上面,i是全局的,然后在监听触发的时候,i就已经无视代码块变成了3,接着在里面找不到items[3]导致报错

    因此需要将var变成let,这样的话,i就不会污染三个块级区域了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    for(let i = 0; i < items.length; i++){
    items[i].onClick = function(){
    items[i].style.background = 'pink'
    }
    }

    // ----------这也是其中一种方法,用this来确定i------------- //

    for(var i = 0; i < items.length; i++){
    items[i].onClick = function(){
    this.style.background = 'pink'
    }
    }

2.const关键字

  • 作用:用于声明常量

  • 注意事项:

    • 一定要赋初始值,不然报错

    • 一般常量使用大写

    • 常量的值不能修改

    • 它也用于块级作用域

    • 对于数组和对象的元素修改,不算作对常量的修改,不会报错

      1
      2
      3
      4
      5
      6
      // 不会报错
      const TEAM = ['UZI', 'AUG']
      TEAM.push('XM8')

      // 会报错
      TEAM = 100

      原因:常量值虽然发生了变化【指增加删减元素】,但是常量的栈地址没有发生变化,只变了堆内存地址,因此不会报错

解构赋值

  • ES6允许按照一定模式从数组对象中来提取值,对变量进行赋值

1.数组的结构赋值

1
2
3
4
const F = ['UZI', 'AUG', 'XM8']
let [gun1, gun2, gun3] = F
console.log(gun1)
// output:UZI

我们发现都是自己根据位置来赋值的

2.对象的解构

1
2
3
4
5
6
7
8
9
const p = {
name: 'UZI',
age: 18,
action: function(){
console.log(this.name)
}
}
let {name} = p
console.log(name)

我们发现与数组类似,都是直接取出,如果不打算全部取的话,就必须按照属性原名取出即可

模板字符串

1.声明方式

1
let str = `I_am_a_string`

2.与普通字符串的区别

  • 内容中可以出现换行符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 错误的,只能通过加法拼接,并且还没有换行符
    let str = "<ul>
    <li>example</li>
    </ul>"

    // 模板字符串
    let str = `<ul>
    <li>example</li>
    </ul>`
  • 可以拼接变量

    1
    2
    3
    let exp = "示例"
    let out = `${exp}显示成功`
    // output:示例显示成功

对象写法

  • 在ES6里面允许在大括号直接写入变量和函数【类似于vue】

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    let name = 'lkd'
    let change = function(){
    console.log('lkd')
    }

    // 这就是ES6的简化写法,类似于vue中引入组件一样
    // 在这里也可以用下面直接声明的方法【以ins为例】
    const object = {
    name,
    change,
    // 这个地方等价于:
    // ins: function(){}
    ins(){
    console.log('即时创建简化声明的方法')
    }
    }

函数相关

1.箭头函数

特性

  • this是静态的,this始终是指向函数声明时所在作用域下的this的值

    • call方法是可以用来改变作用域的,但是箭头函数是静态的,this不会遭到变动,因此使用call方法是不会发生变化的

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      function getName(){
      console.log(this.name)
      }
      let getName2 = () => {
      console.log(this.name)
      }

      window.name = "lkd"

      const obj = {
      name: "obj"
      }
      // 输出lkd,lkd
      getName()
      getName2()
      // 输出obj,lkd
      getName.call(obj)
      getName2.call(obj)
    • 因此不能作为构造函数实例化对象,否则报错

      1
      2
      3
      4
      5
      6
      7
      // 报错,不能产生实例化对象
      let person = (name, age) => {
      this.name = name
      this.age = age
      }
      let m = new person("123",123)
      console.log(m)
  • 不能使用arguments变量

1
2
3
4
5
// 报错,因为已经没有arguments对象了
let fn = () => {
console.log(arguments)
}
fn(1, 2, 3)

简写方法

  • 只有一个参数时,省略小括号

    1
    2
    3
    let fn = n => {
    console.log(n)
    }
  • 只有一个return语句时,省略花括号和return

    1
    let fn = (m, n) => m * n

2.参数相关

默认值

  • 我们可以给函数添加默认值,但是有默认值的必须放到最后

    1
    2
    3
    4
    5
    6
    const p = (a, b, c = 10) => {
    return a + b + c
    }
    // output: 23
    // 在这里因为没有传入c,因此c传入默认值10
    p(1, 2)
  • 一定程度上可以和解构赋值结合书写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    const p = ({host, username, password, port}) => {
    console.log(host)
    console.log(username)
    console.log(password)
    console.log(port)
    }
    // output: 127.0.0.1, root, root, 3306
    p({
    host: 127.0.0.1,
    username: root,
    password: root,
    port: 3306
    })

rest参数

  • 在ES6废弃了arguments之后,我们使用rest参数来获取函数的参数变量

    就是将变量当作是数组传入,然后再解出来

    1
    2
    3
    4
    5
    const p = (...args) => {
    console.log(args)
    }
    // output: [1, 2, 3, 4, 5, 6]
    p(1, 2, 3, 4, 5, 6)
  • 与argument不同的是,rest参数是数组存储,更具灵活性;而arguments使用对象存储

  • rest参数必须放到最后,不然会报错

    1
    2
    3
    4
    5
    6
    7
    const p = (a, b, ...args) => {
    console.log(a)
    console.log(b)
    console.log(args)
    }
    // output: 1, 2, [3, 4, 5]
    p(1, 2, 3, 4, 5)

扩展运算符

1.扩展运算符的定义与作用

  • 符号:...

  • ...可以将数组拆出

    1
    2
    3
    4
    5
    6
    const arr = [1, 2, 3, 4, 5]
    const fn = (arr) => {
    console.log(...arr)
    }
    // output: 1 2 3 4 5
    fn(arr)

2.扩展运算符应用

  • 合并数组

    1
    2
    3
    4
    5
    var arr1 = [1, 2, 3]
    var arr2 = ['UZI', 'AUG', 'XM8']
    var arrFinal = [...arr1, ...arr2]
    // output: 1 2 3 'UZI' 'AUG' 'XM8'
    console.log(arrFinal)

    当然,我们也可以使用concat来实现

    1
    2
    3
    4
    5
    var arr1 = [1, 2, 3]
    var arr2 = ['UZI', 'AUG', 'XM8']
    var arrFinal = arr1.concat(arr2)
    // output: 1 2 3 'UZI' 'AUG' 'XM8'
    console.log(arrFinal)
  • 克隆数组

    1
    2
    var arr1 = [1, 2, 3]
    var arr2 = [...arr1]
  • 转换伪数组

    HTML文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    <div></div>
    <div></div>
    <div></div>
    </body>
    </html>

    js文件:

    1
    2
    3
    4
    5
    6
    7
    const divs = document.querySelectorAll('div')
    // output: [div, div, div]
    // 虽然是数组,但是是有原型对象的,为ListNode,是伪数组
    console.log(divs)
    const divArr = [...divs]
    // 这样就是数组了,有数组的方法
    console.log(divArr)

Symbol

1.定义

  • Symbol是ES6的一种新的数据类型,类似于字符串的数据类型

  • Symbol表示独一无二的值,就算是两个变量的数值相同,在判定的时候也会被判为false

2.共享体系

  • Symbol也有for方法来创建对象,可以作为一个共享体系

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    let s = Symbol()
    // output: Symbol() 'symbol'
    console.log(s, typeof(s))

    // ---------------------------- //
    let s2 = Symbol('lkd')
    let s3 = Symbol('lkd')
    // output: false
    console.log(s2 === s3)

    // ---------------------------- //
    let s4 = Symbol.for('lkd')
    let s5 = Symbol.for('lkd')
    // output: true
    console.log(s4 === s5)
  • 我们可以使用Symbol.keyFor()方法在Symbol全局注册表中检索是否有该键对应值

    1
    2
    3
    4
    5
    6
    let k1 = Symbol.for('k1')
    let k2 = Symbol('k2')

    // output: k1 undefined
    console.log(Symbol.keyFor(k1))
    console.log(Symbol.keyFor(k2))

3.特点

  • 不能和其他数据进行运算

    1
    2
    // 报错
    let result = s4 + '100'
  • 唯一性极高

4.使用方法

  • 给对象添加独一无二的属性和方法

    比如,我想给obj添加属性,但是不确定该属性有没有,就可以使用symbol了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let game = {}
    let methods = {
    up: Symbol(),
    down: Symbol()
    }
    game[methods.up] = function(){
    console.log("up")
    }
    game[methods.down] = function(){
    console.log("down")
    }
    console.log(game)
  • 当然,我也可以直接在对象内部添加方法

    1
    2
    3
    4
    5
    let game = {
    [Symbol('say')]: function(){
    console.log("say")
    }
    }

5.Symbol内置值

  • Symbol.hasInstance:当其他对象使用instanceof运算符,判断是否为该对象的实例时就会使用这个方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Person {
    static [Symbol.hasInstance](param){
    console.log(param)
    console.log("lkd")
    }
    }

    let o = {}

    // output: {}
    // lkd
    // false
    console.log(o instanceof Person)
    // output: false
    console.log(Person[Symbol.hasInstance](o))

    为什么不只用instanceof方便呢?因为在这里我们可以随便改变instanceof的运行方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Person {
    static [Symbol.hasInstance](param){
    return false
    }
    }
    let o = new Person()
    // output: false
    // 在这里本来是true才是正常的,但是我们硬编码了实例对象的判定方法
    console.log(o instanceof Person)
  • Symbol.isConcatSpreadable:布尔值,用于表示是否将集合内元素归类到一个层级

    数组拼接的时候都会将数组展开成零散的数

    也就是说,该值是为了判断是否展开该层级

    1
    2
    3
    4
    5
    6
    7
    const arr = [1, 2, 3]
    const arr2 = [4, 5, 6]
    // output: [1, 2, 3, 4, 5, 6]
    console.log(arr.concat(arr2))
    arr2[Symbol.isConcatSpreadable] = false
    // output: [1, 2, 3, [4, 5, 6]]
    console.log(arr.concat(arr2))

迭代器

1.作用

  • 用于为各种不同的数据结构提供统一的访问机制
  • 使得数据结构成员能够按某种次序排列
  • ES6创造了一个新的遍历命令for-of循环
  • 迭代强调依次取出

2.工作原理

  • 创建一个指针对象,指向当前数据结构的起始位置
  • 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
  • 接下来不断调用next方法,指针一直向后移动,只得到指向最后一个成员
  • 每调用next方法返回一个包含value和done属性的对象
1
2
const arr = ['AUG', 'XM8', 'UZI']
let iterator = arr[Symbol.iterator]()

3.自定义遍历数据

  • [Symbol.iterator]:迭代方法,可以内置于对象中,作为for-of的迭代方式
    • 可以自定义遍历哪个属性的对象
    • 可以自定义遍历顺序
  • next方法:用于规定循环的下一个对象是谁,通常是一个有着value和done的对象,通常是一个函数
    • value:定义下一个指针的指向
    • done:定义是否再进行一次指向
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const _class = {
name: 'class1',
arr: [
'UZI',
'XM8',
'AUG'
],
[Symbol.iterator](){
let index = 0
return {
// 在这里使用箭头函数,是因为这里是块作用域
next: () => {
if(index < this.arr.length){
return {
// 遍历值为arr属性的值
value: this.arr[index++],
done: false
}
}else{
return {
value: undefined,
done: true
}
}
}
}
}
}
// 如果没有自定义,of类型只能遍历数据结构,是默认遍历_class所有属性的
for(let v of _class){
// output: UZI XM8 AUG
console.log(v)
}

// ---------------------------------------------------- //
const ex = ['UZI', 'XM8', 'AUG']

// 如果没有自定义,of类型只能遍历数据结构
for(let v of ex){
// output: UZI XM8 AUG
console.log(v)
}

// 遍历的只是索引下标
for(let v in ex){
// output: 0 1 2
console.log(v)
}

4.新增的数据结构

集合

  • Set():集合,里面的数都有着不重复的特性

    注意,要用let来定义

    1
    2
    let set = new Set([1, 2, 3, 3, 4, 4])
    console.log(set)
  • 方法主要为:

    • has(x):用于判断值x是否存在于集合中

    • add(x):添加元素x

    • delete(x):删除元素x

    • clear():删除所有元素

    • size():返回集合长度

    • 我们一般转回数组都是使用Array.from(set)来将集合转换为数组,当然from方法就是用来转换数据结构的

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      var arr = [1, 2, 2, 3, 4, 5]
      let set = new Set(arr)
      // output: false
      console.log(set.has(6))
      // set[1, 2, 3, 4, 5, 6]
      set.add(6)
      console.log(set)
      // set[2, 3, 4, 5, 6]
      set.delete(1)
      console.log(set)
      // 5
      console.log(set.size)
      var arr2 = Array.from(set)
      // array[2, 3, 4, 5, 6]
      console.log(arr2)
  • 上面的方法是链式的

    1
    2
    3
    4
    5
    6
    7
    8
    let set = new Set()
    let a = NaN
    let b = NaN
    let c = {}
    let d = {}
    // 记住,两个对象的栈地址不相同,那么他们也就不相同
    // [NaN, {}, {}]
    set.add(a).add(b).add(c).add(d)

映射

  • Map():映射,里面存的是键值对,当然比对象更加好,因为可以使用任意值作为键值

    当然,里面的键值对也有不重复的特性

1
2
3
const map = new Map([[1, 2], [3, 4], [1, 2]])
// output: 2
console.log(map.size)
  • 方法主要为:

    • set(x, y):添加键值对(x ,y)

    • get(x):得到键值为x的另一边

    • clear():清空所有键值对

      1
      2
      3
      4
      5
      6
      7
      8
      9
      const map = new Map([[1, 2], [3, 4], [1, 2]])
      // 2
      console.log(map.get(1))
      map.set("string1", "string2")
      // 3
      console.log(map.size)
      map.clear()
      // 0
      console.log(map.size)

生成器

1.定义

  • 生成器是一种ES6独有的异步函数

2.创建方法

  • 使用 * 来创建
  • yield用来分割函数内部作用域
  • next方法用于向下执行作用域
  • 这种函数只能通过next向下执行,否则就会在yield处被切断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function * gen(){
console.log(1)
yield '-----------'
console.log(1)
yield '-----------'
console.log(1)
yield '-----------'
console.log(1)
}
let iterator = gen()
// output: 1
iterator.next()
// output: 2
iterator.next()
// output: 3
iterator.next()
// output: 4
iterator.next()
// output: undefined【因为已经执行完毕了】
iterator.next()

// output:
// 1
// -----------
// 1
// -----------
// 1
// -----------
// 1
// 如果不使用迭代器遍历,那么yield后面的数值也会被遍历显示
for(let v of gen()){
console.log(v)
}

3.生成器的参数传递

  • ()括号内部的可以正常传递

    1
    2
    3
    4
    5
    6
    7
    function * gen(len){
    console.log(len)
    yield '-----------'
    }
    let iterator = gen('123')
    // output: '123'
    iterator.next()
  • next传进来的值会改变yield后面的值

    注意:只能改变下一个yield的值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    function * gen(len){
    console.log(len)
    yield '-----------'
    console.log(1)
    yield '-----------'
    console.log(2)
    const one = yield '-----------'
    console.log(one)
    }
    let iterator = gen('123')
    iterator.next('456')
    iterator.next()
    iterator.next()
    iterator.next('789')

    // output:
    // '123'
    // 1
    // 2
    // '789'

4.异步使用的实例

  • 解除回调地狱
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 1s - 2s - 4s 依次打印
// 回调地狱
setTimeout(() => {
console.log(1)
setTimeout(() => {
console.log(2)
setTimeout(() => {
console.log(3)
}, 4000)
}, 2000)
}, 1000)

// yield方法
// 先依次定义
let one = () => {
setTimeout(() => {
console.log(1)
iterator.next()
}, 1000)
}
let two = () => {
setTimeout(() => {
console.log(2)
iterator.next()
}, 2000)
}
let three = () => {
setTimeout(() => {
console.log(3)
iterator.next()
}, 4000)
}

// 使用生成函数
function * gen(){
yield one()
yield two()
yield three()
}

let iterator = gen()
iterator.next()
  • 拿出函数内部数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
let one = () => {
setTimeout(() => {
var order1 = 'order1'
iterator.next(order1)
}, 1000)
}
let two = () => {
setTimeout(() => {
var order2 = 'order2'
iterator.next(order2)
}, 2000)
}
let three = () => {
setTimeout(() => {
var order3 = 'order3'
iterator.next(order3)
}, 4000)
}

// 使用生成函数
function * gen(){
// 在此,我们一样可以在这里拿到函数内部的值
let one_ = yield one()
console.log(one_)
let two_ = yield two()
console.log(two_)
let three_ = yield three()
console.log(three_)
}

let iterator = gen()
iterator.next()

Promise

1.定义

  • Promise是ES6引入的异步编程的新解决方案
  • 语法上来说它是一个构造函数,用来封装异步操作并可以获取其成功或者失败的结果

2.基本使用

1
2
3
4
5
6
7
8
9
10
11
const p = new Promise(function(resolve, reject){
setTimeout(function(){
let data = 'data'
resolve(data)
})
}).then(function(value){
// 接收data
console.log(value)
}, function(reason){
console.err(reason)
})

3.Promise封装读取文件

  • 读取单个文件
1
2
3
4
5
6
7
8
9
10
11
12
13
var fs = require('fs')
const p = new Promise((resolve, reject) => {
fs.readFile('./ES6.md', (err, data) => {
if(err) reject(err)
resolve(data)
})
})
p.then((value) => {
// 我们拿到了文件,我们可以在这里对该字符串进行操作,然后得到我们想要的
console.log(value.toString())
}, (reason) => {
console.log("error")
})
  • 次序读取多个文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var fs = require('fs')
const p = new Promise((resolve, reject) => {
fs.readFile('./ES6.md', (err, data) => {
resolve(data)
})
})

p.then(value => {
return new Promise((resolve, reject) => {
fs.readFile('./Ajax.md', (err, data) => {
resolve([value, data])
})
})
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile('./JavaScript.md', (err, data) => {
value.push(data)
resolve(value)
})
})
}).then(value => {
console.log(value)
})

4.Promise封装Ajax请求

  • 简易请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 创建对象
    const xhr = new XMLHttpRequest()
    // 初始化
    xhr.open("GET", "https://127.0.0.1:3000/server")
    // 发送请求
    xhr.send()
    // 绑定事件,处理响应结果
    xhr.onreadystatechange = function(){
    if(xhr.readyState === 4){
    if(xhr.status >= 200 && xhr.status < 300){
    console.log(xhr.response)
    }else{
    console.log(xhr.status)
    }
    }
    }
  • 封装请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    const p = new Promise((resolve, reject) => {
    // 创建对象
    const xhr = new XMLHttpRequest()
    // 初始化
    xhr.open("GET", "https://127.0.0.1:3000/server")
    // 发送请求
    xhr.send()
    // 绑定事件,处理响应结果
    xhr.onreadystatechange = function(){
    if(xhr.readyState === 4){
    if(xhr.status >= 200 && xhr.status < 300){
    resolve(xhr.response)
    }else{
    reject(xhr.status)
    }
    }
    }
    })

    p.then((value) => {
    console.log(value)
    }, (reject) => {
    console.err(reject)
    })

ES7新特性

  • 数组添加includes方法

    1
    2
    const arr = ['AUG', 'XM8', 'UZI']
    arr.includes('AWM') // false
  • 幂的计算

    1
    var a = 2 ** 3 // 9

ES8新特性

1.async和await

  • async和await两者可以使异步代码像同步代码执行

async

  • async函数的返回值为promise对象
  • promise对象的结果由async函数执行的返回值决定
1
2
3
4
5
6
7
8
9
10
11
12
async function fn(){
return new Promise((resolve, reject) => {
resolve("success")
})
}

const result = fn()
result.then((value) => {
console.log(value)
}, (reason) => {
console.err(reason)
})

await

  • await必须写在async函数中【单项依赖】
  • await右侧的表达式一般为promise对象
  • await返回的是promise成功的值
  • await的promise失败了就会抛出异常,需要用try-catch捕获处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const p = new Promise((resolve, reject) => {
resolve("success")
})

async function main(){
// 在这里,try执行成功了就正常向下走,失败了就执行catch
try {
// 在这里是从上到下的执行的,低IO的也会被阻塞
let result = await p
console.log(result)
} catch(e){
console.log(e)
}
}
main()

2.借助async和await依次读取文件

借用读取文件的异步,来等价替换为其他的异步也是可行的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const fs = require('fs')

function readF1(){
return new Promise((resolve, reject) => {
fs.readFile('./ES6.md', (err, data) => {
if(err) reject(err)
resolve(data)
})
})
}

function readF2(){
return new Promise((resolve, reject) => {
fs.readFile('./JavaScript.md', (err, data) => {
if(err) reject(err)
resolve(data)
})
})
}

function readF3(){
return new Promise((resolve, reject) => {
fs.readFile('./Ajax.md', (err, data) => {
if(err) reject(err)
resolve(data)
})
})
}

async function main(){
let F1 = await readF1()
let F2 = await readF2()
let F3 = await readF3()

console.log(F1.toString())
console.log(F2.toString())
console.log(F3.toString())
}
main()

3.async和await封装Ajax请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function sendAjax(url){
return new Promise((resolve, reject) => {
const x = new XMLHttpRequest()
x.open('GET', url)
x.send()
x.onreadystatechange = function(){
if(x.readyState === 4){
if(x.status >= 200 && x.status < 300){
resolve(x.response)
}else{
reject(x.status)
}
}
}
})
}


async function main(){
let test1 = await sendAjax('127.0.0.1:3000/')
let test2 = await sendAjax('https://api.apiopen.top/getJoke')

console.log(test2)
}

main()

ES9新特性

1.对象的拓展运算符和rest

  • ...运算符可以对对象使用了,这样就是拆出一系列的键值对,当然也可以用来合上

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    var skill1 = {
    Q: '斩钢闪',
    W: '风之障壁'
    }

    var skill2 = {
    E: '踏前斩'
    }

    var skill3 = {
    R: '狂风绝息斩',
    passive: '浪客之道'
    }

    var skill = {
    ...skill1,
    ...skill2,
    ...skill3
    }
    console.log(skill)
  • 拓展运算符也可以用在对象的属性里面了,这样子传入的对象就可以是属性不确定了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function connect({host, port, ...user}){
    console.log(host)
    console.log(port)
    console.log(user)
    }

    // output: '127.0.0.1' 3306 {username: 'root', password: 'root'}
    connect({
    host: '127.0.0.1',
    port: 3306,
    username: 'root',
    password: 'root'
    })

2.正则扩展

命名捕获分组

  • 注意,正则得到的结果里面有一个groups的对象属性,不对正则到的字符贴标签就为undefined
1
2
3
4
5
6
7
8
9
10
let str = '<a href="http://www.baidu.com">百度</a>'

// 写出正则
const reg = /<a href="(.*)">(.*)<\/a>/
// 执行
const result = reg.exec(str)
// output: array
// ['<a href="http://www.baidu.com">百度</a>', "http://www.baidu.com", "百度"]
// 在这里的groups就是undefined
console.log(result)
1
2
3
4
5
6
7
8
9
10
11
12
let str = '<a href="http://www.baidu.com">百度</a>'

// 写出正则
// ?<name>使用命名分组语法
const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/
// 执行
const result = reg.exec(str)

// output: array
// ['<a href="http://www.baidu.com">百度</a>', "http://www.baidu.com", "百度"]
// 在这里的groups就是[{url: "http://www.baidu.com"}, {text: "百度"}]
console.log(result)

断言

  • 断言:判断匹配结果是否正确的规则

  • 正向断言:根据后面的内容来判断取出字符

    1
    2
    3
    4
    5
    let str = "123123123456qwe123"
    const reg = /\d+(?=qwe)/

    // output: 123123123456
    const result = reg.exec(str)
  • 反向断言:根据前面的内容来判断取出字符

    1
    2
    3
    4
    let str = "123123123456qwe123"
    const reg = /(?<=qwe)\d+/
    // output: 123
    const result = reg.exec(str)

dot-All模式

  • .:代表除了换行符之外的任何一个字符

  • 我们在正则表达式的后面加上gs,进行带换行符的全局匹配

    • 换行符用.*?来表示
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    let str = 
    `<ul>
    <li>电影1</li>
    <p>时间1</p>
    </ul>`
    // /s 换行 g代表global
    // 常规模式匹配:需要将换行符考虑进去
    //const reg = /<ul>\s+<li>(.*?)<\/li>\s+<p>(.*?)<\/p>\s+<\/ul>/
    // dot-All模式:可以将换行符给替换掉为*?
    const reg = /<ul>.*?<li>(.*?)<\/li>.*?<p>(.*?)<\/p>.*?<\/ul>/gs
    let result
    let data = []
    while(result = reg.exec(str)){
    data.push({title: result[1], time: result[2]})
    }
    console.log(data)

ES10新特性

1.对象拓展方法

  • Object.fromEntries:用于创建对象,接收二维数组或者Map

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 二维数组
    const result = Object.fromEntries([
    ['name', 'lkd'],
    ['age', 30],
    ['grade', 3],
    ['class', 2]
    ])
    // {name: 'lkd', age: 30, grade: 2, class: 3}
    console.log(result)

    // 使用Map也是同样的道理
    const map_ = new Map()
    map_.set('name', 'lkd')
    const result2 = Object.fromEntries(map_)
    // {name: 'lkd'}
    console.log(result2)
  • 在ES8中,有将对象转换为二维数组的:Object.entries

    1
    2
    3
    4
    var arr = Object.entries({
    name: 'lkd'
    })
    console.log(arr)

2.字符串扩展方法

  • trimStart:清除左侧的字符

  • trimEnd:清除右侧的字符

  • trim:清除左右两侧的字符

    1
    2
    3
    4
    5
    6
    7
    let str = `     lkd     lkd     `
    // `lkd lkd`
    console.log(str.trim())
    // `lkd lkd `
    console.log(str.trimStart())
    // ` lkd lkd`
    console.log(str.trimEnd())

3.数组方法扩展

  • flat(x):将多为数组转化为低位数组,x表示转化深度

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const arr = [1, 2, 3, 4, [5, 6]]
    // [1, 2, 3, 4, 5, 6]
    console.log(arr.flat())

    // 三维数组的深度为2
    const arr2 = [1, 2, [3, 4, [5, 6]]]
    // [1, 2, 3, 4, [5, 6]]
    console.log(arr2.flat())

    // [1, 2, 3, 4, 5, 6]
    console.log(arr2.flat(2))
  • flatMap(x):改进map方法,使数组变成一维数组

    1
    2
    3
    4
    5
    const arr = [1, 2, 3]
    // 虽然操作之后的每一个返回值是数组,但是还是将其变成了低位数组
    const result = arr.flatMap(item => [item * 10])
    // [10, 20, 30]
    console.log(result)