ES6-ES12简单知识点总结

1.ES6相关知识点

1.1.对象字面量的增强

ES6中对对象字面量的写法进行了增强,主要包含以下三个方面的增强:

  • 属性的简写:当给对象设置属性时,如果希望变量名和属性名一样就可以直接写该变量名;
  • 方法的简写:对象中的方法可直接写成foo() {}的形式;
  • 计算属性名:对象的属性名可以动态传入,将变量使用[]包裹即可;
const obj = {
// 1.属性简写
name,
age,
// 2.方法简写
foo() {
console.log('foo')
},
// 3.计算属性名
[key]: 'value'
}

1.2.解构

为了方便从数组或对象中获取数据,ES6给我们提供了解构的方案,可分为数组的解构和对象的解构。

  • 数组的解构:注意数组的解构是按元素顺序来的。

    const names = ['curry', 'kobe', 'klay', 'james']
    
    // 1.基本的解构,解构出数组所有的元素
    var [name1, name2, name3, name4] = names
    console.log(name1, name2, name3, name4) // curry kobe klay james // 2.解构部分元素,只解构后面两个元素
    var [, , name3, name4] = names
    console.log(name3, name4) // klay james // 3.解构出第一个元素,后面的元素放到一个新数组中
    var [name1, ...newNames] = names
    console.log(newNames) // [ 'kobe', 'klay', 'james' ] // 4.解构数组的同时,给元素指定默认值,如果数组中没有该元素,就会使用默认值
    var [name1, name2, name3, name4, name5 = 'default'] = names
    console.log(name1, name2, name3, name4, name5) // curry kobe klay james default
  • 对象的解构:对象的解构是不按顺序的,是根据key来赋值的。

    const obj = {
    name: 'curry',
    age: 30,
    team: '金州勇士'
    } // 1.基本的解构
    var { name, age, team } = obj
    console.log(name, age, team) // curry 30 金州勇士 // 2.解构的同时重命名
    var { name: newName, age: newAge, team: newTeam } = obj
    console.log(newName, newAge, newTeam) // curry 30 金州勇士 // 3.解构的同时指定默认值,当对象中没有该属性时,就会取默认值
    var { height = '1.83' } = obj
    console.log(height) // 1.83 // 4.同时重命名和指定默认值
    var { height: newHeight = '1.83' } = obj
    console.log(newHeight) // 1.83
  • 解构的应用场景:一般开发中拿到一个变量,可以对齐进行解构使用,比如对函数的参数进行解构。

    function fn({ name, age, team }) {
    console.log(name, age, team)
    }
    fn(obj) // curry 30 金州勇士

1.3.let和const的使用

在ES5中,声明变量都是使用var,从ES6开始新增了两个声明变量的关键字let和const。

  • let关键字:从直观的角度来说,let和var是没有太大的区别的,都是用于声明一个变量。

    let message = 'hello world'
  • const关键字:const声明的变量称为常量,表示保存的数据一旦被赋值就不能再被修改了,但是如果是引用类型的数据,还是可以通过引用找到对应的对象进行修改的。

    const obj = {
    name: 'curry',
    age: 30
    }
    const names = ['curry', 'kobe'] obj.name = 'kobe'
    names.push('klay') console.log(obj) // { name: 'kobe', age: 30 }
    console.log(names) // [ 'curry', 'kobe', 'klay' ] // 注意:不能直接给引用类型重新赋值
    /*
    obj = {} // TypeError: Assignment to constant variable.
    names = [] // TypeError: Assignment to constant variable.
    */
  • 注意:与var不同的是,let和const是不允许重复声明变量的。并且使用let和const声明的变量是具有自己的块级作用域的。var和let可以不设置初始值,const必须设置。

有关作用域提升的问题:

使用过var关键字的人都知道,var声明的变量是会进行作用域提升的,如果使用let和const声明的变量,是不允许在声明之前对其进行访问的,会直接报错。

console.log(message) // undefined
var message = 'hello world'
console.log(message) // ReferenceError: Cannot access 'message' before initialization
let message = 'hello world'

为什么var声明的变量有作用域提升,而let和const没有呢?

  • 作用域提升:在声明变量的作用域中,如果这个变量可以在声明之前被访问,那么就可以称之为作用域提升。
  • 在JavaScript执行之前,会先对我们声明的变量进行收集创建,普通变量的默认值都为undefined,只有等到执行赋值代码时,该变量才会被真正赋值,所以在声明之前访问就为undefined。
  • 那let和const不能访问,是不是let和const声明的变量没有在代码执行前被收集创建呢?到底let和const有没有作用域提升?
    • 其实let和const声明的变量在代码执行前是有被收集创建的,只是不能访问而已,所以就不能称之为作用域提升,在ECMA262对let和const的描述中,这些变量会被创建在包含它们的词法环境被实例化时,但是是不可以访问它们的,直到词法绑定被求值(也就是变量被赋值之后);
    • 在使用var声明的变量,是会添加到window上的,而let和const声明的变量是不会被添加到window上的,实际上是被添加到了变量环境中进行存储;
    • 暂时性死区:在代码中,使用let、const声明的变量,在声明之前变量是不可以被访问的,这种现象称之为temporal dead zone(TDZ);

