ES6-ES11易忘笔记

let 经典案例实践

点击切换背景色案例

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    .item{
      width: 100px;
      height: 60px;
      display: inline-block;
      border-radius: 4px;
      border: 2px solid #e06ad4;
    }
  </style>
</head>
<body>
  <div class="content">
    <h2>点击切换颜色</h2>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
  </div>
  <script>
    const items = document.querySelectorAll('.item')

    for(let i = 0; i < items.length; i ++) {
      items[i].onclick = function () {
        items[i].style.backgroundColor = 'pink'
      }
    }
  </script>
</body>
</html>

rest 参数

function fn (a, b, ...args) {
  console.log(a, b, ...args)
}
fn(1,2,3,4)

扩展运算符的应用

将伪数组转为真正的数组

const divs = document.querySelectorAll('div')
const divArr = [...divs]

Symbol

Symbol mdn docs

Symbol 的介绍与创建

// 创建Symbol
let s1 = Symbol()
console.log(s1, typeof s1) // Symbol() 'symbol'

// 判断唯一值
let s2 = Symbol('张三')
let s3 = Symbol('张三')
console.log(s2 === s3) // false

// Symbol.for 创建
let s4 = Symbol.for('张三')
console.log(s4, typeof s4) // Symbol(张三) 'symbol'

// 通过 Symbol.for 方式创建,可以通过 ('张三') 描述字符串得出唯一的 Symbol 值
let s5 = Symbol.for('张三')
let s6 = Symbol.for('张三')
console.log(s5 === s6) // true

// 不能与其他数据进行计算(报错)
// let result = s1 + 1
// let result = s1 > 1
// let result = s1 + s1

Symbol 的应用场景

向对象添加Symbol类型的属性(如果不确定对象中是否有这两个方法可以用Symbol方式添加)

// 向对象中添加方法 up down (game方法中可能已经存在 up down 方法)
let game = {
  up() {
    console.log('up')
  },
  down() {
    console.log('down')
  }
}

// 声明一个对象
let methods = {
  up: Symbol(),
  down: Symbol()
}

game[methods.up] = function () {
  console.log('Symbol up')
}

game[methods.down] = function () {
  console.log('Symbol down')
}

console.log(game) // {up: ƒ, down: ƒ, Symbol(): ƒ, Symbol(): ƒ}

另一种写法

let game = {
  name: 'snake',
  [Symbol('up')]: function () {
    console.log('up')
  },
  [Symbol('down')]: function () {
    console.log('down')
  }
}

console.log(game) // {name: 'snake', Symbol(up): ƒ, Symbol(down): ƒ}

Symbol 的内置属性

Symbol.hasInstance 用于判断某对象是否为某构造器的实例。

class Person {
  static [Symbol.hasInstance] (params) {
    console.log(params, '我被用来检测类型了')
    // return true // 可以指定返回值(Boolean)
  }
}

let obj = {
  name: 'obj'
}

console.log(obj instanceof Person) // false

Symbol.isConcatSpreadable 用于配置某对象作为Array.prototype.concat()方法的参数时是否展开其数组元素。

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

ES10 Symbol.prototype.description

let s = Symbol('aaa')
console.log(s.description) // aaa

迭代器

工作原理

  • 创建一个指针对象,指向当前数据结构的起始位置。
  • 第一次调用对象的next方法,指针自动指向数据结构的第一个成员。
  • 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员。
  • 每调用next方法返回一个包含value和down属性的对象

Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。

// 声明一个数组
const arr = ['a', 'b', 'c', 'd']
let iterator = arr[Symbol.iterator]()

console.log(iterator.next()) // {value: 'a', done: false}
console.log(iterator.next()) // {value: 'b', done: false}
console.log(iterator.next()) // {value: 'c', done: false}
console.log(iterator.next()) // {value: 'd', done: false}
console.log(iterator.next()) // {value: undefined, done: true}

迭代器的应用-自定义遍历数据

也可以直接用 obj.arr 遍历,但是不符合面向对象的思想,这里演示用迭代器控制for...of

// 声明一个对象
const obj = {
  name: 'obj',
  arr: ['a', 'b', 'c', 'd'],
  [Symbol.iterator]() {
    let index = 0
    return {
      next: () => {
        if(index < this.arr.length) {
          return { value: this.arr[index ++], done: false }
        } else {
          return { value: undefined, done: true }
        }
      }
    }
  }
}

