ES6-11总结

415 阅读6分钟

先来几个案例:

1. 读取一个被连接对象的深层次的属性的值

const user = {
    address: {
        street: 'xx街道',
        getNum() {
            return '100号'
        }
    }
}

const street = user && user.address && user.address.street
const num = user && user.address && user.address.getNum && user.address.getNum()

ES6+ 语法:

const street = user?.address?.street
const num = user?.address?.getNum?.()

2.消除魔术字符串(新增的数据类型)

const getArea = (shape) => {
    let area = 0;
    switch (shape) {
        case 'triangle':
            area = 1
            break
        case 'circle':
            area = 2
            break
    }
    return area
}
getArea('triangle')

ES6+ 语法:

const shapeType = {
    triangle: Symbol(),
    circle: Symbol()
}

function getArea(shape) {
    let area = 0;
    switch (shape) {
        case shapeType.triangle:
            area = 1
            break
        case shapeType.circle:
            area = 2
            break
    }
    return area
}

3. 将类数组转化为数组

const arrayLike = document.querySelectorAll('.item')

ES5 语法:

Array.prototype.slice.call(arrayLike)

ES6+ 语法:

Array.from(arrayLike)
Array.from('1234567')
Array.from(new Set([1,2,3,1]))

4. 优雅的异步操作与结构赋值

function getData (url) {
    ajax(url, function(res) {
        var data = res.data
        this.list = data
    })
}

ES6+ 语法:

async function getData (url) {
    const {data} = await axios.get(url)
    this.list = data
}

ES6(2015)

新的声明方式: let  const

  • 不存在变量提升

  • 不属于顶层对象window

  • 不允许重复声明

  • 块级作用域

    if(true) var a=5 if(true) let a= 5 // error 加大括号即可

    for(var i= 0; i<3; i++) { setTimeout(function() { console.log(i) }) }

    // 3个3

    for(var i= 0; i<3; i++) { (function(j){ setTimeout(function() { console.log(j) }) })(i) }

    // 0 1 20
    for(let i= 0; i<3; i++) { setTimeout(function() { console.log(i) }) }

    // 0 1 2

结构赋值

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

  • 数组结构

  • 对象结构

  • 字符串结构

    let json = '{"a":"hello", "b":"world"}' let {a, b} = JSON.parse(json) // hello world

ES5中数组遍历方式

  • for循环

  • forEach(): 没有返回值, 只是针对每个元素调用func

  • map(): 返回新的array, 每个元素为调用func的结果

  • filter(): 返回符合func条件的元素数组

  • some(): 返回boolean, 判断是否有元素是否符合func 条件

  • every():  返回boolean, 判断每个元素是否符合func条件

  • reduce(): 接受收一个函数作为累加器

  • for in 下标 for of 内容

    let arr = [1, 2, 3, 3] let sum = arr.reduce(function(prev, cur, index, array){ return prev + cur }, 0) console.log(sum) //6

    let max = arr.reduce(function(prev, cur) { return Math.max(prev, cur) }) console.log(max) // 3

    let res = arr.reduce(function(prev, cur) { prev.indexOf(cur) == -1 && prev.push(cur) return prev }, []) console.log(res) // [1,2,3]

ES6 中的数组遍历

  • find: 返回第一个通过测试的元素
  • findIndex: 返回第一个通过的元素的下标
  • for of

values()

  • keys()

  • entries()

    let res = arr.find(function(value) {
    return value = 8})
    
    for(let i of arr.keys()) 返回index
    for(let i of arr.values()) 返回value
    for(let [index, item] of arr.entries()) 
    

数组的扩展

  • 类数组/伪数组

**Array.from
**

  •   ES5: 
           let arr = Array.prototype.slice.call(div3)
      ES6:
      let arrayLike = {
      '0': 'es6',
      '1': 'es7',
      '2': 'es8',
      length: 3
      }
      
      let arr = array.from(arrayLike)  
    
    

Array.of

let arr = new Array(1,2) // 数组长度为2

