ES6 学习笔记 4 完结 --- Reflect, Proxy, Generator, Iterator
ES6(2015)
反射 Reflect
调用方法 .apply()
// ES5
Math.floor.apply(null,[3.7]) // 3
// ES6
Reflect.apply(Math.floor,null,[3.7])
作用: 可以将方法当做参数,根据实际情况变化方法名
// ES5
let price = 91.5
if(price > 100){
price = Math.floor.apply(null,[price])
}else {
price = Math.ceil.apply(null,[price])
}
// ES6
Reflect.apply(price >100 ? Math.floor : Math.ceil,null,[price])
实例化类 .construct()
实例化对象 .construct()
// ES5
let d = new Date()
// ES6
let d = Reflect.construct(Date,[]) // 无参使用 空数组
实例对象的方法 .defineProperty() & .deleteProperty()
// 定义属性
const student = {}
const o = Object.defineProperty(student,'name',{value:'Mike'}) // {name: 'Mike'}
const r = Reflect.defineProperty(student,'name',{value:'Mike2'}) // true
// 删除属性
const obj = {x:1,y:2}
const o = Object.deleteProperty(obj,'x') // {y:2}
const r = Reflect.deleteProperty(obj,'x') // true
// 查看属性
const obj = {x:1,y:2}
const o = obj.x // 1
const r = Reflect.get(obj,'x') // 1
// 查看属性描述符
const r = Reflect.getOwnPropertyDescriptor(obj,'x') // writable
// 查看原型对象
const ge = Reflect.getPropertyOf(obj)
// 查看属性是否存在
const r = Reflect.has(obj,'x') // Reflect 特有
// 可扩展
const r = Reflect.isExtensible(obj)
// 冻结扩展性
const z = Object.freeze(obj)
const r = Relfect.preventExtensions(obj)
// 查看属性名
const r = Reflect.ownKeys(obj)
// set
Reflect.set(obj,'z',4)
// 修改原型对象
Reflect.setPrototypeOf(obj,String.prototype) // 将对象变成了 string
代理 Proxy
中介,保护原始信息 ,代替 Object.defineProperty()
let o = {
name : 'xm',
price: 190
}
window.addEventListener('error',(e)=>{
console.log(e.message)
report('./') // 统一监控的方法
},true)
validator = function (target,key,value){
if(Reflect.has(key)){
if(key === 'price'){
if(value >300){
throw new TypeError('price exceed 300')
}
}
target[key] = value
}else {
return false // 阻止写操作,只读
}
}
let d = new Proxy(0,{
get(target,key){
if(key === 'price'){
return target[key] + 20
}else {
return target[key] || ''
}
},
set:validator
})
console.log(d.price) // 210 经过代理改变了
let r = Proxy.revocable(o,{ // 可撤销代理
get(target,key){
if(key === 'price'){
return target[key] + 20
}else {
return target[key] || ''
}
}
})
let p = r.proxy.price // 相当于 d.price
console.log(p) // 读取了数值
setTimeout(()=>{
d.revoke() // 代理销毁
},1000)
作用:
- 保护原始信息,获取信息时,可以调整信息
- 阻止信息的修改
- 做校验,修改信息时,对超过值域的值进行阻断
- 监控,触发校验者的信息
发生器 Generator
暂停循环
function * loop (){
for (let i = 0 ; i < 3; i ++ ){
yield console.log(i)
}
}
const l = loop() // 此时一次值也没有
l.next() // 0
l.next() // 1
l.next() // 2
l.next() // 没了
// 每次 遇到 yield 就停
// 依靠next() 来执行每一次的循环
语法
用* 定义的方法, 每次遇到 yield 就会停止 等待指令, 直到 .next(val) 执行 ,会跳过一个yield ,并给 yield赋值,影响yield等号左侧的值.
function * gen(){
try {
let val
val = yield 1
console.log(val)
} catch (e){
console.log(e.message)
}
}
const l = gen()
const n1 = l.next() // 1 n1: {undefined,false}
const t1 = l.throw(new Error('ss')) // 使yield 异常
const r1 = l.return() // 提前结束
const n2 = l.next() // undefined n2: {undefined,true}
遍历器 Iterator
不可遍历对象
let a = {
b :{
c: [1,2,3,4,5],
d: [11,22,33,44,55,66],
e: [111,222,333,444]
},
kk:{},
zz:{}
}
// 将 c,d,e 中的数组 统一成一个数组
// 常规做法 耦合度不够
let r = []
for(let [k,v] of Object.entries(a.b)){
r = r.concat(v)
}
console.log(r) // 变成了新的数组
使用固定格式 给对象增加遍历器
// 理想做法
let r = []
for (let v of a ){
r.push(v)
}
// 于是 , 需要增加遍历器接口
// 入口this固定格式 可迭代协议
a[Symbal.iterator] = function(){
// 逻辑
let a = this.a
let keys = Reflect.ownKeys(a)
let values = []
// 出口固定格式 迭代器协议
return {
next(){
if(!value.length){
if(keys.length){
values = a[keys][0]
keys.shift()
}
}
done:!value.length,
value:values.shift()
}
}
}
使用Generator 给对象增加遍历器
// 上步可见,迭代器协议的格式 和 Generator 的 返回值格式 完全一样.其实,Generator 就是一个迭代器协议.
a[Symbol.iterator] = function * (){
let a = this.a
let keys = Reflet.ownKeys(a)
let values = []
while(1){
if(!values.length){
if(keys.length){
values = a[keys[0]]
keys.shift()
yield valuse.shift()
}else {
return false
}
}else {
yield values.shift()
}
}
}