ES6-ES12知识点 笔记(一)

1. ES6

对象字面量增强写法

var name = 'coder'
var age = 18

// 当键名(key)和值名(value)一样时可以简写
var obj = {
    name: name,
    age: age,
    
    foo: function() {
        console.log(this)
    },
    bar: () => {
        console.log(this)
    }
}


var obj = {
    // 1. property shorthand(属性简写)
    name,
    age,
    
    // 2. method shorthadn(方法的简写)
    foo() {
         console.log(this)
    }

    // 3. computed property name(计算属性名)
    [name + 123]: 'hahahah'   // coder123: 'hahahah'
}

... 解构

数组的解构

var names = ['abc', 'cba', 'nba']

// var item1 = names[0]
// var item2 = names[1]
// var item3 = names[2]

// 对数组的解构: []

var [item1, item2, item3] = names

console.log(item1, item2, item3) // 'abc', 'cba', 'nba'

// 解构后面的元素
var [, , itemz] = names
console.log(itemz) // nba

// 解构出一个元素,后面的元素放到一个新数组中
var [itema, ...newNames] = names
console.log(itema) // abc
console.log(newNames) // ['cba', 'nba']

// 解构的默认值
var [itema, itemb, itemc, itemd = 'aaa']
console.log(itemd) // aaa

对象的解构

var obj = {
    name: 'coder',
    age: 18,
    height: 1.88
}

// 对象的解构: {} 根据key赋值,不是按顺序赋值的

var { name, height ,age } = obj
console.log(name, age, height) // coder, 18, 1.88

var { age } = obj
console.log(age) // 18

// 解构出来后,重命名
var { name: newName } = obj
console.log(newName)

// 解构出来后,重命名,当没有这个值时,给一个默认值
var {addresss: newAddress = '长沙市'} 
console.log(newAddress) // 长沙市

// 解构的在函数中的使用
function foo({ name, age }) {
    console.log(name,age) // coder, 18
}

foo(obj)

let const

// es6之前声明变量的方式
var foo = 'foo'

// es6声明变量的方式
let bar = 'bar'

const name = 'abc' // const constant(常量、衡量) 
// name = 'cba' // 报错

// 注意事项一:const本质上是传递的值不可以修改
// 但是如果传递的是一个引用类型(内存地址),可以通过引用找到对应的对象,去修改对象内部的属性,这个是可以的
const obj = {
    foo: 'foo'
}

// obj = {} // 报错

obj.foo = 'aaa'
console.log(obj.foo) // aaa


// 注意事项二: 通过let const 定义的变量名是不可以重复定义的
// var foo = 'abc'
// var foo = 'cba'

let foo = 'abc' 
let foo = 'cba' // SyntaxError: -Identifier: 'foo ' has already been declared

作用域提升:在声明变量的作用域中,如果这个变量可以在声明之前被访问,那么我们可以称之为作用域提升

let,const会在执行上下文创建阶段被创建出来,但是不可以被访问,所以他们没有作用域提升

// console.log(foo) undefined
// var foo = 'foo' 

// Reference(引用)Error; Cannot access 'foo ' before initialization(初始化)
// let/ const 他们是没有作用域提升
// foo被创建出来了,但是不能被访问
// 作用域提升: 能提前被访问
console.log(foo)
let foo = 'foo'


 let-const 暂时性死区

var foo = 'foo'

if(true) {
    console.log(foo) // 在这里是访问不到foo的,这种现象,称之为暂时性死区
    let foo = 'coder'
}

let-const 和window的关系

var foo = 'foo'
var message = 'Hello World'

/** (早期的ECMA标准)每一个执行上下文会被关联到一个变量环境(variable object,v0),在源代码
中的变量和函数声明会被作为属性添加到VO中。对于函数来说,参数也会被添加到VO中。**/
console.log(window.foo) // foo
console.log(window.message) // Hello World

window.message = '哈哈哈'
console.log(message) // 哈哈哈