let arr = new Array(3) // 一个值时代表定义数组的长度

let arr = Array.of(3)  

let arr = Array.of(1, true, 'imooc', [1,2], {name: 'oyyf'})  // 场景: 组装不同类型的数据为一个数组

**copeWithin () ** // 三个参数, 1代表从那个位置开始替换数据 必选   

                                               2代表开始哪个位置读取参数    可选

                                               3从哪个位置停止读取参数         可选, 默认为末尾

let arr = [1, 2, 3, 4, 5]

arr.copyWithin(1, 3)

fill() // 三个参数, 1是代表填充的参数   2代表 从哪个位置填充   3从哪个位置截止填充

let arr = new Array(3).fill(7)  // [7, 7, 7]

let arr = [1,2,3,4,5].fill('oyyf', 1, 3) //  [1, "oyyf", "oyyf", 4, 5]

includes()

let arr = [1,2,3,NaN]

cosnole.log(arr.indexOf(NaN))  // -1, 包含返回下标, 不包含返回-1

cosnole.log(arr.includes(NaN)) // true

函数的参数

  1.  参数默认值, 参数的默认值放在最后面

  2. 与解构赋值结合({x='', y=''} = {})

  3. length 的属性  返回没有指定默认值的参数个数

  4. 作用域 

    let x = 1 function foo(y=x) { let x= 2 console.log(y) } foo() // 1

5. 函数的name 属性

console.log((new Function).name)   // anonymous


function foo(x, y) {
    console.log(this, x, y)    // {name: 'oyyf'}, 1, 3

}
foo.bind({name: 'oyyf'}, 1, 3)()

console.log(foo.bind({}).name)  // bound foo

扩展运算符与rest参数

扩展运算符: 把数组或者类数组展开用逗号隔开的值

rest参数: 把逗号隔开的值组合成一个数组

箭头函数

this指向定义时所在的对象, 而不是调用时所在的对象

不可以当作构造函数

不可以使用arguments对象

对象的扩展

属性简洁写法

let name = 'oyyf'
let age = 18
let s = 'company'
let obj = {
    name,
    age,
    [s]: 'imooc',  // 动态的用数组包裹
    study(){
        ccosnole.log(this.name + '正在xxx')
    }
}

Object.is()  判断左右是否严格相等

Object.is(NaN, NaN)  // true 对象的比较比较的是内存地址

let obj1 = {
    name: '111'
}

let obj2 = {
    name: '111'
}
Object.is(obj1, obj2)  // false

in

let arr = [1, 2, 3]
console.log(3 in arr)  // false 数组时判断是下标

深拷贝和浅拷贝

. 如何把一个对象复制给另一个对象
. Object.assign() // 不安全: 

let target = {
    a: {        b: {
           c: 1
        },
        e: 2,
        f: 2,
        g: 6
    }}
let source = {
    a: {
        b: {
           c: 1
        },
        e: 2,
        f: 2
    }, 
}

Object.assign(target, source) // g 消失了

// 深拷贝 互不干扰
let a = 5
let b = a
a = 6 
cosnole.log(a, b) // 6, 5


// 浅拷贝 相互改变
let obj1 = {
    name: "oyyf",
    age: 25
}
let obj2 = obj1
obj1.age = 18
console.log(obj1) // 18
cosnole.log(obj2) // 18


let obj1 = {
    name: 'oyyf',
    age: 25
}

// "{"a": 'hello', "b": "world"}"
// JSON.stringify() 对象转为json 格式字符串
// JSON.parse() json格式字符串转为对象
. 实现一个深拷贝
let str = JSON.stringify(obj1)
let obj2 = JSON.parse(str)
obj1.age = 18
console.log(obj2) // 25

let checkType  = data => {
    // typeof 基本数据类型
   return Object.peototype.toString.call(data).slice(8, -1)
}