总结:在上面的代码中,其实message在代码执行前就已经被创建了,在用let进行修饰后,js底层会对其进行约束,以至于在声明前不可以访问。

1.4.模板字符串

ES6允许使用字符串模板来嵌入JS的变量或者表达式来进行拼接。

使用``来编写字符串,可以${expression}来嵌入动态内容,里面可以写一个表达式。

const name = 'curry'
const age = 30 console.log(`My name is ${name}\nMy age is ${age}`)

标签模板字符串:模板字符串另外一种用法,可以用来调用函数,如果使用标签模板字符串,并且在调用的时候插入其他的变量。

  • 模板字符串被拆分了;
  • 第一个元素是数组,元素为被${}的字符串组合;
  • 后面的元素是一个个${}中传入的变量值;
function fn(x, y, z) {
console.log(x, y, z)
} const name = 'curry'
const age = 30 fn`sojfo${name}hghaooa${age}jgoajg` // [ 'sojfo', 'hghaooa', 'jgoajg' ] curry 30

应用:在react中编写css就有这么一个库叫styled-components,其原理就是使用的标签模块字符串。

1.5.函数的默认参数

在ES6之前,我们编写的函数参数是没有默认值的,而ES6给我们提供了默认参数,如果传入了该参数就使用传入的值,没有传入就使用默认值。

  • 在ES6之前,如果想实现默认参数的效果,就必须编写以下最终代码。

    function fn() {
    var m = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'aaa'
    var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'bbb'
    console.log(m, n)
    } fn() // aaa bbb
    fn(111, 222) // 111 222
  • 在ES6中,可以在声明函数时给其参数默认值。

    • 一般默认值写法:

      function fn(m = 'aaa', n = 'bbb') {
      console.log(m, n)
      }
    • 默认值搭配解构的使用:

      // 1.写法一:对象参数+解构
      function fn1({ name, age } = { name: 'curry', age: 30 }) {
      console.log(name, age)
      }
      fn1() // curry 30 // 2.写法二:解构+默认值
      function fn2({ name = 'curry', age = 30 } = {}) {
      console.log(name, age)
      }
      fn2() // curry 30

注意:有默认值的参数一般会放到最后,在JS中函数都会有一个length属性,length长度代表函数参数个数,但是有默认值的参数是不会被计算在内的。但是如果将有默认值的参数放在中间,那么后面的参数也不会被计算在内的。

function fn1(x, y, z) {}
console.log(fn1.length) // 3 function fn2(x, y, z = 30) {}
console.log(fn2.length) // 2 function fn3(x, y = 30, z) {}
console.log(fn3.length) // 1

1.6.函数的剩余参数

ES6中引用了剩余参数,可以将不定数量的参数放入到一个数组中,如果最后一个参数是以...为前缀的,那么它会将剩余的参数放入到该参数中,并且作为一个数组。

剩余参数和arguments有什么区别呢?

  • 剩余参数只包含那些没有对应形参的实参,而arguments对象包含了传给函数的所有实参;
  • arguments对象不是一个真正的数组,而rest是一个真正的数组,可以进行数组的所有操作;
  • arguments是早期的ECMAScript中为了方便去获取所有的参数提供的一个数据结构,而剩余参数是ES6中提供并且希望代替arguments的;
function foo(m, n, ...args) {
console.log(m, n, args)
console.log(arguments) // [Arguments] { '0': 10, '1': 20, '2': 30, '3': 40, '4': 50 }
} foo(10, 20, 30, 40, 50) // 10 20 [ 30, 40, 50 ]

1.7.箭头函数

相比于普通函数,箭头函数有一下几个特殊点:

  • 箭头函数内部是不绑定this的,会去它上一层作用域中找;
  • 箭头函数是没有显示原型的,所以不能作为构造函数,使用new操作符来调用;
  • 箭头函数没有自己的argments;
const fn = () => {
console.log(this)
// console.log(argments) // ReferenceError: argments is not defined
} fn() // window对象
console.log(fn.prototype) // undefined

1.8.展开语法

展开语法(spread syntax)可以在函数调用或数组构造是,将数组表示或者字符串在语法层面展开,还可以在构造字面量对象时,将对象表达式按键值对的方式展开。

展开语法的主要使用场景:在函数调用时数组构造时使用:

const nums = [1, 2, 3]
const str = 'abc' function fn(x, y, z) {
console.log(x, y, z)
} // 函数调用时
fn(...nums) // 1 2 3
fn(...str) // a b c // 数组构造时
const newNums1 = [...nums, 4, 5]
const newNums2 = [...nums, ...str]
console.log(newNums1) // [ 1, 2, 3, 4, 5 ]
console.log(newNums2) // [ 1, 2, 3, 'a', 'b', 'c' ]

1.9.数值的表示

ES6中规范了二进制和八进制的写法。

const num1 = 188 // 十进制
const num2 = 0b101 // 二进制
const num3 = 0o567 // 八进制
const num4 = 0x8cf // 十六进制 // 打印转成对应的十进制数
console.log(num1, num2, num3, num4) // 188 5 375 2255

1.10.Symbol的使用

在ES6之前,对象属性名都是字符串形式,很容易造成属性名冲突,Symbol是ES6中新增的一个基本数据类型,可用来生成一个独一无二的值。

  • 作为属性名:

    const s1 = Symbol()
    const s2 = Symbol()
    const s3 = Symbol() // 对比调用Symbol生成的值
    console.log(s1 === s2) // false // Symbol值作为对象key
    // 写法一:定义对象字面量时使用
    const obj = {
    [s1]: 'aaaa'
    }
    // 写法二:对象新增属性
    obj[s2] = 'bbbb'
    // 写法三:通过Object.defineProperty()
    Object.defineProperty(obj, s3, {
    enumerable: true,
    configurable: true,
    writable: true,
    value: 'cccc'
    }) console.log(obj) // { [Symbol()]: 'aaaa', [Symbol()]: 'bbbb', [Symbol()]: 'cccc' }
  • 作为属性值:

    const s1 = Symbol()
    
    const obj = {
    name: 'curry',
    age: s1
    } console.log(obj) // { name: 'curry', age: Symbol() }
  • 注意:Symbol作为属性名时,不能通过.方式来获取,也就是obj.s1,只能通过obj[s1]的方式获取。并且在通过Object.keys()获取对象所有的key时,是获取不到这些Symbol的,可以借助Object.getOwnPropertySymbols()来获取所有类型为Symbol的key。

    console.log(obj.s1) // undefined
    
    console.log(obj[s1]) // aaaa
    console.log(obj[s2]) // bbbb // 使用Object.keys获取对象所有key并打印,发现数组中是没有Symbol的key
    console.log(Object.keys(obj)) // [] // 使用Object.getOwnPropertySymbols(obj)获取所有的Symbol的key
    console.log(Object.getOwnPropertySymbols(obj)) // [ Symbol(), Symbol(), Symbol() ]

延伸:Symbol的作用就是给我们创建一个独一无二的值,如果我们想创建一个相同的Symbol可以怎么做呢?

  • 可以使用Symbol.for()来做到这一点;
  • 并且可以通过Symbol.keyFor()方法来获取对应的key;
// 通过Symbol.for(描述)创建并传入相同描述
const s1 = Symbol.for('aaaa')
const s2 = Symbol.for('aaaa') console.log(s1 === s2) // true // 拿到s1传入的值
const key = Symbol.keyFor(s1)
console.log(key) // aaaa // 将拿到的值又传给s3
const s3 = Symbol.for(key)
console.log(s3 === s1) // true
console.log(s3 === s2) // true

1.11.Set和WeakSet的使用

在ES6之前,存储数据的结构主要有两种,分别是数组和对象。在ES6中新增了另外两种数据结构:Set、Map,以及它们另外形式的WeakSet、WeakMap。下面就先来看看Set和WeakSet。

(1)Set:用于保存数据,类似于数组,与数组不同的是Set中的元素是不能重复的。

  • Set的基本使用:

    // 1.创建一个Set结构
    const set = new Set() // 2.往set中添加元素
    set.add(30)
    set.add(30) // 相同的基本数据类型只会保留一个
    set.add('abc')
    set.add(undefined)
    set.add({})
    set.add({}) // 对象可以重复的原因是,对象存放的是内存地址
    set.add(NaN)
    set.add(NaN) // 为什么NaN也不能重复,因为在Set内部会视NaN为同一个东西 console.log(set) // Set(6) { 30, 'abc', undefined, {}, {}, NaN }
  • Set常见的属性:

    • size:返回Set中元素的个数;

      console.log(set.size) // 6
  • Set常见的方法:

    • add(value):添加一个元素,返回set对象本身;
    • delete(value):从set中删除与value值相等的元素,返回boolean类型;
    • has(value):判断set中是否存在value这个元素,返回boolean;
    • clear():清空set中所有的元素,无返回值;
    • forEach(callback,[thisArg]):遍历set对象(Set的实例化对象是一个可迭代对象,所以也支持for...of遍历);
    // add
    console.log(set.add(30)) // Set(1) { 30 }
    console.log(set.add(60)) // Set(2) { 30, 60 }
    console.log(set.add(90)) // Set(2) { 30, 60, 90 }
    // delete
    console.log(set.delete(40)) // 未找到40,返回false
    console.log(set.delete(30)) // true
    // has
    console.log(set.has(60)) // true
    console.log(set.has(30)) // false
    // forEach
    set.forEach(item => {
    console.log(item) // 60 90
    })
    // for...of
    for (const item of set) {
    console.log(item) // 60 90
    }
    // clear
    set.clear()
    console.log(set) // Set(0) {}