/** (最新的ECMA标准)每一个执行上下文会关联到一个变量环境(VariableEnvironment)中,在执行代码
中变量和函数的声明会作为环境记录(Environment Record)添加到变量环境中。**/
// 对于函数来说,参数也会被作为环境记录添加到变量环境中。

`1. 变量被保存到VariableMap中`
`2. window对象是早期的GO对象,在最新的实现中其实是浏览器添加的全局对象`


let foo = 'foo'
console.log(window.foo) // undefined

块级作用域

// ES5中没有块级作用域
{
    var foo = 'foo'
}

console.log(foo) // foo

// 在ES5中只有两个东西可以形成作用域
/**
    1. 全局作用域
    2. 函数作用域
**/

function foo() {
    var bar = 'bar'
}

console.log(bar) // bar is not defined



/**
    ES6的块级作用域只对let/const/function/class声明的类型有效
**/

{
    let foo = 'why'
    function demo() {
        console.log('demo function')
    }
    class Person {}
}

console.log(foo) // foo is not defined

// 不同的浏览器有不同实现的(大部分浏览器为了兼容以前的代码,让function是没有块级作用域)
demo() // demo function

var p = new Person() // Person is not defined

if - switch - for 块级代码

// if语句的代码就是块级作用域
if(true) {
    var foo = 'foo'
    let bar = 'bar'
}

console.log(foo) // foo
console.log(bar) // bar is not defined



// switch语句的代码就是块级作用域
var color = 'red'

switch(color) {
    case 'red': 
        var foo = 'foo'
        let bar = 'bar'
}

console.log(foo) // foo
console.log(bar) // bar is not defined

// for语句的代码就是块级作用域
for (var i = 0; i < 10; i++) {

}
console.log(i) // 10

for (let i = 0; i < 10; i++) {

}
console.log(i) // i is not defined


`块级作用域的应用场景`
// const btns = document.getElementsByTagName('button)

for(var i = 0; i < btns.length; i++) {
    btns[i].onclick = function() {
        console.log('第'+ i + '个按钮点击了') // 在外面点击打印的永远是btns.length个
    } 
}
// es5时期的解决方案
for(var i = 0; i < btns.length; i++) {
    (function(n) {
          btns[i].onclick = function() {
            console.log('第'+ i + '个按钮点击了')
         } 
    })(i)
}

// ES6可以直接使用let产生块级作用域
for(let i = 0; i < btns.length; i++) {
    btns[i].onclick = function() {
        console.log('第'+ i + '个按钮点击了')
    } 
}

for...of ES6新增的遍历数组(对象)

const names = ['abc', 'cba', 'nba']
/**
可以使用break,continue,return
支持数组和类数组对象的遍历,循环读取键值
也支持字符串的遍历
**/
for(const item of names ) {
    console.log(item) 
    /** 
    abc
    cba
    nba
    **/
}

for...in ES6新增的遍历对象

const obj = {
    age: 18,
    name: 'coder'
    height: 1.88
}
/**
循环遍历对象自身和继承的可枚举属性(不含Symbol)
会循环原型链和手动添加的键,返回键名key
**/
for(let key in obj) {
    console.log(obj[key])
}

`` 字符串模板的基本使用

// ES6之前拼接字符串和其他标识符
const name = 'coder'
const age = 18
const height = 1.88

// my name iscoder, age is18, heigth is 1.88
console.log('my name is ' + name + ', age is ' + age + ', heigth is ' + height)


// ES6提供模板字符串 ``

const message = `my name is ${name}, age is ${age}, heigth is ${height}`
console.log(message) // my name is coder, age is 18, heigth is 1.88

标签模板字符串

function foo(m, n, z) {
    console.log(m, n, z)
}

foo('hello', 'World', '---------') // hello World ---------

// 另外一种调用函数的方式: 标签模板字符串
// foo``

const name = 'coder'
const age = 18
const height = 1.88

// 第一个参数依然是模板字符串中整个字符串,只是被切割成了多块,放到数组中
// 第二个参数是模板字符串中的第一个${},一次类推