let deepClone = target => {
    let targetType = checkType(traget)
    let result 
    if (targetType === 'Object') {
        result = {}
    } else if(targetType === 'Array') {
        result = []
    } else {
        return target
    }

    for(let i in target) {
        let value = target[i]
        let valueType = checkType(value)
        if (valueType === 'Object' || valueType === 'Array') {
            result[i] = deepClone(target[value])
        } else {
            result[i] = value
        }
    }
 return result 
}

let arr1 = [1, 2, {age: 18}]
let arr2 = deepClone(arr1)
arr2[2].age = 34

面向过程和面向对象(JavaScript是一种基于对象(object-based)的语言)

把大象装进冰箱需要几步: 

面向过程: 

1, 打开门

2, 装进去

3, 关门

面向对象: (JAVA  Everything is Object)

1. 大象

2. 冰箱

3.隐藏对象: 一双手/一个人来装大象

类与对象

人     欧阳月飞

类(class)是对象(object)的模版, 定义了同一组对象共有的属性和方法

Es5中的类与继承

fucntion People(name, age) {

this.name = name

this.age = age

}

let p1 = new People('111', '18')

ES7

数组的扩展: incudes

const arr = ['es6', 'es7', 'es8']
cosnole.log(arr.inculdes('es7')) // true
// includes -> boolean 

两个参数(要搜所的值, 索引)
console.log(arr.includes('es7', 1))
console.log(arr.includes('es7', -1)) // false
与indexOf区别(索引, 下表), includes更严格
arr.indexOf('es7') //  1
arr.indexOf('es7') > -1  // true

const arr = ['es6', NaN, 'es7', 2]
arr.includes(NaN) // true
arr.indexOf(NaN) // -1
arr.includes('2') // false

数值扩展

.幂运算符: **

.等同于 Math.pow(底数, 指数)

2 ** 10 // ** 之间不能有空格,否则语法报错

ES8(2017)

async(异步)/await (等待)

function timeout() {
    return new Promise(resolve => {
        setTimeout(() => {
            cosnole.log(1)
            resolve(1)
        }, 1000)
    })
}

async function foo() {
    const res = await timeout()
    console.log(res)
    console.log(2)
}

foo()

对象扩展

.Object.values()

.Object.entries()

const obj  = {
    name: 'oyyf',
    web: 'www.baidu.com',
    course: 'es'    
}

const res = Object.keys(obj).map(key => obj[key])
// 等同于
Object.values(obj)

Object.entrise(obj) // 二维数组 [key, value]

对象属性描述符号

.Object.getOwwnPropertyDescriptors()

const obj = {
    name: 'oyyf',
    course: 'es
}

console.log(Object.getOwwnPropertyDescriptors(obj))
{
 name: {
    value: 'oyyf', // 值
    writable: true,  // 是否可更改
    enumerable: true, // 是否可以for in 循环
    configurable: true // 能否用delete 运算符删除
  }
}

const obj = {}
Reflect.defineProperty(obj, 'name', {
    value: 'oyyf',
    writable: false,
    configurable: true,
    enumerable:  true
})

字符串扩展

.String.prototype.padStart()

.String.prototype.padEnd()

const str = 'oyyf'
str.padStart(8, 'x') // 目标长度, 以什么填充  xxxxoyyf

// 使用场景: yyyy--mm-dd 2020-04-01   xxxxxxx6789 身份证号  时间戳
const now = new Date()
const year = now.getFullYear()
cosnt month = (now.getMonth() + 1).toString().padStart(2, '0')
const day = (now.getDate()).toString().padStart(2, '0')

const tel = '17682342970'
tel.splice(-4).padStart(tel.length, 'x')

尾逗号(允许函数参数列表使用尾逗号)

fucntion foo (a, b, c,) {
    consoel.log(a, b, c)
}

foo(4, 5, 6, )

作用: 减少修改代码行数

ES9(2018)

异步迭代

.for-await-of(多个异步操作)

Symbol.asycIterator(异步迭代器)

const arr = [1, 2, 3, 4]
arr[Symbol.iterator] = fucntion() {
    let nextIndex = 0
    return {
        next() {
            return nextIndex < arr.length ? 
                    {
                        value: arr[nextIndex++],
                        done: false
                    }:{
                    value: undefined,
                    done: true
                    }
            }
        }
    }

    for(let item of arr) {
        
    }
}


