1.Reflect
反射机制是指编译阶段不知道哪个类被加载,而是在运行阶段的时候才加载,执行。
1.1 Reflect.apply
传统做法
console.log(Math.floor.apply(null, [1.13])) // 1
Reflect
Reflect.apply(Math.floor, null, [1.73]) // 1
类似可以把很多方法都这么使用,比如Math.max等等
使用场景
let price = 101
Reflect.apply(price > 100 ? Math.floor : Math.ceil, null, [price])
ES5
let price = 101
if (price > 100) {
Math.floor.apply(null, [price])
} else {
Math.ceil.apply(null, [price])
}
1.2 Reflect.construct
function Person(name) {
this.name = name;
}
// new写法
let person = new Person('jack')
// Reflect
let nPerson = Reflect.construct(Person, ['jack'])
let d = Reflect.construct(Date, [])
console.log(d.getTime())
1.3 Reflect.defineProperty
Object.defineProperty 返回对象
let student = {}
console.log(Object.defineProperty(student, 'name', { value: 'Mike' })) // {name: "Mike"}
Reflect.defineProperty 返回true或false
let student = {}
console.log(Reflect.defineProperty(student, 'name', { value: 'Mike' })) // true
1.4 Reflect.deleteProperty
let student = {
name: 'jack',
age: 12
}
console.log(Reflect.deleteProperty(student, 'name')) // true
1.5 Reflect.isExtensible
Reflect.isExtensible (target) 对应Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展
const object1 = {};
console.log(Reflect.isExtensible(object1));
// expected output: true
Reflect.preventExtensions(object1);
console.log(Reflect.isExtensible(object1));
// expected output: false
const object2 = Object.seal({}); // 或者 Object.freeze() freeze不可修改属性 seal可修改密封属性
console.log(Reflect.isExtensible(object2));
// expected output: false
1.6 Reflect.getOwnPropertyDescriptor 获取属性描述符
Reflect.getOwnPropertyDescriptor({x: "hello"}, "x");
// {value: "hello", writable: true, enumerable: true, configurable: true}
Reflect.getOwnPropertyDescriptor({x: "hello"}, "y");
// undefined
Reflect.getOwnPropertyDescriptor([], "length");
// {value: 0, writable: true, enumerable: false, configurable: false}
1.7 Reflect.ownKeys
Reflect.ownKeys(obj) // ["x", "y"]
Reflect.ownKeys([]) // ["length"]
Reflect.ownKeys([1, 2, 3]) // ["0", "1", "2", "length"] 索引加length
1.8 Reflect.setPrototypeOf Reflect.getPrototypeOf
可以修改和获取目标的原型
let arr = []
Reflect.getPrototypeOf(arr)
Reflect.setPrototypeOf(arr, String.prototype) // 改成了字符串的原型
Reflect.getPrototypeOf(arr)
2. Proxy
2.1 使用方法
let o = {
name: '张三',
money: 190
}
let d = new Proxy(o, {
get (target, key) {
if (key === 'money') {
return target[key] + 20
} else {
return target[key]
}
}
})
console.log(d.money) // 210
2.2 使用场景
2.2.1 使对象变为只读
ES5
let o = {
x: 1,
y: 2
}
for (let [key] of Object.entries(o)) {
Object.defineProperty(o, key, {
writable: false
})
}
ES6 proxy
let o = {
x: 1,
y: 2
}
let d = new Proxy(o, {
get (target, key) {
return target[key]
},
set (target, key, value) {
return false
}
})
好处是不改变原对象,原对象仍然是可操作的
2.2.2 拦截无效操作
let o = {
x: 1,
y: 2
}
let validator = (target, key, value) => {
if (Reflect.has(target, key)) {
if (key === 'x') {
if (value > 300) { // x大于300就不能赋值
return false
} else {
target[key] = value
}
} else {
target[key] = value
}
} else {
return false
}
}
let d = new Proxy(o, {
get (target, key) {
return target[key]
},
set: validator
})
2.2.3 上报违规操作
window.addEventListener('error', (e) => {
// 不满足就触发上报异常机制
console.log(e)
}, true)
let o = {
x: 1,
y: 2
}
let validator = (target, key, value) => {
if (Reflect.has(target, key)) {
if (key === 'x') {
if (value > 300) {
throw new TypeError('x exceed 300') // 抛出异常
} else {
target[key] = value
}
} else {
target[key] = value
}
} else {
return false
}
}
let d = new Proxy(o, {
get (target, key) {
return target[key]
},
set: validator
})
2.2.4 生成一个组件 每个id不同且只读
class Component {
constructor () {
this.proxy = new Proxy({
id: Math.random().toString(16).slice(-8)
}, {})
}
get id () {
return this.proxy.id
}
}
let com = new Component()
let com2 = new Component()
for (let i = 0; i < 10; i++) {
console.log(com.id, com2.id)
}
2.3 撤销代理
let o = {
x: 1,
y: 2
}
let d = Proxy.revocable(o, {
get (target, key) {
return target[key]
}
})
// d不是单纯的代理数据,要通过proxy获取信息
console.log(d.proxy)
d.revoke() // 代理对象已经被撤销