foo`He${height}llo${name}Wo${age}rld` // ['He', 'llo', 'Wo', 'rld', raw: Array(4)] 1.88 'coder'

ES6中函数的默认参数

// ES5以及之前给参数默认值
/**
* 1. 写起来麻烦,并且代码的阅读性比较差
* 2. 这种写法有bug
**/
function foo(m, n) {
    m = m || 'bbb'
    n = n || 'aaa'
    console.log(m, n)
}
foo(0, '')

// ES6可以给函数参数提供默认值
function foo(m='aaa', n='bbb') {
    console.log(m,n)
}

// 对象参数的默认值以及解构
function printInfo({ name, age } = { name: 'coder', age: 18 }) {
    console.log(name, age)
}
printInfo({name: 'kobe', age: 18})


// 另外一种写法(给一个空对象为默认值,但是解构不出来,又给了name默认值和age默认值)
fucntion printInfo1({name = 'coder', age = 19} = {}) {
     console.log(name, age)
}
printInfo1()


// 有默认值的形参最好放到最后
function bar(x, y, z = 30) {
    console.log(x, y, z)
}
bar(10,20)

函数的剩余参数

剩余参数喝arguments的区别

1. 剩余参数只包含那些没有对应形参的实参,而arguments对象包含了传给函数的所有实参;

2. arguments对象不是一个真正的数组,而rest参数是一个真正的数组,可以进行数组的所有操作;

3. arguments是早期的ECMAScript中为了方便去获取所有的参数提供的一个数据结构,而rest参数是ES6中提供并且希望以此来替代arguments的;

function foo(m, n, ...args) {
    console.log(m, n) // 10, 20
    console.log(args) // [30, 40, 50]
}

foo(10, 20, 30, 40, 50)

箭头函数

const bar = () => {
    console.log(this, arguments)
    // 箭头函数不绑定this,this去上层作用域找
    // 箭头函数没有arguments    
}

console.log(bar.prototype) // undefined 箭头函数没有显式原型的

var f = new far() // TypeError: far is not a constructor

展开语法

展开运算符是浅拷贝

const names = ['abc', 'cba', 'nba']
const name = 'why'

// 1.函数调用时
function foo(x, y, z) {
    console.log(x, y, z)
}

// foo.apply(null, names) ES5的调用方式
foo(...names) // abc cba nba
foo(...name) // w h y


// 2. 构造数组时
const newNames = [...names, ...name]

console.log(newNames) // ['abc', 'cba', 'nba', 'w', 'h', 'y']


// 3. 构建对象字面量时ES9
const obj = { ...names, address: '广东省'}
console.log(obj) // {0: 'abc', 1: 'cba', 2: 'nba', address: '广东省'}

// 4. 展开运算符做的是浅拷贝
const info = {
    name: 'coder'
    friend: { name: 'kobe' }
}

const obj = {...info, name: 'jeka'}
obj.friend.name = 'james'

console.log(info.friend.name) // james

表示数值的方式

const num1 = 100 // 十进制
console.log(num1) // 100

// b -> binary
const num2 = 0b100 // 二进制
console.log(num2) // 4

// o -> octonary
const num3 = 0o100 // 八进制
console.log(num3) // 64

// x -> hexadecimal
const num4 = 0x100 // 十六进制
console.log(num4) // 256


// 大的数值的连接符(ES12)
const num = 1_000_000_000_000
console.log(num) // 1000000000000

Symbol

Symbol是ES6中新增的一个基础数据类型,翻译为符合

特性: 创建一个独一无二的key

// ES6之前,对象的属性名(key)只能使用字符串
const obj = {
    name: 'coder'
    friend: { name: 'kode' },
    age: 18
}

obj['newName'] = 'james'
console.log(obj.newName) // james


// ES6中Symbol的基本使用
const s1 = Symbol()
const s2 = Symbol()
console.log(s1 === s2) // false

// ES10中, Symbol还有一个描述(descripiton)
const s3 = Symbol('aaa')
console.log(s3.description) // aaa