fucntion getPromise(time) {
    return new Promise(res, rej) => {
        setTimeout(() => {
            res({
                value: time,
                done: fasle
            })
        }, time)
    }
}

const arr = [getPromise(1000), getPromise(2000), getPromise(3000)]
arr[Symbol.asyncIterator] = fucntion() {
    let nextIndex = 0
    return {
        next() {
            return nextIndex < arr.length ? arr[nextIndex++] : Promise.resolve({
               value: undefined,
               done: true            })
        }
    }
}
async fucntion test(){
        for await(let item of arr) {     consoel.log(item)    }
}

正则表达式扩展

.dotAll

.具名组匹配

.后行断言

// dot

const reg= /./   /./s
reg.test('5') true  true
reg.test('x') true  true
reg.test('\n') false true
reg.test('\r') false true
reg.test('\u{2028}') false true

// g 全局  i忽略  m 跨行匹配 es5
// y 粘性  u 匹配unicode  s 匹配任意单个字符 es6 

// 具名组匹配

const date = /(\d{4}) - (\d{2}) -(\d{2})/.exec('2020-01-01')
date[1/2/3] 年月日 // low groups是undeined

const reg = const date = /(?<year>\d{4}) - (?<month>\d{2}) -(?<day>\d{2})/
const groups = reg.exec('2020-12-06').groups
const {year, month, day} = groups

// 后行断言  先行断言
const str = 'ecmascript'
str.match(/ecma(?=script)/)  // 先行断言, 匹配后边必须是script的字符串

str.match(/(?<=ecma)script/)  // 后行断言, 必须后边是script, 前边是ecma
str.match(/(?<!ecma)script/) 

对象扩展 rest

const arr1 = [1, 2, 3 ]
const arr2 = [4, 5, 6 ]
const arr3 = [...arr1, ...arr2]

const obj1 = {
    name: 'oyyf',
    age: 25
 }

const obj2 = {
    school: 'xxxx'
}

const obj3 = {...obj1} // 浅拷贝
obj1.age = 18


const obj4 = {...obj1, ...obj2}
const {name, age, ...resr} = obj4 // 必须放在后边

Promise扩展  finally()

new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('fail')
    }, 1000)
}).then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
}).finally(() => {
    console.log('finally')
})

使用场景: 不管请求是否成功, loading 消失

字符串扩展 (放宽了限制)

const foo = (a, b, c, d) => {
    console.log(a,b, c, d)
  // ['这是', ', 他的年龄是']
  // oyyf
  // 25
  // undefined

}

const name = 'oyyf'
const age = 25
foo`这是${name}, 他的年龄是${age}`



const foo = arg => {
    console.log(arg)
}

foo`\u{61} and \unicode` // es9 之前会报unicode无效的转译序列

let str = `\u{61} and \unicode` // 报错

ES10(2019)

对象扩展

.Object.fromEntries()

const obj = {
    name: 'oyyf',
    course: 'es'
}

const entries = Object.entries(obj)
// [["name": 'oyyf'], ['course': 'es']]

Object.fromEntries(entries)
// [name: 'oyyf', course: 'es']

使用场景: map-> 对象   

字符串的扩展

String.prototype.trimStart() ; 消除字符串前面的空格

String.prototype.trimLeft()

String.prototype.trimEnd(): 消除字符串后面的空格

String.prototype.trimRight()

const str = '  oyyf   '
str.replace(/^\s+/g, '')
str.replace(/\s+$/g, '')

str.trim()

数组的扩展

Array.prototype.flat()

Array.prototype.flatMap()

const arr = [1, 2, [3, 4, [5, 6, [7, 8, 9]]]]
console.log(arr.flat()) // 默认参数是1, 只会拍平一级
console.log(arr.flat(Infinity)) // 无限的

