高级JS-ES6~ES13新特性

122 阅读8分钟

let、const基本使用

  • var允许重复声明变量;let、const不允许重复声明变量
  • var声明的变量是会有作用域提升;使用let、const声明的变量,在声明之前访问会报错
  • let、const定义的标识符真正执行到声明的代码之前,是不能被访问的,存在暂时性死区
  • let、const没有作用域提升,但是会在解析阶段被创建出来
  • 全局通过var来声明一个变量,会在window上添加一个属性;let、const不会给 window 添加属性
  • var没有块级作用域;通过let、const、function、class声明的标识符是具备块级作用域的限制的
  • 函数有块级作用域,外面依然可以访问:因为引擎会对函数声明进行特殊处理,允许像var进行提升
let message2 = '你好啊'
message2 = '你好啊 大哥'
console.log(message2); // 你好啊 大哥

// 示保存的数据一旦被赋值,就不能被修改
const message3 = '香菜'
message3 = '喜欢吃'
console.log(message3); // Uncaught TypeError: Assignment to constant variable

// 如果赋值的是引用类型,可以通过引用找到对应的对象,修改对象的内容
const info = {
    name:'www',
    age:10
}
info.name = 'wqq'
console.log(info); // {name: 'wqq', age: 10}

模板字符串

// 基本用法
const name = 'www'
console.log(`我叫${name}`) // 我叫www
function bar() {
    return '香菜'
}
console.log(`我爱吃${bar()}`) // 我爱吃香菜

// 标签模板字符串的用法(React的styled-components库里用)
const age = 19
function foo(...args) {
    console.log('参数:',args);
}
foo`hello${name}, age is${age}` // [Array(3), 'www', 19]

函数默认值

有默认参数的形参,尽量放在最后面,且不会计算在length之内(后面所有的形参都不会计算在内)

剩余参数放在最后

/* 默认值写法:
     1. n1 = n1 ? n1 : '默认值'
     2. n1 = n1 || '默认值'
     3. n1 = (n1 === undefined || n1 === null) ? '默认值' : n1
     4. n1 = n1 ?? '默认值'
 */
function foo(n1 = 10, n2 = 20) {
    console.log(n1 + n2);
}
foo(10, 20)

// 默认参数解构
function foo1(obj={name:'ww',age:20}) {
    console.log(obj.name, obj.age);
}

function foo2({name,age} = {name:'ww',age:20}) {
    console.log(name, age);
}

function foo3({name = 'qq', age = '20'} = {}) {
    console.log(name, age);
}
foo()

展开语法

const obj ={
    name:'ww',
    age:10
}

// 在构建字面量的时候,可以使用展开运算符
const info = {
    ...obj,
    height:1.99
}


function foo(name, age, ...arg) {
    console.log(name, age, ...arg);
}

const obj = {
    name: 'ww',
    height: 1.22
}
// 可迭代对象:数组,字符串,argument
foo(...obj)  // 对象默认不是可迭代的,不可以这样使用

浅拷贝深拷贝

浅拷贝-原始类型:赋值引用,修改info1的值,obj的值也会改掉

image.png

浅拷贝-复杂类型,只会拷贝第一层数据

image.png

深拷贝-完全生成一个新的对象

深拷贝实现方案:第三方库、自己实现、间接利用js机制(拷贝不了函数)

const obj3 = JSON.parse(JSON.stringify(obj)) // 会完全创建一个新的对象
image.png

数字过长时可以用 _ 连接

const num = 1000_000_000

Symbol的基本使用

Symbo()用来生成一个独一无二的值

对象的属性名都是字符串形式,那么很容易造成属性名的冲突

在ES6中,对象的 key 可以使用字符串或者 Symbol值

用法

function baz(obj) {
    const key = Symbol()
    obj[key] = function () {} // 不会覆盖obj本身的key
    delete obj[key]
}

写法

// 写法一:字面量直接赋值
const s1 = Symbol()
const  obj = {
    [s1]:'aaa'
}

// 写法二:属性名赋值
const s2 = Symbol()
obj[s2] = 'bbb'

// 写法三: Object.defineProperty
Object.defineProperty(obj,s1,{
    value:'ddd'
})