// Symbol值作为key
const obj = {
    [s1]: 'bac',
    [s2]: 'cba'
}

obj[s3] = 'nba'

const s4 = Symbol()
Object.defineProperty(obj, s4, {
    enumerable: true,
    configurable: true,
    writable: true,
    value: 'mba'
})

console.log(obj[s1], obj[s2], obj[s3], obj[s4]) // bac cba nba mba
console.log(obj.s1) // undefined 不能通过.语法获取



// 使用Symbol作为key属性名,在遍历Object.keys等中是获取不到这些Symbol值的
// 需要 Object.getOwnPropertySymbols()获取所有Symbol的key
console.log(Object.keys(obj)) // []
console.log(Object.getOwnPropertyNames(obj)) // []

console.log(Object.getOwnPropertySymbols(obj)) 
// [Symbol(), Symbol(), Symbol(aaa), Symbol()]

const sKeys = Object.getOwnPropertySymbols(obj)
for(const sKey of skeys) {
    console.log(obj[sKeys])
}


// Symbol.for(key) 创建一样的Symbol key
const sa = Symbol.for('aaa')
const sb = Symbol.for('aaa')
console.log(sa === sb) // true

const key = Symbol.keyFor(sa) // 返回Symbol的key
console.log(key) // aaa
const sc = Symbol.for(key)
console.log(sa === sc) // true

set的基本使用

ES6之前,我们存储数据的结构主要有两种: 数组,对象

ES6中新增了另外两种数据结构:Set, Map, 以及它们的另外形式weakSet, WeakMap

Set 是一个新增的数据结构,可以用来保存数据,类似于数组,但是和数组的区别是元素不能重复

// 创建Set结构
const set = new Set()
set.add(10)
set.add(20)
set.add(40)
set.add(4440)

set.add(10) // set数据不可以重复

// 这里是两个对象
// set.add({})
// set.add({})

// const obj = {}
// 这里是添加同一个对象,只会存在一个
// set.add(obj)
// set.add(obj)
console.log(set) // Set(4) {10, 20, 40, 4440}


// 2. 对数组去重(去除重复的元素)
const arr = [33, 22, 11, 10, 11]
// const newArr = []
// for(const item of arr) {
//     if(newArr.indexOf(item) === -1) {
//         newArr.push(item)
//     }
// }
// console.log(newArr) // [33, 22, 11, 10]

const arrSet = new Set(arr)
// console.log(arrSet) // Set(4) {33, 22, 11, 10}

// const newArr = Array.from(arrSet)
// console.log(newArr) // [33, 22, 11, 10]

// const newArr = [...arrSet]
// console.log(newArr) // [33, 22, 11, 10]



// Set的属性和方法

`size属性`得到set里面数据的个数
console.log(arrSet.size)

`add`添加
arrSet.add(100)

`delete`删除
arrSet.delete(100)

`has`判断是否包含某个元素,返回true,false
arrSet.has(100) // false

`clear`清除Set,里面所有的元素都会被删掉
arrSet.clear()

`对Set进行遍历`
arrSet.forEach(item => {
    console.log(item)
})

for (const item of arrSet) {
    console.log(item)
}

WeakSet的使用

和Set类似的另外一个数据结构称为WeakSet, 也是内部元素不能重复的数据结构

WeakSet和Set的区别:

1. WeakSet中只能存放对象类型,不能存放基本数据类型

2. WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收

const weakSet = new WeakSet()

// 1. 只能存放对象类型
weakSet.add(10) // TypeError: Invalid value used in weak set

// 2. 对对象是一个弱引用
let obj = { name: 'coder' }


const set = new Set()
// 建立的是强引用
set.add(obj)

// 建立的是弱引用
weakSet.add(obj)


// WeakSet常见方法

`add 添加元素 返回WeakSet本身`
`delete 删除和这个值相等的元素,返回boolean类型`
`has 判断weakset中是否存在某个元素,返回boolean类型`