(2)WeakSet:也要求内部元素不能重复。

  • WeakSet与Set的区别:

    • 区别一:WeakSet中只能存放对象类型,不能存放基本数据类型;
    • 区别二:WeakSet对元素的引用是弱引用,如果没有其他引用对该元素进行引用,是可以被GC回收的;
    • 区别三:WeakSet由于是弱引用的原因,所以是不能进行遍历的,存储到WeakSet中的对象是没办法通过遍历获取的;
    • 什么是弱引用?:简单理解就是对对象类型的引用是可以看成没有的,但是却可以访问其对象内部的数据;
  • WeakSet常见方法:add(value)、delete(value)、has(value),没有clear和forEach;

  • WeakSet的基本使用:

    const wSet = new WeakSet()
    // 只能存放对象类型
    // wSet.add(10) // TypeError: Invalid value used in weak set
    wSet.add({ name: 'curry', age: 30 })
    wSet.add([1, 2, 3])

1.12.Map和WeakMap的使用

下面来讲讲Map和WeakMap,主要用于存储映射关系。

(1)Map:对于普通对象存储映射关系,只能使用字符串或者Symbol作为属性名,如果普通对象使用对象来作为key的话,会自动将对象转成字符串,但是Map允许我们使用对象作为key。

const obj1 = { name: 'curry', age: 30 }

const obj = {
[obj1]: 'aaaa'
}
// 普通对象使用对象作为key,对象会自动转成字符串[object Object]
console.log(obj) // { '[object Object]': 'aaaa' }
  • Map的基本使用:

    const obj1 = { name: 'curry', age: 30 }
    const obj2 = { name: 'kobe', age: 24 } // 方式一:创建map后,通过set添加属性
    const map1 = new Map()
    map1.set(obj1, 'aaaa')
    map1.set(obj2, 'bbbb') // 方式二:创建map时,传入一个数组
    const map2 = new Map([
    [obj1, 'aaaa'],
    [obj2, 'bbbb']
    ]) console.log(map1)
    console.log(map2)

  • Map常见的属性:

    • size:返回Map中元素的个数;

      console.log(map1.size) // 2
  • Map常见的方法:与Set很相似,设置和获取属性不太一样。

    • set(key, value):在Map中添加key和value,并且返回整个map对象;
    • get(key):根据key获取map中的value;
    • has(key):判断map中是否包含某一个key,返回boolean值;
    • delete(key):根据key删除一个键值对,返回boolean值;
    • clear():清空所有的属性;
    • forEach(callback, [thisArg]):遍历map(也可使用for...of遍历);
    const map = new Map()
    const obj = { name: 'curry', age: 30 } // set
    map.set(obj, 'aaaa')
    map.set('bbbb', 1234)
    map.set(11, 'cccc')
    // get
    console.log(map.get(obj)) // aaaa
    // delete
    console.log(map.delete(11)) // true
    console.log(map.delete(22)) // false
    // has
    console.log(map.has('bbbb')) // true
    console.log(map.has('abc')) // false
    // forEach
    map.forEach((value, key) => {
    console.log(key, value)
    /*
    { name: 'curry', age: 30 } aaaa
    bbbb 1234
    */
    })
    // clear
    map.clear() console.log(map) // Map(0) {}

    如果map使用for...of遍历,看一下遍历出来的值是什么样子的:

    // 这里取出的item是一个个数组,数组第一个元素是key,第二个元素是value
    for (const item of map) {
    console.log(item)
    } // 所以可以在取值的时候对item进行解构
    for (const [key, value] of map) {
    console.log(key, value)
    }

(2)WeakMap:也是以键值对的形式存在。

  • WeakMap和Map的区别:与Set和WeakSet的区别类似;

    • 区别一:WeakMap的key只能使用对象,不接受其他类型作为key;
    • 区别二:WeakMap的key对对象的引用是弱引用,如果没有其他引用指向这个对象,那么GC可以回收该对象;
    • 区别三:WeakMap和WeakSet一样也不能进行遍历;
  • WeakMap常见的方法:set(key, value)、get(key)、has(key)、delete(key),没有clear和forEach;

2.ES7相关知识点

2.1.数组的includes方法

在ES7之前,判断数组中包含某一个元素,一般可以用indexOf判断是否为-1,ES7给我们提供了includes方法来判断数组中是否包含指定元素,返回boolean类型;