获取Symbol对应的key,使用getOwnPropertySymbols方法

const keys = Object.getOwnPropertySymbols(obj)
for (const key of keys){
    console.log(obj[key]);
}

拿到Symbol描述,description

const s3 = Symbol('ccc')
console.log(s3.description)  // 可以拿到描述'ccc'
const s4 = Symbol(s3.description)
console.log(s3 === s4); // false
const s5 = Symbol.for(s3.description)
console.log(s4 === s5); // false

// 如果相同的key(s3.description), Symbol.for可以生成相同的Symbol值(了解)
const s6 = Symbol.for(s3.description)
console.log(s5 === s6); // ture

// 获取传入的key
console.log(Symbol.keyFor(s5)) // ccc

Set的基本使用

可以用来保存数据,类似于数组,但是和数组的区别是元素不能重复

// 创建Set
const set = new Set()
// 添加元素
set.add(10)
set.add(13)
set.add(14)
set.add(14)
const info = {}
set.add(info)
set.add(info)
console.log(set); // { 10, 13, 14, {...} }

// set常见的属性和方法
console.log(set.size); // 获取元素个数: 3
console.log(set.delete(14)); // 10 13
console.log(set.has(10)); //是否存在某个元素:true
set.forEach(item => console.log(item)) // 10 13

// set 支持for...of
for( const item of set) {
    console.log(item);
}
set.clear() // 清空set中所有的元素,没有返回值

应用场景(数组去重)

const name = ['aa','bb','cc','aa']
// 方式一:
const newArr = []
for (const key of name){
    // 判断新数组是否包含key
    if(!newArr.includes(key)) {
        newArr.push(key) // 没有就push进新数组
    }
}
console.log(newArr);  // ['aa', 'bb', 'cc']

// 方式二:
const newArr2 = Array.from(new Set(name))
console.log(newArr2); // ['aa', 'bb', 'cc']

WeakSet使用

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

WeakSet中只能存放对象类型

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

WeakSet 不能遍历

  • WeakSet常见的方法:

add(value):添加某个元素,返回WeakSet对象本身

delete(value):从WeakSet中删除和这个值相等的元素,返回boolean类型

has(value):判断WeakSet中是否存在某个元素,返回boolean类型

  • WeakSet的案例
const pWeakSet = new WeakSet()
class Person {
    constructor() {
        pWeakSet.add(this)
    }
    running(){
        if(!pWeakSet.has(this)){
            console.log('type error');
            return
        }
        console.log('running');
    }
}
const  p = new Person() // p = null的时候,就会进行销毁 
p.running()

Map的基本使用

  • size:返回Map中元素的个数
  • set(key, value):在Map中添加key、value,并且返回整个Map对象
  • get(key):根据key获取Map中的value
  • has(key):判断是否包括某一个key,返回Boolean类型
  • delete(key):根据key删除一个键值对,返回Boolean类型
  • clear():清空所有的元素
  • forEach():拿到的是value
  • for of进行遍历,将key,value组成数组返回

WeakMap的使用

对象的局限性:不可以使用复杂类型作为key

image.png

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

WeakMap的key对对象的引用是弱引用,如果没有其他引用引用这个对象,那么GC可以回收该对象

image.png
  • WeakMap常见的方法:

set(key, value):在Map中添加key、value,并且返回整个Map对象;

get(key):根据key获取Map中的value;

has(key):判断是否包括某一个key,返回Boolean类型;

delete(key):根据key删除一个键值对,返回Boolean类型;

应用

image.png

对象相关的属性

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

const obj = {
    name: 'www',
    age: 19,
    address: '成都'
}

// 获取所有的key
console.log(Object.keys(obj)); // ['name', 'age', 'address']

// 获取所有的value
console.log(Object.values(obj)); //  ['www', 19, '成都']

// 对对象的操作
const entries = Object.entries(obj)
console.log(entries);
for (const entry of  entries){
    const [key,value] = entry
    console.log(key, value);
}

// 对数组、字符串的操作
console.log(Object.entries(['abc', 'cda']));
console.log(Object.entries('hello'));

padStart 和 padEnd(字符串的首尾)

