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 的介绍与创建
// 创建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
完结~