arr.includes(valueToFind[, fromIndex])
  • valueToFind:需要查找的元素;
  • fromIndex:从指定索引开始查找,如果from为负值,就从array.length + fromIndex的位置开始查找(默认值为0);
const names = ['curry', 'kobe', NaN]

console.log(names.includes('curry')) // true
console.log(names.includes('klay')) // false
console.log(names.includes('curry', 1)) // false console.log(names.indexOf(NaN)) // -1
console.log(names.includes(NaN)) // true

注意:includes方法是可以判断NaN是否存在的,因为includes的内部实现对NaN采用isNaN方法进行判断。

2.2.指数运算符

在ES7之前,计算数字的指数需要通过Math.pow方法来完成,在ES7中,增加了**运算符,可以来计算指数。

计算2的3次方:

const res1 = Math.pow(2, 3)
const res2 = 2 ** 3 console.log(res1, res2) // 8 8

3.ES8相关知识点

3.1.获取对象所有的value

我们知道可以使用Object.keys获取一个对象的所有key,ES8给我们提供了Object.values来获取所有的value值。

const obj = {
name: 'curry',
age: 30,
team: '勇士'
} // 传入一个对象
console.log(Object.values(obj)) // [ 'curry', 30, '勇士' ]
// 传入一个字符串,达到split的效果
console.log(Object.values('abc')) // [ 'a', 'b', 'c' ]

3.2.Object的entries方法

通过Object.entries()可以获取到一个二维数组,数组中会存放可枚举的键值对数组,数组元素分别为对象的key和value。

const obj = {
name: 'curry',
age: 30,
team: '勇士'
} // 传入一个对象
console.log(Object.entries(obj)) // [ [ 'name', 'curry' ], [ 'age', 30 ], [ 'team', '勇士' ] ] for (const [key, value] of Object.entries(obj)) {
console.log(key, value)
/*
name curry
age 30
team 勇士
*/
} // 传入一个数组,下标作为第一个元素
console.log(Object.entries(['curry', 'kobe', 'klay'])) // [ [ '0', 'curry' ], [ '1', 'kobe' ], [ '2', 'klay' ] ] // 传入一个字符串,下标作为第一个元素
console.log(Object.entries('abc')) // [ [ '0', 'a' ], [ '1', 'b' ], [ '2', 'c' ] ]

3.3.字符串的填充

如果需要对字符串进行前后填充,来实现某种展示格式,ES8中提供了padStart和padEnd方法,分别可以对字符串进行首位填充。

const str = 'ssssssssss'

// 如果指定填充的位数小于等于str的长度,就不会进行填充
// 指定的位数需大于str的长度,就会填充str长度减去指定位数
// 如下指定了15,最终填充的只有5位,因为str的长度为10
console.log(str.padStart(15, '*')) // *****ssssssssss
console.log(str.padEnd(15, '-')) // ssssssssss-----

应用场景:字符串的填充可以用于对身份证、银行卡进行位数隐藏。

const bankCard = '2034399002125581'
// 截取银行卡后四位数组
const lastFourNum = bankCard.slice(-4)
// 将前面数组全部填充为*
const finalBankCard = lastFourNum.padStart(bankCard.length, '*')
console.log(finalBankCard) // ************5581

3.4.Object的getOwnPropertyDescriptors方法

Object.getOwnPropertyDescriptors()方法用来获取一个对象的所有自身属性的描述符。

const obj = {}

Object.defineProperties(obj, {
name: {
configurable: false,
writable: false,
enumerable: false,
value: 'curry'
},
age: {
configurable: true,
writable: true,
enumerable: true,
value: 30
}
}) console.log(Object.getOwnPropertyDescriptors(obj))

4.ES9相关知识点

4.1.对象的展开语法

在前面讲了,数组是可以使用展开语法的,在ES9中,在构建对象字面量时,也可以使用展开语法了。

const obj1 = {
name: 'curry',
age: 30
} const newObj1 = { ...obj1, team: '勇士' }
console.log(newObj1) // { name: 'curry', age: 30, team: '勇士' }

注意:对象的展开运算符只能实现浅拷贝,如果对象内部还包含引用类型的值,就会指向同一地址空间。

const obj = {
name: 'curry',
age: 30,
friends: ['kobe', 'klay']
} const newObj = { ...obj }
newObj.friends.push('james')
console.log(newObj) // { name: 'curry', age: 30, team: '勇士' }
console.log(obj) // { name: 'curry', age: 30, friends: [ 'kobe', 'klay', 'james' ] }

5.ES10相关知识点

5.1.flat和flatMap

(1)flat方法

按照一个可指定的深度递归遍历数组,并将所有的元素和遍历到的子数组合并为一个新数组返回。(可用于数组扁平化)

const nums = [1, 2, [3, 3], [4, [5, 5]]]

