九、ES6、ES6面对对象
续JS高级知识点最全梳理上篇链接
13、map、weakMap
新增的数据结构是Map,用于存储映射关系,事实上我们对象存储映射关系只能用字符串(ES6新增了Symbol)作为属性名(key);,某些情况下我们可能希望通过其他类型作为key(可以是对象或者其他)
- 常见方法
- size返回map元素的个数
- 常见属性
- get()根据key得到value
- set(“key”,“value”) 返回整个map对象
- has(key)是否包含某一个key 返回布尔值
- delete()根据key删除某个键值对,返回布尔值
- clear()清空map,没有返回值
- foreach for of
weakMap
- WeakMap也是不能遍历的p因为没有forEach方法,也不支持通过for of的方式进行遍历
- WeakMap的key只能使用对象,不接受其他的类型作为key;
- 区别二:WeakMap的key对对象想的引用是弱引用,如果没有其他引用引用这个对象,那么GC可以回收该对象;
14、ES7Array Includes
- 在ES7之前,如果我们想判断一个数组中是否包含某个元素,需要通过indexOf获取结果,并且判断是否为-1。
- 在ES7中,我们可以通过**includes(“元素”,判断的位置)**来判断一个数组中是否包含一个指定的元素,根据情况,如果包含则返回true,否则返回false。
15、ES7–指数(乘方)exponentiation运算符
- 在ES7之前,计算数字的乘方需要通过Math.pow(3,3)方法来完成 。3的三次方
- 在ES7中,增加了3** 3运算符,可以对数字来计算乘方。
16、ES8Object.values
Object.keys获取一个对象所有的key,在ES8中提供了Object.values来获取所有的value值
17、ES8Object.entries
通过Object.entries可以获取到一个数组,数组中会存放可枚举属性的键值对数组。不是对象的时候,是字符串或者数组,key值就是下标索引值
18、padStart和padEnd
- 某些字符串我们需要对其进行前后的填充,来实现某种格式化效果,ES8中增加了padStart和padEnd方法,分别是对字符串的首尾进行填充的。
- 简单具一个应用场景:比如需要对身份证、银行卡的前面位数进行隐藏:
19、ES10-flat flatMap(降维)
- flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
- flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。
- 注意一:flatMap是先进行map操作,再做flat的操作;
- 注意二:flatMap中的flat相当于深度为1;
20、ObjectfromEntries(Object.entries)
Object.entries的逆过程,将数组转换为字符串结合flatMap,可以更新为一个数组
21、ES10-trimStarttrimEnd
去除一个字符串首尾的空格,我们可以通过trim方法,ES10中给我们提供了trimStart和trimEnd;
22.ES11-BigInt
- 大于MAX_SAFE_INTEGER的数值,表示的可能是不正确的
- BitInt的表示方法是在数值的后面加上n
23、可选链Optional Chaining
可选链也是ES11中新增一个特性,主要作用是让我们的代码在进行null和undefined判断时更加清晰和简洁:防止操作的属性或者方法不存在,就不会向下继续执行,在操作之后添加?号
24、ES11-GlobalThis
- 比如在浏览器中可以通过this、window来获取;-
- 比如在Node中我们需要通过global来获取
- ES11中对获取全局对象进行了统一的规范:globalThis
25、FinalizationRegistry
FinalizationRegistry对象可以让你在对象被垃圾回收时请求一个回调
你可以通过调用register方法,注册任何你想要清理回调的对象,传入该对象和所含的值;
26、WeakRefs
默认将一个对象赋值给另外一个引用,那么这个引用是一个强引用:p如果我们希望是一个弱引用的话,可以使用WeakRef;
十、proxy-reflect
前言:
Object.defineProperty的存储属性描述符来对属性的操作进行监听。
但是Object.defineProperty设计的初衷,不是为了去监听截止一个对象中所有的属性的。我们在定义某些属性的时候,初衷其实是定义普通的属性
其次,如果我们想监听更加丰富的操作,比如新增属性、删除属性,那么Object.defineProperty是无能为力的。
proxy:ES6中,新增了一个Proxy类
- 希望监听一个对象的相关操作,那么我们可以先创建一个代理对象(Proxy对象);
- 之后对该对象的所有操作,都通过代理对象来完成,代理对象可以监听我们想要对原对象进行哪些操作
- 首先,我们需要new Proxy对象,并且传入需要侦听的对象以及一个处理对象,可以称之为handler;
üconst p = new Proxy(target, handler) - 之后的操作都是直接对Proxy的操作,而不是原有的对象,因为我们需要在handler里面进行侦听;
proxy的捕获器
常用的proxy的捕获器为:
let obj = {
name:"haha",
age:"18"
}
// 创建代理.proxy(代理对象,{处理对象handler})
const objProxy = new Proxy(obj,{
// 获取值的捕获器
get:function(target,key){ //target 目标对象(侦听的对象),key将被设置的属性key,receiver调用的代理对象
console.log("get捕获器",key);
return target[key]
},
// 设置值的捕获器
set:function(target,key,value){ //target 目标对象(侦听的对象),key将被设置的属性key,value新属性值,receiver调用的代理对象
console.log("set捕获器",key);
target[key] = value
},
// 监听in的捕获器
has:function(target,key){
console.log("has捕获器",key);
return key in target
},
// 监听delete的捕获器
deleteProperty:function(target,key){
console.log(`监听到属性${key}属性删除操作`);
delete target[key]
}
})
// 1.获取
console.log(objProxy.name);
// 2.设置
objProxy.name = "xixi"
console.log(objProxy.name);
// 3.in存在
console.log("name" in objProxy); //返回布尔值
// 4.删除
delete objProxy.name
proxy的constructor捕获器和apply是运用与函数的
reflect
Reflect也是ES6新增的一个API,它是一个对象,字面的意思是反射。
- 早期的ECMA规范中没有考虑到这种对对象本身的操作如何设计会更加规范,所以将这些API放到了Object上面
- Object作为一个构造函数,这些操作实际上放到它身上并不合适
- 另外还包含一些类似于in、delete操作符,让JS看起来是会有一些奇怪的
- 所以在ES6中新增了Reflect,让我们这些操作都集中到了Reflect对象上
- 但是reflect和object中的API并不完全相同
reflect常用的方法
reflect可以将之前对对象的操作都修改为reflect操作,从而真正的不对原对象进行操作
// 创建代理.proxy(代理对象,{处理对象handler})
const objProxy = new Proxy(obj,{
// 获取值的捕获器
get:function(target,key){ //target 目标对象(侦听的对象),key将被设置的属性key,receiver调用的代理对象
console.log("get捕获器",key);
return Reflect.get(target,key)
},
// 设置值的捕获器
set:function(target,key,value){ //target 目标对象(侦听的对象),key将被设置的属性key,value新属性值,receiver调用的代理对象
console.log("set捕获器",key);
return Reflect.set(target,key,value)
},
// 监听in的捕获器
has:function(target,key){
console.log("has捕获器",key);
return Reflect.has(target,key)
},
// 监听delete的捕获器
deleteProperty:function(target,key){
console.log(`监听到属性${key}属性删除操作`);
delete Reflect.defineProperty(target,key)
}
})
receiver
源对象(obj)有setter、getter的访问器属性,那么可以通过receiver来改变里面的this,receiver就可以将this值绑定为为代理对象,,receiver也就是创建出来的代理对象
Reflect的construct
十一、响应式
响应式:初始化了一个值,当有一段代码使用了这个值,那么当这个值发生改变的时候,这段代码会重新执行。可以自动响应数据变量的代码机制,我们就称之为是响应式的。
响应式代码封装
- 响应式函数的实现watchFn:封装一个新的函数watchFn;凡是传入到watchFn的函数,就是需要响应式的;其他默认定义的函数都是不需要响应式的;
- 响应式依赖的收集:所以我们要设计一个类,这个类用于管理某一个对象的某一个属性的所有响应式函数:相当于替代了原来的简单reactiveFns的数组;
- 监听对象的变化:方式一:通过Object.defineProperty的方式(vue2采用的方式);方式二:通过new Proxy的方式(vue3采用的方式);
十二、promise
Promise是一个类
promise创建方式:
// 创建方式1
const promise = new Promise((resolve,reject)=>{
})
// promise的回调
promise.then((value)=>{},(err)=>{})
// 创建方式2
new promise((resolve,reject)=>{
}).then((value)=>{}).catch((err)=>{})
promise在使用过程中的三个状态
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝;
- 已兑现(fulfilled): 意味着操作成功完成;ü执行了resolve时,处于该状态;
- 已拒绝(rejected): 意味着操作失败;ü执行了reject时,处于该状态;
Executor是在创建Promise时需要传入的一个回调函数,这个回调函数会被立即执行,并且传入两个参数
通常我们会在Executor中确定我们的Promise状态:p通过resolve,可以兑现(fulfilled)Promise的状态,我们也可以称之为已决议(resolved);p通过reject,可以拒绝(reject)Promise的状态;
一旦状态被确定下来,Promise的状态会被锁死,该Promise的状态是不可更改的
resolve不同值的区别
- 如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数
- 如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态
- 如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据then方法的结果来决定Promise的状态