// 遍历这个对象
for (let v of obj) {
  console.log(v) // 遍历出obj.arr中的数据,依次为 a b c d
}

生成器

  • 生成器其实就是一个特殊的函数。
  • 用于异步编程 纯回调函数 例如使用:node fs、ajax、mongodb。

简单使用

function * gen () {
  console.log('hello generator')
}

// gen()是一个迭代器对象,必须调用next方法才能向下执行
let iterator = gen()
iterator.next()

yield 函数代码的分隔符

function * gen () {
  console.log(111)
  yield 'aaa'
  console.log(222)
  yield 'bbb'
  console.log(333)
  yield 'ccc'
  console.log(444)
}

let iterator = gen()
iterator.next() // 111
iterator.next() // 222
iterator.next() // 333
iterator.next() // 444

for...of遍历

function * gen () {
  // console.log(111)
  yield 'aaa'
  // console.log(222)
  yield 'bbb'
  // console.log(333)
  yield 'ccc'
  // console.log(444)
}

let iterator = gen()
console.log(iterator.next()) // {value: 'aaa', done: false}
console.log(iterator.next()) // {value: 'bbb', done: false}
console.log(iterator.next()) // {value: 'ccc', done: false}
console.log(iterator.next()) // {value: undefined, done: true}

// 遍历
for (let v of gen()) {
  console.log(v) // 依次输出 aaa bbb ccc
}

生成器函数的参数传递

function * gen (arg) {
  console.log(arg) // AAA
  let one = yield 111
  console.log(one) // BBB
  let two = yield 222
  console.log(two) // CCC
  let three = yield 333
  console.log(three) // DDD
}

let iterator = gen('AAA')
console.log(iterator.next()) // {value: 111, done: false}
// next方法可以传入参数(第二个next方法传入的参数作为第一个yield的返回结果)
console.log(iterator.next('BBB')) // {value: 222, done: false}
console.log(iterator.next('CCC')) // {value: 333, done: false}
console.log(iterator.next('DDD')) // {value: undefined, done: true}

生成器函数实例1:1s后输出111,2s后输出222,3s后输出333

使用回调地狱

setTimeout(() => {
  console.log(111)
  setTimeout(() => {
    console.log(222)
    setTimeout(() => {
      console.log(333)
    }, 3000)
  }, 2000)
}, 1000)

使用生成器函数

function one () {
  setTimeout(() => {
    console.log(111)
    iterator.next()
  }, 1000)
}

function two () {
  setTimeout(() => {
    console.log(222)
    iterator.next()
  }, 2000)
}

function three () {
  setTimeout(() => {
    console.log(333)
    iterator.next()
  }, 3000)
}

function * gen() {
  yield one()
  yield two()
  yield three()
}

let iterator = gen()
iterator.next()

生成器函数实例2:先获取用户数据,然后获取订单数据,最后获取商品数据

function getUsers () {
  setTimeout(() => {
    let data = '用户数据'
    // 调用next方法并传入data,注意这是第二次调用next,传入的data将作为第一个yield的返回值
    iterator.next(data)
  }, 1000)
}

function getOrders () {
  setTimeout(() => {
    let data = '订单数据'
    iterator.next(data)
  }, 1000)
}

function getGoods () {
  setTimeout(() => {
    let data = '商品数据'
    iterator.next(data)
  }, 1000)
}

function * gen() {
  let users = yield getUsers()
  console.log(users) // 用户数据
  let orders = yield getOrders()
  console.log(orders) // 订单数据
  let goods = yield getGoods()
  console.log(goods) // 商品数据
}

let iterator = gen()
iterator.next()

Promise

简单封装ajax

const p = new Promise((resolve, reject) => {
  // 1.创建对象
  const xhr = new XMLHttpRequest()
  // 2.初始化
  xhr.open('GET', 'https://api.apiopen.top/api/sentences')
  // 3.发送
  xhr.send()
  // 4.绑定事件,处理相应结果
  xhr.onreadystatechange = function () {
    if(xhr.readyState === 4) {
      // 判断响应状态码 200-299
      if(xhr.status >= 200 && xhr.status < 300) {
        // 表示成功
        resolve(xhr.response)
      } else {
        // 如果失败
        reject(xhr.status)
      }
    }
  }
})

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