// 3. WeakSet的应用场景
const personSet = new WeakSet()
class Person {
    constructor() {
        personSet.add(this)
    }
    running() {
        if(!personSet.has){
            throw new Error('不能通过非构造方法创建出来的对象调用running方法')    
        }
        console.log('running', this)
    }
}
let p = new Person()
p.running()

p.running.call({name: 'coder'})

Map的基本使用

ES6新增的数据结构,用于存储映射关系

可以使用对象做为key,key也是唯一的

对对象的引用是强引用

// 1. JavaScript 中对象是不能使用对象来作为key的
const obj1 = { name: 'coder' }
const obj2 = { name: 'kebe' }

const info = {
    [obj1]: 'aaa',
    [obj2]: 'bbb'
}

console.log(info) // {[object Object]: 'bbb'}


// 2. Map就是允许我们对象类型作为key的
// 构造方法的使用
const map = new Map()
map.set(obj1, 'aaa')
map.set(obj2, 'bbb')
map.set(1, 'ccc')
console.log(map) // Map(3) {{…} => 'aaa', {…} => 'bbb', 1 => 'ccc'}

const map2 = new Map([[obj1, 'aaa'], [obj2, 'bbb'], [2. 'ccc']])
console.log(map2)

// 3. 常见的属性和方法
console.log(map2.size)

// set
map2.set('coder', 'eee')

// get
map2.get('coder')

// has 判断map里是否有某一个key,返回boolean
map2.has('coder')

// delete 删除某一个key,返回boolean
map2.delete('coder')

// clear 清除所有
map.clear('coder')


// 4. 遍历map
map2.forEach((item, key) => {
    console.log(item, key)
})

for(const item of map2) {
    console.log(item[0], item[1])
}

for(const [key, value] of map2) {
    console.log(key, value)
}

WeakMap的使用

WeakMap和Map的区别

1. WeakMap只能使用对象,不能接受其他类型作为key

2. WeakMap的key对对象的引用是弱引用,如果没有其他引用使用这个对象,GC会回收这个对象

const obj1 = {name: 'obj1'}

const map = new Map()

map.set(obj1, 'aaa')

obj1 = null 

'{name: 'obj1'} 这个对象是不会销毁的, 因为map使用了这个对象,是强引用'



const weakMap = new WeakMap()

weakMap.set(obj1, 1)

obj1 = null 

// {name: 'obj1'} 会被GC回收

// 常见的方法

// get
console.log(weakMap.get(obj1))

// set
console.set(weakMap.get(obj1, '123'))

// has
console.has(weakMap.get(obj1))

// delete
console.has(weakMap.delete(obj1))


// 应用场景(vue3响应式原理中使用了WeakMap)
 const obj = {
    name: 'coder',
    age: 18
}

function objNameFn1() {
    console.log('obj1NameFn1被执行')
}

function objAgeFn1() {
    console.log('obj1AgeFn1被执行')
}

// 创建WeakMap
const seakMap = new WeakMap()

// 对obj1收集的数据结构
const obj1Map = new Map()
obj1Map.set('name', [objNameFn1])
obj1Map.set('age', [objAgeFn1])
weakMap.set(obj1,obj1Map )

// 如果obj.name 发生了改变
// proxy/ Object.defineProperty

ES7

Array Includes

在ES7之前,判断一个数组中是否包含某个元素,需要通过indexOf获取结果,并且判断是否为-1

const names = ['abc', 'cba', 'nba', NaN]

if(names.indexOf('cba') !== -1) {
    console.log('包含abc元素')
}


// ES7 
// 第一个参数,传入要验证包含的元素, 第二个是索引,从那个位置开始验证, 返回boolean
if(names.includes('cba', 2)) {
    console.log('包含abc元素')
}

// 区别
console.log(names.indexOf(NaN)) // -1
console.log(names.includes(NaN)) // true

指数(乘方)运算符

// 获取3的3次方

const result1 = Math.pow(3, 3)

// ES7
const result2 = 3 ** 3

console.log(result1, result2 ) // 27 27