const arr = [1, 2, 3, 4, 5]
const res = arr.map(x => x + 1)
const res = arr.map(x=>[x+1]).flat()
const res = arr.flatMap(x => [x+1])

修改Function.prototyype.toString() 返回源代码中的实际文本片段

function foo() {
    console.log('oyyf')
}

foo.toString() // 方法文本化输出 

可选的Catch Binding  省略catch 绑定的参数和括号

const validJSON = json => {
    try{
        JSON.parse(json)
        return true
    }.catch {
       return false
    }
}

const json  ='{name": 'oyyf'}'
validJSON(json)

JSON扩展

.JSON.superset

.JSON.stringify() 增强能力

eval('var str="oyyf";\u2029 function foo(){retuurn str}') // 段分隔符
console.log(foo()) // oyyf

// 0xD800~0xDfff
JSON.stringify('\uD83D\uDE0E') // emoji

Symbol 扩展

const s= Symbol('oyyf')  // description 可读不可写

s.description // oyyf 

const s2 = Symbol()
s2.description // undefined

ES11(2020)

字符串扩展 matchAll()

const str = `
    <html>
        <body>
            <div>111</div>
            <p>222</p>
            <div>11122</div>
            <span>222</span>
        </body>
    </html>
`
// exec g

function selectDiv(regExp, str) {
    let matches = []
    while(true) {
        const match = regExp.exec(str)
        if (match == null) {
            break
        }
        matches.push(match[1])
    }
    return matches
}

const regExp =  /<div>.(*)<\/div>/g
const res = selectDiv(resExp, str)

// match
str.match(regExp)

// replace
function selectedDiv(regExp, str) {
    let matches = []
    str.replace(regExp, (all, first) => {
        matches.push(first)
    })
    return matches
}

selectDiv(regExp, str)

// matchAll
function selectedDiv(regExp, str) {    let matches = []
    for (let match of str.matchAll(regExp)) {
          matches.push(match[1])
    }
    return matches
}

Dynamic Import (动态导入/按需导入)

const oBtn = document.querySelector('#btn')
oBtn.addEventListener('click', () => {
    import('./ajax').then(mod => {
        mod.default('static/a.json', res => {
            console.log(res)
        })
    })
})

新的原始数据类型 BigInt

const max= 2 ** 53         9007199254740992
Number.MAX_SAFE_INTEGER    9007199254740991
max === max + 1 // true
const bigInt = 9007199254740993n
typeof bigInt // bigInt
1n == 1 // true
1n ===  1 // false

const bigInt2  = BigInt(9007199254740993n)
const num = bigInt + bigInt2
num.toString() // 以字符串才可以存储这么大的值

Promise 扩展

.Promise.allSettled()   // 稳定的固定的

.allSettled vs all

Promise.all([
    Promise.resolve({code: 200, data: [1, 2, 3]}),
    Promise.reject({code: 500, data: []},
    Promise.resolve({code: 200, data: [7, 8, 9]})
]).then(res => {
    
}).catch(err => {
    //
})

Promise.allSettled([
    Promise.resolve({code: 200, data: [1, 2, 3]}),
    Promise.reject({code: 500, data: []},
    Promise.resolve({code: 200, data: [7, 8, 9]})
]).then(res => {
    //
    res.filter(item =>  item.status === 'fulfilled')
}).catch(err => {
    
})

globalThis: 提供了一个标准的 方式  去获取不同环境下的全局对象

// node: global
//web: window self

const getGlobal = () => {
   if (typeof self !== 'undefined') {
      return self
   }
   if (typeof window !== 'undefined') {
      return window
   } 
   if (typeof global !== 'undefined') {
      return global
   }
    
   throw new Error('无法获取全局对象')}

globalThis     getGlobal()  // window

Optional chaining  可选链

const user = {
    address: {
        street: 'xx街道',
        getNum() {
            return '80号'
        }
    }
}

const street = user?.address?.street

空值合并运算符

const b = 0  null undefined   ''  false 
const a = b || 5
console.log(a) // 5

const a = b ?? 6
console.log(a)  // null / undefined 才取后边的