padStartpadEnd 方法,分别是对字符串的首尾进行填充的

// 对时间进行格式化
const  minute = '15'.padStart(2,'0')
const  second = '8'.padStart(2,'0')
console.log(`${minute}:${second}`) // 15:08 字符串的首尾

// 对数据格式化
let carNumber = '277382933281923339'
const sliceNumber = carNumber.slice(-4) // 3339
carNumber = sliceNumber.padStart(carNumber.length,'*')
console.log(carNumber); // **************3339

将当前字符串从末尾开始填充给定的字符串

const str1 = 'hello';
console.log(str1.padEnd(10, '.')); // hello.....

flat 和 flatMap

flat() 将多维数组扁平化

// flat的使用
const num = [12,435,[231],[13,23,[14,546]]]
console.log(num.flat(1)); // [12, 435, 231, 13, 23, Array(2)]
console.log(num.flat(2)); // [12, 435, 231, 13, 23, 14, 546]
const message = [
    'hello wqq',
    '你好啊 gg'
]

// for循环的方式:
const newInfo = []
for (const item of message) {
    const infos = item.split(' ')
    for (const info of infos) {
        newInfo.push(info)
    }
}
console.log(newInfo); // ['hello', 'wqq', '你好啊', 'gg']

// 先进性map,在进行flat
const newMeg = message.map(item => item.split(' ')) // [Array(5), Array(3)]
const finalMeg = newMeg.flat(1) // // ['hello', 'wqq', '你好啊', 'gg']

// flatMap的使用
const newMessage = message.flatMap(item => item.split(''))
console.log(newMessage); // ['hello', 'wqq', '你好啊', 'gg']

trimStart 和 trimEnd(去除首尾空格)

const message = '   hello wqq   '
console.log(message.trim()); //hello wqq
console.log(message.trimStart()); //hello wqq
console.log(message.trimEnd()); //   hello wqq

BigInt

const maxNum = Number.MAX_SAFE_INTEGER
console.log(maxNum); // 9007199254740991 安全的最大正整数

// BitInt的表示方法是在数值的后面加上n
const bigInt = 9007199254740991n
console.log(bigInt + 1n); // 9007199254740992n

空值合并运算符 ??

逻辑或 || 操作符在左侧操作数为假值时返回默认值,左侧为 0 或空字符串都会返回默认值

?? 操作符在左侧值为undefined和null就返回默认值

let info = ''
info1 = info || '默认值'  // 默认值
info2 = info ?? '默认值' // ''

可选链 ?.

const obj = {
    name: 'www',
    friend: {
        name:'qqq',
        running(){
            console.log('running');
        }
    }
}

if(obj.friend && obj.friend.running) {
    obj.friend.running()
}
// 可选链
obj?.friend?.running?.()

replaceAll(字符串替换)

const message = 'hello www'
const newMeg = message.replaceAll('www','qqq')
console.log(newMeg); // hello qqq

at方法

const nums = ['aaa','bbb','ccc']
const str = 'hello wq'
console.log(nums.at(1)); // bbb
console.log(nums.at(-1)); // ccc
console.log(str.at(1)); // e
console.log(str.at(-1)); // q

hasOwn

用于判断一个对象中是否有某个自己的属性

  • 防止对象内部有重写hasOwnProperty
  • 对于隐式原型指向null的对象, hasOwnProperty无法进行判断
let info = {
    name: 'www',
    age:10,
    __proto__:{
        address:'成都'
    }
}
console.log(Object.hasOwn(info, 'name')); // true
console.log(Object.hasOwn(info, 'address')); // false

定义class类中成员字段

class Person {
    // 对象属性(公共)
    height = 1.66

    // 约定的私有属性
    _intro = 'hello www'

    // es13私有属性
    #intro = 'message'

    // 类属性(公共)
    static totalCount = '70'

    // 类属性(私有)
    static #maleCount = '20'

    constructor(name, age) {
        this.name = name
        this.age = age
        this.address = '成都'
    }

    // 静态代码块
    static {
        console.log('吃香菜'); // 进行初始化操作
    }
}
const p = new Person('www',19)
console.log(p.height); // 1.66