ES8

Object values

ES5以前可以通过 Object.keys 获取一个对象所有的key
ES8中提供了, Object.values 来获取所有的value值

const obj = {
    name: 'coder',
    age: 19,
    height: 1.88
}

console.log(Object.keys(obj)) // ['name', 'age', 'height']
console.log(Object.values(obj)) // ['coder', 19, 1.88]

console.log(Object.values(['abc', 'cba', 'nba'])) // ['abc', 'cba', 'nba']
console.log(Object.values('abc')) // ['a', 'b', 'c']

Object entries

通过Object.entries 可以获取到一个数组,数组中会存放可枚举属性的键值对数组

const obj = {
    name: 'coder',
    age: 19
}


console.log(Object.entries(obj)) // [Array(2), Array(2)]

const objEntries = Object.entries(obj)

objEntries.forEach(item => {
    console.log(item[0], item[1])
})


console.log(Object.entries(['abc', 'cba', 'nba'])) 
// [['0', 'abc'],['1', 'cba'],['2', 'nba']]

String Padding

某些字符串我们需要对其进行前后的填充,来实现某种格式化效果,ES8中增加了padStart和 padEnd方法,分别是对字符串的首尾进行填充的。

const message = 'Hello World'


// 第一个参数是填充后的长度, 第二个参数是填充的内容
const newMessage = message.padStart(15, '*').padEnd(20, '_')

// 案例

const cardNumber = '45642348678612354231'

const lastFourCard = cardNumber.slice(-4)

const finalCard = lastFourCard.padStart(cardNumber.length, '*')

console.log(finalCard) // ****************4231

Tariling Commas

function foo(m, n,) {
    // ES8 可以在参数后面可以多加一个逗号,不会报错
}

foo(20, 30,)

Object Descriptors

获取一个对象的所有属性描述符

async await

async用于声明function异步, await 用于等待一个异步方法执行完成

async异步函数的写法

// 第一种普通函数
async function foo() {

}

// 第二种箭头函数
const foo = async() => {

}

// 第三章类中方法的异步

class bar {
  async foo() {
    
  }
}

 异步函数的执行流程

async function foo() {
  console.log(1);
  console.log(2);
  console.log(3);
}

console.log('script start');
foo()
console.log('script end');

/**
 * 当里面没有其他代码时。跟平常函数执行是一样的
 * script start
 * 1
 * 2
 * 3
 * script end
 * **/

 和普通函数的区别一 (返回值)

async function foo() {
  console.log('foo function start');

  console.log('中间代码');

  console.log('foo function end');
  // 第一种返回一个值
  // return 'abc'

  // 第二种返回一个thenable
  // return {
  //   then: function(resolve) {
  //     resolve('hhh')
  //   }
  // }

  // 第三种返回一个promise
  return new Promise((resolve,reject) => {
    setTimeout(() => {
      resolve('hahahah')
    },1000)
  })
}


// 异步函数的返回值一定是一个Promise
const promise = foo()

promise.then(res => {
  // then接受的参数是异步函数return的值
  console.log('promise then function exec', res);
})

 和普通函数的区别二(异常)

async function foo() {
  console.log('foo function start');

  console.log('中间代码');

  // 异步函数中的异常,会被作为异步函数返回的promise的reject值的
  throw new Error('error message')

  console.log('foo function end');
}


// 异步函数的返回值一定是一个Promise
const promise = foo()

promise.catch(err => {
  console.log('err: ', err);
})

await关键字

1. await是后面会跟上一个表达式,这个表达式会返回一个Promise

2. await会等到Promise的状态变成fulfilled状态,之后继续执行异步函数

如果await后面是一个普通的值,那么会直接返回这个值

如果await后面是一个thenable的对象,那么会根据对象的then方法调用来决定后续的值

function requestData() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(2222)
    },2000)
  })
}

async function foo() {
  const res = await requestData()
  // 这里的代码就想当于是then方法里的代码
  console.log('后面的代码1',res);

  const res1 = await requestData()
  console.log('后面的代码2',res1);
}