// 对数组进行降维处理
console.log(nums.flat(1)) // [ 1, 2, 3, 3, 4, [ 5, 5 ] ]
console.log(nums.flat(2)) // [ 1, 2, 3, 3, 4, 5, 5 ]
// 如果不知道数组嵌套了多少层,可直接指定Infinity
console.log(nums.flat(Infinity)) // [ 1, 2, 3, 3, 4, 5, 5 ]

(2)flatMap方法

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

  • flatMap先进行map操作,然后做flat操作;
  • flatMap中的flat操作深度为1;
const arr = [[1, 2, 3, 4], ['a', 'b','c', 'd']]

// 数组自动降一维
const newArr = arr.flatMap(item => {
return item
}) console.log(newArr) // [ 1, 2, 3, 4, 'a', 'b', 'c', 'd' ]

5.2.Object的fromEntries方法

在前面讲了可以通过Object.entries()将一个对象转换成键值对数组,而Object.fromEntries()可以将键值对列表转换成对象。

const entries = [
['name', 'curry'],
['age', 30]
] const obj = Object.fromEntries(entries)
console.log(obj) // { name: 'curry', age: 30 }

应用场景:解析url的query部分,将其转成一个对象。

const url = 'http://127.0.0.1:8000/search?name=curry&age=30'

const queryStr = url.slice(url.indexOf('?') + 1, url.length)
console.log(queryStr) // name=curry&age=30 // URLSearchParams:可用于处理url的查询字符串
const queryParams = new URLSearchParams(queryStr)
console.log(queryParams) // URLSearchParams { 'name' => 'curry', 'age' => '30' } const paramObj = Object.fromEntries(queryParams)
console.log(paramObj) // { name: 'curry', age: '30' }

5.3.去除字符串首尾空格

去除一个字符串首尾空格可以通过trim()方法,而trimStart和trimEnd方法分别可以单独去除字符串前或后的空格。

// 这里以·代表空格
const str = '····ssss···'
console.log(str.trim()) // ssss
console.log(str.trimStart()) // ssss···
console.log(str.trimEnd()) // ····ssss

5.4.Symbol的description

在前面讲了Symbol类型,在创建一个Symbol类型的值时,还可以传入指定的描述符。

const s1 = Symbol('aaaa')
const s2 = Symbol('bbbb') console.log(s1.description) // aaaa
console.log(s2.description) // bbbb

6.ES11相关知识点

6.1.BigInt类型

在JavaScript中,如果数字过大,可能是不正确的,先看看JavaScript提供给我们的最大值和最小值是多少。

const maxNum = Number.MAX_SAFE_INTEGER
const minNum = Number.MIN_SAFE_INTEGER console.log(maxNum) // 9007199254740991
console.log(minNum) // -9007199254740991

如果给最大值再加大数值,很明显数值是不正确的:

console.log(maxNum + 1) // 9007199254740992
console.log(maxNum + 2) // 9007199254740992

所以,ES11引入了新的数据类型BigInt,可用于表示很大的整数:

  • BigInt的写法需要在数值后面加上n
  • 只有数值同为BigInt类型才能进行运算(不能进行隐式转换),如果需要运算的数据不是BigInt类型就要加上n转成BigInt;
  • 也可使用BigInt()方法进行转类型;
const bigInt = 9007199254740991n
console.log(bigInt + 2n) // 9007199254740993n
console.log(bigInt + bigInt) // 18014398509481982n

6.2.空值合并操作符(??)

如果||不能对空字符串和0进行很好的判断,就可以使用??

const test1 = ''
const test2 = 0
const test3 = null
const test4 = undefined const res1 = test1 || 'default'
const res2 = test2 || 'default'
console.log(res1) // default
console.log(res2) // default // ??认为空字符串和0是真值的
const res3 = test1 ?? 'default'
const res4 = test2 ?? 'default'
console.log(res3) // ''
console.log(res4) // 0 // 只有当??前面的值为null或者undefined,才会使用后面的值
const res5 = test3 ?? 'default'
const res6 = test4 ?? 'default'
console.log(res5) // default
console.log(res6) // default

6.3.可选链

可选链(Optional Chaining)的主要作用就是让代码在进行null和undefined判断时更加清晰和简洁,确保我们访问对象属性是安全的(因为从undefined里面取值是会报错的)。

const obj = {
name: 'curry',
friend: {
name: 'kobe',
age: 24
}
} // 先判断obj中是否有friend属性,然后再判断friend中是否有name属性
console.log(obj?.friend?.name) // kobe // console.log(obj.teammate.name) // TypeError: Cannot read property 'name' of undefined
// obj中没有teammate属性,所以就直接返回undefined,不会再从undefined中取name了,不会报错影响后面程序运行
console.log(obj?.teammate?.name) // undefined

6.4.globalThis

在ES11之前获取JavaScript的全局对象在不同的环境下的获取方式不同:

  • 浏览器中:this、window获取;
  • node中:global获取;

ES11中,对我们获取全局对象进行统一规范:

console.log(globalThis)

浏览器中:

node中:

7.ES12相关知识点

7.1.FinalizationRegistry

FinalizationRegistry对象可以让你在对象被垃圾回收时请求一个回调。

  • FinalizationRegistry提供了这样的一种方法:当一个在注册表中注册的对象被回收时,请求在某个时间点上调用一个清理回调;(清理回调有时被称为 finalizer )
  • FinalizationRegistry可实例化一个对象,可以借助该对象注册想要清理回调的对象,传入该对象和所含的值;
let obj1 = { name: 'curry', age: 30 }
let obj2 = { name: 'kobe', age: 24 } // 实例化注册表
const register = new FinalizationRegistry(value => {
console.log(`${value}对象被销毁了`)
}) // 注册obj1和obj2,并指定其值
register.register(obj1, 'obj1')
register.register(obj2, 'obj2') // 将两个对象销毁
obj1 = null
obj2 = null

需要借助浏览器的GC来进行测试,当两个对象被真正回收了,就会调用清理回调,打印对应内容:

7.2.WeakRef

在前面讲了WeakSet和WeakMap中的元素对对象的引用都是弱引用,WeakRef就可以专门实现对一个对象进行弱引用,也就是说该对象被GC回收时,是不会看它是否有弱引用的,有没有弱引用一样被回收。

可以结合上面的FinalizationRegistry进行测试:

  • WeakRef创建的弱引用需通过deref()来访问对象属性;
let obj = { name: 'curry', age: 30 }

// 创建一个弱引用weakObj指向对象{ name: 'curry', age: 30 }
let weakObj = new WeakRef(obj) // 拿到{ name: 'curry', age: 30 }对象
// console.log(weakObj.deref())
// console.log(weakObj.deref().name) // curry
// console.log(weakObj.deref().age) // 30 const register = new FinalizationRegistry(value => {
console.log(`${value}对象被销毁了`)
})
register.register(obj, 'obj') // 去掉obj对对象{ name: 'curry', age: 30 }的引用
obj = null // 等对象回收后再打印
setTimeout(() => {
// 注意:当弱引用的对象被GC回收后,weakObj.deref()的值为undefined
// 如果不想报错,可以使用可选链或者逻辑与
console.log(weakObj.deref()?.name)
console.log(weakObj.deref() && weakObj.deref().name)
}, 10000)

7.3.逻辑赋值运算

ES12为我们提供了三种逻辑赋值运算:

  • ||=:逻辑或赋值运算;

    let msg = undefined
    msg ||= 'default'
    console.log(msg) // default
    /*
    等同于:
    msg = msg || 'default'
    */
  • &&=:逻辑与赋值运算;

    let obj = {
    name: 'curry',
    age: 30
    }
    // 在obj有值的情况下,将obj赋值为obj.name
    obj &&= obj.name
    console.log(obj) // curry
    /*
    等同于:
    obj = obj && obj.name
    */
  • ??=:逻辑空赋值运算;

    let msg = 0
    // 当msg为null或undefined情况下,将msg赋值为default,这里为0,所以值还是0
    msg ??= 'default'
    console.log(msg) // 0
    /*
    等同于:
    msg = msg ?? 'default'
    */

注意:该新增特性可能过新,可能出现node版本不支持的情况,可以在浏览器中打印查看。

7.4.数值分隔符

当数值过长时,ES12允许我们使用_进行连接,方便阅读。

const num = 100_000_000
console.log(num) //100000000

7.5.字符串替换

ES12提供了一个replaceAll方法,该返回一个新字符串,新字符串所有满足 pattern 的部分都已被replacement 替换。pattern可以是一个字符串或一个RegExpreplacement可以是一个字符串或一个在每次匹配被调用的函数。

const newStr = str.replaceAll(regexp|substr, newSubstr|function)

将所有的a替换为b:

const str = 'ababababab'

// 字符串
const newStr1 = str.replaceAll('a', 'b')
// 正则
const regex = /a/g
const newStr2 = str.replace(regex, 'b') console.log(newStr1) // bbbbbbbbbb
console.log(newStr2) // bbbbbbbbbb

注意:该新增特性可能过新,可能出现node版本不支持的情况,可以在浏览器中打印查看。

总结:

本篇文字只总结了ES6-ES12部分简单知识点,还有一些其它ES6之后新增的特性,如Promise、迭代器、生成器、async、await等等,将会在后续的文章中进行整理。