then的链式调用

const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    let data = 'aaa'
    resolve(data)
  }, 300)
})

p.then(value => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let data = 'bbb'
      resolve([value, data])
    }, 800)
  })
}).then(value => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let data = 'ccc'
      resolve([...value, data])
    }, 100)
  })
}).then(value => {
  console.log(value) // ['aaa', 'bbb', 'ccc']
})

Set

Set集合实践

// 1.数组去重
let arr1 = [1, 3, 2, 1, 4, 2, 1]
let result1 = [...new Set(arr1)]
console.log(result1) // [1, 3, 2, 4]

// 2.交集
let arr2 = [4, 3, 4, 7]
let result2 = [...new Set(arr1)].filter(v => new Set(arr2).has(v))
console.log(result2) // [3, 4]

// 3.并集
let result3 = [...new Set([...arr1, ...arr2])]
console.log(result3) // [1, 3, 2, 4, 7]

// 4.差集
let result4 = [...new Set(arr1)].filter(v => !(new Set(arr2).has(v)))
console.log(result4) // [1, 2]

Map

Map基本使用

// 声明 Map
let m = new Map()
m.set('name', 'name')
m.set('change', function () {
  console.log('change')
})
let key = {
  school: 'school'
}
m.set(key, [1 ,2, 3])

// 获取长度
console.log(m.size) // 3

// 删除属性
m.delete('name')

// 获取属性
console.log(m.get('change')) // f
console.log(m.get(key)) // [1, 2, 3]

for(let v of m){
  console.log(v) // 依次输出 ['change', ƒ] [{school: 'school'}, [1, 2, 3]]
}

class

基本使用

class Phone{
  // 构造方法 名字不能修改
  constructor(brand, price){
    this.brand = brand
    this.price = price
  }

  // 方法必须使用该语法 不能使用ES5的对象完整形式
  call() {
    console.log('hello')
  }
}

let iphone = new Phone('iphone', 5999)
iphone.call() // hello

静态成员

class Phone{
  // 静态属性
  static name = '手机'
  static change () {
    console.log('change')
  }
}

let iphone = new Phone()
console.log(iphone.name) // undefined
console.log(Phone.name) // 手机

继承

class Phone{
  // 构造方法 名字不能修改
  constructor(brand, price){
    this.brand = brand
    this.price = price
  }

  // 父类的成员属性
  call() {
    console.log('hello')
  }
}

class SmartPhone extends Phone {
  // 构造方法
  constructor(brand, price, color, size) {
    super(brand, price) // 相当于 Phone.call(this, brand, price)
    this.color = color
    this.size = size
  }

  photo() {
    console.log('photo')
  }
}

const xiaomi = new SmartPhone('小米', 1999, '黑色', '4.7inch')
xiaomi.call() // hello
xiaomi.photo() // photo

ES11 私有属性

// 私有属性必须声明
class Person {
  #age
  #weight
  constructor(name, age, weight) {
    this.name = name
    this.#age = age
    this.#weight = weight
  }