// 2.跟上其他的值
async function foo() {
  const res1 = await 123
  console.log(res1);

  const res2 = await {
    then: function(resolve) {
      resolve('abc')
    }
  }
  console.log(res2);

  const res3 = await new Promise(resolve => {
    resolve('coder')
  })
  console.log(res3);
}

// foo()


// 3. reject值
function requestData1() {
  return new Promise((resolve,reject) => {
    setTimeout(() => {
      reject(2222)
    },2000)
  })
}
async function foo1(){
  const res = await requestData1()
  console.log('res:',res);
}
foo1()
.catch(err=> {
  console.log('err:',err);
})


ES9

async iterators: 迭代器补充

Object spread operators

Object Spread 运算符的基本思想是使用现有对象的自身属性来创建新的普通对象。 所以{...obj} 创建一个和 obj 具有相同属性的对象。 对于普通的旧 JavaScript 对象,你实际上是在创建一个obj副本。


const obj = { foo: 'bar' };
const clone = { ...obj }; // `{ foo: 'bar' }`
obj.foo = 'baz';
clone.foo; // 'bar'

Promise finally: Promise补充

ES10

flat flatMap

flat()方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

flatMap()方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。

1.flatMap是先进行map操作,再做flat的操作;

2.flatMap中的flat相当于深度为1;

// flat的使用
const nums = [10, 20, [3, 4], [[40, 50], [18, 45]], 78, [55, 88]]

// 第一个参数,递归的深度,默认是为一
const newNums = nums.flat()
console.log(newNums) // [10, 20, 3, 4, [40, 50], [18, 45], 78, 55, 88]

const newNum2 = nums.flat(2)

console.log(newNum2) // [10, 20, 3, 4, 40, 50, 18, 45, 78, 55, 88]


// flatMap的使用 第一个参数是传进一个回调函数,第二个参数是传入一个this

const nums = [10 ,20, 30]
const newNum3 = nums.flatMap(item => {
    return item * 2
}, {})

const newNum4 = nums.map(item => {
    return item * 2
})


// 3. flatMap的应用场景
const message = ['Hello World', '你好啊 李焕英', 'my name is coder']
const words = message.flatMap(item => {
    return item.split(' ')
})
console.log(words) // ['Hello', 'World', '你好啊', '李焕英', 'my', 'name', 'is', 'coder']

const words2 = message.map(item => {
    return item.split(' ')
})
console.log(words2) 
// [['Hello', 'World'], ['你好啊', '李焕英'], ['my', 'name', 'is', 'coder']]

Object fromEntries

const obj = {
    name: 'coder',
    age: 18,
    height: 1.88
}

const entries = Object.entries(obj)
console.log(entries) // [['name', 'coder'], ['age', 18], ['height', 1.88]]

const newObj = {}
for(const entry of entries) {
    newObj[entry[0]] = entry[1]
}

// ES10增长Object.fromEntries
const newObj = Object.fromEntries(entries)
console.log(newObj) // {name: 'coder', age: 18, height: 1.88}


// Object.fromEntries的应用场景
const queryString = 'name=coder&age=18&height=1.88'
const queryParams = new URLSearchParams(queryString)

const paramObj = Object.fromEntries(queryParams)
console.log(paramObj) // {name: 'coder', age: '18', height: '1.88'}

trimStart trimEnd(字符串去除前,后空格)

const message = '   Hello World     '

console.log(message.trim()) // 'Hello World'

// 去除头部空格
console.log(message.trimStart()) // 'Hello World     '

// 去除尾部空格
console.log(message.trimEnd()) // '   Hello World'

Symbol description

Symbol.prototype.description 获取symbol标识

let s = Symbol('标识')
s.description // 标识

Optional catch binding

ES11

BigInt(大数字)

// ES11之前 max_safe_integer

const maxInt = Number.MAX_SAFE_INTEGER
console.log(maxInt) // 9007199254740991
console.log(maxInt + 1) // 9007199254740992
console.log(maxInt + 2) // 9007199254740992