ES6-ES12部分简单知识点总结,希望对大家有用~的更多相关文章

  1. 你知道 ES6~ES12等叫法是怎么来的吗?

    你知道 ES6~ES12等叫法是怎么来的吗? 前言 作为一名前端开发,学习 JavaScript 自是天经地义的事,但是,JavaScript 的发展历史是怎样的,恐怕有相当一部分人都不太了解. 我们 ...

  2. vue+node+es6+webpack创建简单vue的demo

    闲聊: 小颖之前一直说是写一篇用vue做的简单demo的文章,然而小颖总是给自己找借口,说没时间,这一没时间一下就推到现在了,今天抽时间把这个简单的demo整理下,给大家分享出来,希望对大家也有所帮助 ...

  3. 用ES6创建一个简单工厂模式

    1 什么是工厂模式? 工厂模式是用来创建对象的一种最常用的设计模式.我们不暴露创建对象的具体逻辑,而是将将逻辑封装在一个函数中,那么这个函数就可以被视为一个工厂.工厂模式根据抽象程度的不同可以分为:简 ...

  4. es6,async简单总结

    1.简单来讲就是把函数变为异步操作的 async function demo() { let result = Math.random(); console.log(result); } 2.asyn ...

  5. ES6工作中常用知识点

    好久不动笔了 第一个知识点:import 和 export import导入模块.export导出模块 //全部导入 import people from './example' //有一种特殊情况, ...

  6. html,css,js(包含简单的 ES6语法) 实现 简单的音乐盒

    知识要点 videoObject.load(): 加载某个视频(音频)文件,即重新播放 videoObject.play(): 播放视频(音频)文件 videoObject.remove(): 停止播 ...

  7. ES6之常用开发知识点:入门(一)

    ES6介绍 ES6, 全称 ECMAScript 6.0 ,2015.06 发版. let 和 const命令 let命令 let 命令,用来声明变量.它的用法类似于var,区别在于var声明的变量全 ...

  8. Linux&c 文件操作,线程进程控制,网络编程,简单知识点梳理

    一:文件操作 在linux下,一切皆文件,目录是文件,称为目录文件,内容是该目录的目录项(但是目录只有内核可以编辑,超级用户也不可以编辑),设备也是设备文件,在/dev存放的就是一些设备文件,linu ...

  9. Linux&c 文件操作,线程进程控制,网络编程,简单知识点梳理

    一:文件操作 在linux下,一切皆文件,目录是文件,称为目录文件,内容是该目录的目录项(但是目录只有内核可以编辑,超级用户也不可以编辑),设备也是设备文件,在/dev存放的就是一些设备文件,linu ...

随机推荐

  1. Java数据库连接池--DBCP浅析.

    一. 为何要使用数据库连接池假设网站一天有很大的访问量,数据库服务器就需要为每次连接创建一次数据库连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出.拓机.数据库连接是一种关键的有限的昂贵 ...

  2. Linux运维-常用操作-培训用例

    一.服务器环境 Centos 7.9 二.常用连接工具(免费) 1.Finalshell 2.MobaXterm 3.Putty + WinSCP 三.Linux  系统目录结构 /bin :是 Bi ...

  3. ubuntu关机和重启

    本博客旨在自我学习使用,如有任何疑问请及时联系博主 linux下常用的关机命令有:shutdown.halt.poweroff.init:重启命令有:reboot.下面本文就主要介绍一些常用的关机命令 ...

  4. Solution -「AGC 002F」「AT 2000」Leftmost Ball

    \(\mathcal{Description}\)   Link.   给你 \(n\) 种颜色的球,每个球有 \(k\) 个,把这 \(n\times k\) 个球排成一排,把每一种颜色的最左边出现 ...

  5. SpringBoot+JavaMailSender+Redis完整找回密码功能

    导入maven坐标 <parent> <groupId>org.springframework.boot</groupId> <artifactId>s ...

  6. 『德不孤』Pytest框架 — 8、Pytest断言

    目录 1.什么是断言 2.Pytest断言 3.Pytest的断言方式及应用场景 (1)使用assert语句 (2)断言预期的异常 (3)拓展 4.优化断言 5.使用标记检查异常 1.什么是断言 对于 ...

  7. BI分析系统是什么?有什么用?

    伴随着大数据概念的不断发展,存储成本越来越低,数据来源也越来越广泛,我们从原来只关心数据的大小,逐渐转变为如何让数据产生更多的价值.它也一直困扰着许多大小企业,越来越多的企业开始将BI分析系统应用到企 ...

  8. 思迈特软件Smartbi光鲜亮丽的背后是什么在支撑?

    思迈特软件Smartbi是国内知名BI厂商,自2011年成立以来就以提升和挖掘客户的价值为使命,致力于为客户提供一站式商业智能平台和BI解决方案,发展到如今已经获得了来自国家.地方政府.国内外权威分析 ...

  9. Nginx平滑升级的详细操作方法

    转至:https://blog.csdn.net/midion9/article/details/49684325 一.平滑升级概述Nginx方便地帮助我们实现了平滑升级.其原理简单概括,就是:(1) ...

  10. Oracle数据库的一些常用命令

    转至:https://blog.csdn.net/qq_36843413/article/details/81409152?utm_medium=distribute.pc_relevant_t0.n ...