Appearance
Reflect
Reflect对象设计目的如下
- 将
Object对象属于语言内部的方法(),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。从Reflect对象上可以拿到语言内部的方法
比如Object.defineProperty。
- 修改某些
Object方法的返回结果,让其变得更合理。
比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false
js
// 老写法
try {
Object.defineProperty(target, property, attributes)
// success
} catch (e) {
// failure
}
// 新写法
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}- 让
Object操作都变成函数行为,某些Object操作是命令式。比如name in obj和delete obj[name]
js
// 老写法
'assign' in Object // true
// 新写法
Reflect.has(Object, 'assign') // trueReflect对象的方法与Proxy对象的方法一一对应。不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
Proxy方法拦截target对象属性赋值行为。采用Reflect.set方法将值赋给对象属性,确保默认行为,再部署额外功能
js
Proxy(target, {
set: function (target, name, value, receiver) {
var success = Reflect.set(target, name, value, receiver)
if (success) {
console.log('property ' + name + ' on ' + target + ' set to ' + value)
}
return success
}
})Reflect对象,使操作更易读
js
// 老写法
Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1
// 新写法
Reflect.apply(Math.floor, undefined, [1.75]) // 1静态方法
Reflect对象一共有 13 个静态方法,与proxy一一对应
Reflect.get
Reflect.get(target, name, receiver):查找并返回target对象的name属性。没有属性,返回undefined
注意事项
- 属性部署了读取函数(getter),读取函数
this绑定receiver
js
var myObject = {
foo: 1,
bar: 2,
get baz() {
return this.foo + this.bar
}
}
var myReceiverObject = {
foo: 4,
bar: 4
}
Reflect.get(myObject, 'baz', myReceiverObject) // 8- 第一个参数不是对象,
Reflect.get方法报错
js
Reflect.get(1, 'foo') // 报错
Reflect.get(false, 'foo') // 报错Reflect.set
Reflect.set(target, name, value, receiver):设置target对象的name属性等于value
注意事项
- 属性部署了赋值函数(setter),赋值函数
this绑定receiver
js
var myObject = {
foo: 4,
set bar(value) {
return (this.foo = value)
}
}
var myReceiverObject = {
foo: 0
}
Reflect.set(myObject, 'bar', 1, myReceiverObject)
myObject.foo // 4
myReceiverObject.foo // 1第一个参数不是对象,
Reflect.get方法报错Proxy 和 Reflect 联合使用,前者拦截赋值,后者完成赋值默认行为
receiver默认指向当前Proxy实例(obj)- 传入
receiver,赋值函数会将属性赋值到recevier上(也就是obj)。导致触发defineProperty拦截。不传入,不会触发。
js
let p = {
a: 'a'
}
let handler = {
set(target, key, value, receiver) {
console.log('set')
Reflect.set(target, key, value, receiver)
},
defineProperty(target, key, attribute) {
console.log('defineProperty')
Reflect.defineProperty(target, key, attribute)
}
}
let obj = new Proxy(p, handler)
obj.a = 'A'
// set
// definePropertyReflect.has
Reflect.has(target, name):对应name in obj里面的in运算符
js
// 旧写法
'foo' in myObject // true
// 新写法
Reflect.has(myObject, 'foo') // true第一参数不是对象,报错
Relect.deleteProperty
Reflect.deleteProperty(target, name):对应delete obj[name],用于删除对象的属性。返回一个布尔值,删除失败,属性依然存在,返回false
js
// 旧写法
delete myObj.foo
// 新写法
Reflect.deleteProperty(myObj, 'foo')第一参数不是对象,报错
Reflect.construct
Reflect.construct(target, args):对应new target(...args),一种不使用new,来调用构造函数的方法
js
// new 的写法
const instance = new Greeting('张三')
// Reflect.construct 的写法
const instance = Reflect.construct(Greeting, ['张三'])第一参数不是函数,报错
Reflect.getPrototypeOf
Reflect.getPrototypeOf(target):对应Object.getPrototypeOf(obj),读取对象的__proto__属性
Object.getPrototypeOf:参数不为对象,转为对象运行
js
// 旧写法
Object.getPrototypeOf(myObj) === FancyThing.prototype
// 新写法
Reflect.getPrototypeOf(myObj) === FancyThing.prototype参数不为对象,报错
Reflect.setPrototypeOf
Reflect.setPrototypeOf(target, prototype):对应Object.setPrototypeOf(obj, newProto),设置目标对象的原型(prototype),返回布尔值,表示是否设置成功
js
const myObj = {}
// 旧写法
Object.setPrototypeOf(myObj, Array.prototype)
// 新写法
Reflect.setPrototypeOf(myObj, Array.prototype)
myObj.length // 0注意事项
- 无法设置目标对象的原型(比如,目标对象禁止扩展),返回 false
js
Reflect.setPrototypeOf({}, null)
// true
Reflect.setPrototypeOf(Object.freeze({}), null)
// false- 第一参数不是对象,
Object.setPrototypeOf会返回第一个参数本身,而Reflect.setPrototypeOf会报错
js
Object.setPrototypeOf(1, {})
// 1
Reflect.setPrototypeOf(1, {})
// TypeError: Reflect.setPrototypeOf called on non-objectundefined和null,Object.setPrototypeOf和Reflect.setPrototypeOf均会报错(第一参数)
js
Object.setPrototypeOf(null, {})
// TypeError: Object.setPrototypeOf called on null or undefined
Reflect.setPrototypeOf(null, {})
// TypeError: Reflect.setPrototypeOf called on non-objectReflect.apply
Reflect.apply(target, thisArg, args):对应Function.prototype.apply.call(func, thisArg, args),用于绑定this对象后执行给定函数
绑定函数this对象
js
fn.apply(obj, args)
// 函数本身定义了apply
Function.prototype.apply.call(fn, obj, args)
Reflect.apply(fn, obj, args)js
const ages = [11, 33, 12, 54, 18, 96]
// 旧写法
const youngest = Math.min.apply(Math, ages)
const oldest = Math.max.apply(Math, ages)
const type = Object.prototype.toString.call(youngest) // "[object Number]"
// 新写法
const youngest = Reflect.apply(Math.min, Math, ages)
const oldest = Reflect.apply(Math.max, Math, ages)
const type = Reflect.apply(Object.prototype.toString, youngest, [])Reflect.defineProperty
Reflect.defineProperty(target, name, desc):对应Object.defineProperty,用来为对象定义属性
js
// 旧写法
Object.defineProperty(MyDate, 'now', {
value: () => Date.now()
})
// 新写法
Reflect.defineProperty(MyDate, 'now', {
value: () => Date.now()
})搭配 Proxy.defineProperty 使用
js
const p = new Proxy(
{},
{
defineProperty(target, prop, descriptor) {
console.log(descriptor)
return Reflect.defineProperty(target, prop, descriptor)
}
}
)
p.foo = 'bar'
// {value: "bar", writable: true, enumerable: true, configurable: true}
p.foo // "bar"第一参数不是对象会报错
Reflect.getOwnPropertyDescriptor
Reflect.getOwnPropertyDescriptor(target, name):对应Object.getOwnPropertyDescriptor,用于得到指定属性的描述对象
js
var myObject = {}
Object.defineProperty(myObject, 'hidden', {
value: true,
enumerable: false
})
// 旧写法
var theDescriptor = Object.getOwnPropertyDescriptor(myObject, 'hidden')
// 新写法
var theDescriptor = Reflect.getOwnPropertyDescriptor(myObject, 'hidden')Object.getOwnPropertyDescriptor 和 Reflect.getOwnPropertyDescriptor 区别
Object 第一参数不是对象不报错,Reflect 第一参数不是对象,会报错。
Reflect.isExtensible
Reflect.isExtensible(target):对应Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展
js
// 旧写法
Object.isExtensible(myObject) // true
// 新写法
Reflect.isExtensible(myObject) // trueObject.isExtensible 和 Reflect.isExtensible 区别
Object.isExtensible参数不为对象,返回false,Reflect.isExtensible直接报错
Reflect.preventExtensions
Reflect.preventExtensions(target):对应Object.preventExtensions方法,让对象变为不可扩展。它返回一个布尔值,表示是否操作成功
区别
Object.preventExtensions参数不是对象,ES5报错,ES6返回传入参数Reflect.preventExtensions会报错
js
// 旧写法
Object.preventExtensions(myObject) // Object {}
// 新写法
Reflect.preventExtensions(myObject) // trueReflect.ownKeys
Reflect.ownKeys(target):返回对象的所有属性。等同Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和
第一参数不是对象,报错
实现观察者模式
观察者模式(Observer mode):指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行
js
const person = observable({
name: '张三',
age: 20
})
function print() {
console.log(`${person.name}, ${person.age}`)
}
observe(print) // 将print加入观察者函数队列
person.name = '李四'
// 李四, 20js
const queuedObservers = new Set()
const observe = (fn) => queuedObservers.add(fn) // 观察者函数
const observable = (obj) => new Proxy(obj, { set }) // 观察者对象
function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver)
queuedObservers.forEach((observer) => observer()) // 调用队列中函数
return result
}