// ES11 之后 BigInt  数字在后面加上一个n代表大数字

const bigInt = 900719925474099200n
console.log(bigInt + 10n)

const num = 100

console.log(bigInt + BigInt(num))

?? (Nullish Coalescing Operator 空值合并运算)

// SE11: 空值合并运算 ??

let foo 
console.log(foo) // undefined


cosnt fo = 0
// 逻辑或 0 '' 是为假
// const bar = fo || 'default value'

// 只有undefined 和 null 为假
const bar = fo ?? 'default value'



?.(OptionalChaining 可选链)

const info = {
    name: 'coder',
    friend: {
        name: 'lilei',
        girlFriend: {
            name: 'hmm'
        }
    }
}

console.log(info.friend.girlFriend.name) // hmm

info.friend = null

// Cannot read properties of null (reading 'girlFriend')
console.log(info.friend.girlFriend.name) 


// ES11之前的做法
if(info && info.friend && info.friend.girlFriend) {
    console.log(info.friend.girlFriend.name) 
}
// ES11 可选链 当friend没有,girlFriend没有,后面的取值就不会执行了
console.log(info.friend?.girlFriend?.name)

Global Object(获取全局对象)

// 获取某一个环境下的全局 对象(Global Object)

// 浏览器下
console.log(window)
console.log(this)


// 在node下
console.log(global)

// ES11 globalThis

console.log(globalThis) // 在不同环境下,获取的全局对象都是不一样的
 

for...in 标准化

const obj = {
    name: 'coder',
    age: 18
}

for(const item in obj) {
    // ES11之前,不同浏览器,可能会获取到值
    console.log(item) // ES11后标准化,获取的item就是对象的key
}

Dynamic import

promise.allSettled

import meta

ES12

FinalizationRegistry(引用不足)

当一个对象被强引用变量引用时,它处于可达状态,是不可能被垃圾回收器回收的,即使该对象永远不会被用到也不会被回收。

// ES12: FinalizationRegistry 类

// 回调函数,当注册的对象,没有被引用了,销毁的时候,就会执行这个回调函数
const finalRegistry = new FinalizationRegistry((item) => {
   console.log('注册一个finalRegistry的对象,某一个被销毁')
})
let obj = {name: 'coder'}
const info = {age: 18}

finalRegistry.register(obj)
finalRegistry.register(info, 'value')

obj = null

WeakRef

// ES12: FinalizationRegistry 类

// 回调函数,当注册的对象,没有被引用了,销毁的时候,就会执行这个回调函数
const finalRegistry = new FinalizationRegistry((item) => {
   console.log('注册一个finalRegistry的对象,某一个被销毁',item)
})

const info = {age: 18}
let info = new WeakSet() // 弱引用
info.add(obj)

// ES12 WeakRef类
/** WeakRef.prototype.deref : 如果源对象没有销毁,那么可以获取原对象,
如果销毁了获取的就是undefined **/
let info = new WeakRef(obj) // 弱引用
console.log(info.deref().name)

finalRegistry.register(info, 'value')

obj = null

逻辑赋值运算

||= (逻辑或赋值运算),&&=(逻辑与赋值运算) , ??= (逻辑空赋值运算)

// ||= 逻辑或赋值运算
let message = undefined

// message = message || 'default value'

message ||= 'default value'

// 2. &&= 逻辑与赋值运算

let info = {
    name: 'coder'
}

// 判断info,有值的情况,取出info.name

info = info && info.name

info &&= info.name

// ??= 逻辑空赋值运算

let message = null

message = message ?? 'hello world'

message ??= 'Hello'

数字分隔符(_)

// 大数字文字很难使人眼快速解析
1000000000000   1019436871.42

1_000_000_000_000    1_019_436_871.42

String.replaceAll(字符串替换)

const str = 'aaabbbcccdddabcd'

str.replaceAll('b', 't')

console.log(str) // aaatttcccdddatcd

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

派大星965

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值