10_ES6-ES12知识点
ES6
字面量的增强
属性(Property Shorthand)、方法(Method Shorthand)的简写,计算属性名(Computed Property Names)
var name = 'fks' |
解构Destructuring
- 解构数组
var names = ["asd", 'fgd', 'dkb'] |
解构对象
根据key解构
var obj = { |
let/const
let/const使用
let 声明一个变量
const 声明一个常量、衡量(constant)
var foo = 'foo' |
// let / const 定义的变量名是不可以重复定义的 |
let/const作用域提升
使用let声明的变量,在声明之前访问会报错
console.log(foo);
var foo = 'foo'
console.log(bar); // 声明之前访问会报错
// 在这里bar已经被创建出来了
let bar = 'bar' // Reference(引用)Error: Cannot access 'bar' before initialization那么是不是意味着foo变量只有在代码执行阶段才会创建呢?
- 事实上并不是,我们可以看一下ECMA262对 let 和 const 的描述
- 这些变量会被创建在包含他们的词法环境被实例化的时候,但是是不可以访问它们的,直到词法绑定被求值
那 let/const有没有作用域提升呢?
作用域提升:在声明变量的作用域中,如果这个变量可以在声明之前被访问,那么我们可以称之为作用域提升
所以被创建出来了,但不能被访问,不能称之为作用域提升
总结:let、const没有进行作用域提升,但是会在解析阶段被创建出来、
let/const变量保存
let / const 在全局声明变量保存在哪里了?
var foo = 'foo' |
- let, const 是不会给window添加任何属性的
- 最新的ECMA标准中对执行上下文的描述
也就是说我们声明的变量和环境记录是被添加到变量环境中的(在一个对象保存)
但是标准没有规定这个对象是 window对象或者是其他对象
所以JS引擎在解析的时候,会有自己的实现
比如v8中其实是通过VariableMap的一个hashmap来实现它们的存储的
那么window对象呢?
window对象是早起的GO对象,在最新的实现中其实是浏览器添加的全局对象,并且 一直保持了window和var之间值的相等性
块级作用域
var 没有块级作用域
ES5中,JS只会形成两个作用域:全局作用域和函数作用域
var 没有块级作用域
ES5中放到一个代码中定义的变量,外面是可以访问的
{
var foo = "foo"
}
console.log(foo); // foo
let / const 的块级作用域
ES6中新增了块级作用域,通过let、const、function、class 声明的标识符是具备块级作用域的限制的
注意函数,某些引擎会对函数的声明进行特殊处理,允许像var那样提升
{ |
- if/switch/for 语句的代码就是块级作用域
// if语句的代码就是块级作用域 |
块级作用域的应用场景
一个循环打印的问题
// 注意setTimeout是宏任务,循环结束后才执行 |
const注意的地方
因为有 i++,第二次循环需要用到第一次循环的i去++,const定义的是常量,是不可以改变的
for (const i = 0; i < 3; i++) { |
但是ES6新增的 for…of可以
for (const item of names) { |
每次都会有一个新的const item,在不同的块级作用域中
暂时性死区
在一个代码中,使用let、const声明的变量,在声明之前都是不可以访问的
这种现象称之为暂时性死区
function foo() { |
关于字符串
模板字符串
使用:
const name = 'sfa' |
${}里面也可以是表达式,也可以是函数
const str = `age is ${age * 2}` |
标签字符串
应该很少用到
// 第一个参数是模块字符串中的整个字符串,但是被切成多块放到一个数组 |
关于函数
函数的默认参数
如果没有传参,就会用默认参数
function foo(m = 'aaa', n = 'bbb') { |
默认参数也可以是对象,并且可以对对象解构,有两种解构方式
function foo({name, age} = {name: 'asd', age: 18}) { |
另外注意:默认形参最好放到最后
function bar(x, y, z = 30) { |
函数的剩余参数
剩余参数必须放到最后
function foo(a, b, ...args) { |
箭头函数的补充
没有自己的this,没有arguments
没有显式原型,所以不能作为构造函数,不能使用new创建对象
var bar = () => { |
展开语法…
const names = ['aaa','bbb','ccc'] |
注意:展开运算符其实是一种浅拷贝
简单来说就是,拷贝的地址,指向的是同一个对象
const info = { |
表示数值的方法(进制)
ob开头(binary):二进制,0o开头(octonary):八进制,0x开头(hexadecimal):十六进制
const num1 = 100 // 十进制 |
另外,大的数值有一个连接符,便于阅读(ES2021 ES12)
const num = 10_000_000_000_000 |
Symbol的使用
主要是用来创建独一无二的key值,注意使用的时候不要用new
创建Symbol
const s1 = Symbol() |
在对象中作为key使用
const obj = { |
注意:获取属性值的时候不能通过 . 语法获取,因为 . 后面的是会被当做字符串
obj.s1,那么就会去找obj上key为’s1’这个属性值
使用Symbol作为key的属性名,在遍历的时候是获取不到的
console.log(Object.keys(obj)); // [] |
如果想要获取的话可以使用 Object.getOwnPropertySymbols()方法
const sKeys = Object.getOwnPropertySymbols(obj) |
怎么让两个Symbol相等?
Symbol.for(key)
方法会根据给定的键key
,来从运行时的 symbol 注册表中找到对应的 symbol注意这跟 Symbol(‘aaa’) 标签是不一样的哦
// 也就是给symbol一个key |
根据 symbol值获取key
Symbol.keyFor(sym)
方法用来获取全局symbol 注册表中与某个 symbol 关联的键
const key = Symbol.keyFor(sa) |
Set
新增的一种数据结构(存储数据的方式)
是集合,里面的元素不重复
- 创建set和添加元素
// 1. 创建 |
注意添加对象时候的一种情况,因为添加的对象的地址是不一样的
set.add({}) |
- 最常见的应用:对数组去重
// 去重(把数组放进集合) |
- Set的属性
set.size 返回元素个数 |
- Set的方法
add() 添加元素 |
WeakSet
用的很少,对于WeakSet的应用我就不纠结了
WeakSet跟set的区别:WeakSet只能存放对象类型
WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收
另外,WeakSet不能遍历,因为WeakSet只是对对象的弱引用,如果我们遍历获取到其中的元素那么有可能造成对象不能正常销毁,所以存储到WeakSet中的对象是没办法获取的
const weakSet = new WeakSet() |
我对弱引用的理解
关于强引用弱引用的一篇文章:https://juejin.cn/post/6993101968545677319#heading-21
Map
一种数据结构,键值对的形式,并且键可以是对象
普通对象的键不能是对象?不能
const obj1 = { name: 'aaa' } |
怎么使用Map?
// 使用 |
有什么属性和方法?
属性:size:返回map对象的成员数量
方法:
set(key, value) :添加,设置键值,返回整个Map对象
get(key):根据key获取值
has(key):是否存在某一个key,返回布尔值
delete(key):删除一个键值对,返回布尔值
clear():清空元素
遍历 forEach()
// 遍历
map.forEach((item, key) => {
console.log(item, key);
})
// for..of遍历注意
for (const item of map) {
// console.log(item); // 这里把一个键值对放到一个数组了
// [ { name: 'bbb' }, 'bbb' ]
// 所以可以根据索引值分别拿 key, value
console.log(item[0], item[1]);
}
// 或者进行解构
for (const [key, value] of map) {
console.log(key, value);
}
WeakMap
和Map有什么区别呢?
- WeakMap的key只能使用对象
- WeakMap的key对对象的引用是弱引用,如果没有其他引用引用这个对象,那么GC可以回收
常见方法:
- set(key, value):添加键值,返回整个对象
- get(key):根据key获取值
- has(key):是否包含某个key,返回布尔值
- delete(key):根据key删除键值对,返回布尔值
WeakMap不能遍历
const obj = { |
响应式原理中的WeakMap使用
可以看看Vue3的响应式原理,之前实现mini-vue的时候实现过响应式系统
简单的思想就是:
创建一个WeakMap, key是obj1,值是一个Map结构,
这个Map,键是对象的属性,值是有依赖这个属性的函数,
当这个属性发生什么改变的时候,就执行这个属性所有依赖的函数
一个简单的响应式模拟实现
// 应用场景(vue3响应式原理) |
ES7
Array Includes
判断数组中是否包含某个元素
在之前我们经常使用 indexOf() 判断,该方法返回元素所在的索引值,没有就返回-1
const names = ['aaa', 'bbb', 'ccc', 'ddd'] |
ES7 新增 Includes 方法
if (names.includes('bbb')) { |
对于 NaN的处理,indexOf()不能判断,includes可以
const names = ['aaa', 'bbb', 'ccc', 'ddd', NaN] |
指数的运算方法
// 在之前,指数运算通过 Math.pow() |
ES8
Object.values
之前我们可以通过 Object.keys()来获取一个对象的所有key,ES8提供Object.values() 获取所有值
const obj = { |
Object.entries
获取到一个数组,数组中存放可枚举属性的键值对数组
const obj = { |
padStart和padEnd
根据所给长度,和填充元素来往前或往后填充数组
const message = "hello world" |
小案例:假设要对银行卡号用*隐藏
// 案例 |
slice 可以传入负数的哦,-4,倒数4位
Trailing-Commas
ES8,允许在函数定义和调用时多加一个逗号
没什么,反正我们平时也不会加。trailing:后面的,commas:逗号
function foo(a, b,) {} |
Object Descriptors
ES8中新增对对象的操作,Object.getOwnPropertyDescriptors()
获取一个对象的所有自身属性的描述符
const obj = { |
ES8 新增async await 的函数使用,后面另外记
ES9
Async iterators:迭代器,后续另外笔记
Object spread operators:对象展开运算符
const newObj = {...obj, age:18}
Promise finally:后续Promise统一记
ES10
flat flatMap
flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回
// flat |
flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组
先进行map,再flat,并且flat的深度为1
const nums2 = [1,2,3,4,5] |
这样看起来跟map没什么区别呀?那flatMap有什么应用场景吗?
处理这样的字符串数组,把字符串分成一个个放到数组
const message = ["Hello World", "hello kk", "my name is xxx"] |
Object fromEntries
ES8有Object.entries将一个对象转换成entries
ES10有Object.fromEntries 将entries转换成对象
const obj = { |
有什么应用场景吗?
可以处理query参数,最终转换成对象使用
看到键值对的数组可以想到这个方法
const queryString = 'name=xxx&age=18&height=1.88' |
trimStart trimEnd
单独去除前面或后面的空格
const str = ' hello world ' |
Symbol description
s1.description 这个属性可以获取symbol的描述(标签),前面symbol的笔记有写到
Optional catch binding
后续在try catch部分笔记
ES11
BigInt
ES11引入的新的数据类型,用于表示大的整数
使用:加个n,或者 BigInt(num)
// ES11前 最大的安全整数 |
Nullish Coalescing Operator
空值 合并 运算
新增的操作符:??
处理如果为空,那么使用默认值的判断
之前的 || 不能很好的处理空字符串,空串转为false,执行后面的语句
const foo = "" |
Optional Chaining
可选链:让我们的代码在进行 null 和 undefined 判断时更加清晰和简洁
const info = { |
Global This
在之前我们想获取JS环境的全局对象,不同环境获取的方式又不一样
比如在浏览器中,通过 this,window来获取
Node中,通过global获取
所以 ES11 中对获取全局对象进行统一的规范:globalThis
// 浏览器下 |
for…in标准化
在ES11之前,虽然很多浏览器支持 for…in 来遍历对象,但是并没有被ECMA标准化
ES11中,对其进行标准化,for…in 用于遍历对象的 key
const obj = { |
Dynamic Import
后续在 ES Module 模块化中笔记
Promise.allSettled
后续Promise中笔记
import meta
后续在 ES Module 模块化中笔记
ES12
FinalizationRegistry
FinalizationRegistry对象可以让你在对象被垃圾回收时请求一个回调
当一个在注册表中注册的对象被回收时,可以请求在某个时间点上调用一个清理回调(清理回调有时被称为 finalizer)
注册:register方法,注册任何想要清理后执行回调的对象,传入该对象,和所含的值
const finalRegistry = new FinalizationRegistry((value) => { |
WeakRefs
如果我们默认将一个对象赋值给另一个引用,那么这个引用是强引用
如果我们希望是弱引用,可以使用 WeakRef
注意这里有一个 deref 方法获取弱引用的值
const finalRegistry = new FinalizationRegistry((value) => { |
logical assignment operators
logical:逻辑的
几个逻辑赋值运算符 ||=,&&=(很少用),??=
可读性不是很好
- ||= 逻辑或赋值运算
let message = '' |
- &&= 逻辑与赋值运算(很少用)
let obj = { |
- ??= 逻辑空赋值运算 0 “”
感觉是可以填补 || 不能很好的判断"" 0
let message = "" |
Numeric Separator
Numeric 数值的 Separator 分离器
大的数值有一个连接符 _ ,便于阅读
const num = 10_000_000_000_000 |
String.replaceAll
字符串替换,替换所有匹配条件的地方
const res = 'aabbcc'.replaceAll('b', '.'); |
之前replace只换第一处匹配的地方
const res = 'aabbcc'.replace('b', '.'); |