  intor() {
    console.log(this.name, this.#age, this.#weight)
  }
}

const girl = new Person('xiaohong', 18, '45kg')
girl.intor()

数值方法扩展

// 1.Number.EPSILON 是 JavaScript 表示的最小精度
// EPSILON 属性的值接近于 2.220446049250313e-16
function equal(a, b) {
  return Math.abs(a - b) < Number.EPSILON
}
console.log(0.1 + 0.2 === 0.3) // false
console.log(equal(0.1 + 0.2, 0.3)) // true

// 2.二进制和八进制
let b = 0b1010
let o = 0o777
let d = 100
let x = 0xff
console.log(b, o, d, x) // 10 511 100 255

// 3.Number.isFinite 检测一个数值是否为有限数
console.log(Number.isFinite(100)) // true
console.log(Number.isFinite(100 / 0)) // false
console.log(Number.isFinite(Infinity)) // false

// 4.Number.isNaN 检测一个数值是否为NaN
console.log(Number.isNaN(123)) // false
console.log(Number.isNaN(NaN)) // true

// 5.Number.parseInt Number.parseFloat 字符串转数字
console.log(Number.parseInt('123abc')) // 123
console.log(Number.parseFloat('1.23abc')) // 1.23

// 6.Number.isInteger 判断是否为整数
console.log(Number.isInteger(5)) // true
console.log(Number.isInteger(5.5)) // false

// 7.Math.trunc 将数字的小数部分抹掉
console.log(Math.trunc(3.5)) // 3

// 8.Math.sign 判断一个数到底是正数 负数 还是零
console.log(Math.sign(100)) // 1
console.log(Math.sign(0)) // 0
console.log(Math.sign(-100)) // -1

字符串方法扩展 ES10

trimStart()、trimEnd()

数组方法扩展 ES10

const arr = [1, 2, [3, 4, [5, 6]]]
console.log(arr.flat()) // [1, 2, 3, 4, [5, 6]]
console.log(arr.flat(2)) // [1, 2, 3, 4, 5, 6]

const arr2 = [1, 2, 3, 4]
const result = arr2.flatMap(v => [v * 10])
console.log(result) // [10, 20, 30, 40]

对象方法扩展

ES6 对象扩展

// Object.is 判断两个对象是否完全相等
console.log(Object.is(120, 120)) // true
console.log(Object.is(NaN, NaN)) // true
console.log(NaN === NaN) // false

ES8 对象扩展

const obj = {
  name: 'aaa',
  arr: [11, 22, 33]
}

console.log(Object.keys(obj)) // ['name', 'arr']
console.log(Object.values(obj)) // ['aaa', Array(3)]
console.log(Object.entries(obj)) // [['name', 'aaa'], ['arr', [11, 22, 33]]]

// 创建 Map
const m = new Map(Object.entries(obj))
console.log(m.get('name')) // aaa

// 对象属性的描述对象
console.log(Object.getOwnPropertyDescriptors(obj)) // {name: {…}, arr: {…}}
const o = Object.create(null, {
  name: {
    // 设置值
    value: 'bbb',
    // 属性特征
    writable: true,
    configurable: true,
    enumerable: true
  }
})

ES10 对象扩展

// Object.fromEntries 二维数转换为对象
const result = Object.fromEntries([
  ['name', 'aaa'],
  ['age', '18']
])
console.log(result) // {name: 'aaa', age: '18'}

// Map
const m = new Map()
m.set('name', 'bbb')
const result2 = Object.fromEntries(m)
console.log(result2) // {name: 'bbb'}

// 与 Object.entries 作用相反(将对象转换为二维数组)
const arr = Object.entries({
  name: 'ccc'
})
console.log(arr) // [['name', 'ccc']]

模块化

注意

  • html文件需要在服务器中打开,VScode中可以使用Live Server插件
  • <script type="module">标签必须加上type属性

暴露数据语法

m1.js

// 分别暴露
export let name = 'aaa'
export function fn () {
  console.log('fn')
}

m2.js

// 统一暴露
let name = 'aaa'
function fn () {
  console.log('fn')
}
export {name, fn}

m3.js

// 默认暴露
export default {
  name: 'aaa',
  fn() {
    console.log('fn')
  }
}

导入数据语法

通用的导入方式

import * as m1 from './m1.js'
import * as m2 from './m2.js'
import * as m3 from './m3.js'

解构赋值形式

import {name, fn} from './m1.js'
import {name as name2, fn as fn2} from './m2.js'
import {default as m3} from './m3.js'

简便形式 只针对默认暴露

import m3 from './m3.js'

ES11 import动态导入

setTimeout(() => {
  import('./m1.js').then(module => {
    module.fn() // fn
  })
}, 1000)

BigInt 大整形 ES11

// 大整形
let n = 123n
console.log(n, typeof n) // 123n 'bigint'

// 函数 可对整数转换成大整数类型
let n2 = 123 // 必须是整数
console.log(BigInt(n2)) // 123n

// 大数值运算
let max = Number.MAX_SAFE_INTEGER
console.log(max) // 9007199254740991
console.log(max + 1) // 9007199254740992
console.log(max + 2) // 9007199254740992

console.log(BigInt(max)) // 9007199254740991n
console.log(BigInt(max) + BigInt(1)) // 9007199254740992n
console.log(BigInt(max) + BigInt(2)) // 9007199254740993n
posted @ 2022-06-17 13:54  lwlcode  阅读(46)  评论(0编辑  收藏  举报