es6——Reflect

  1. 将 Object 对象的一些明显属于语言内部的方法(如 Object.defineProperty)放到 Reflect 对象上,现阶段,某些方法同时在 Object 和 Reflect 对象上部署,未来的新方法将只在 Reflect 对象上部署。也就是说,从 Reflect 对象上可以获得语言内部的方法
  2. 修改某些 Object 方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj,name,desc) 在无法定义属性时会抛出一个错误,而 Reflect.defineProperty(obj,name,desc) 则返回 false
// 旧写法
try {
  Object.defineProperty(target, property, attributes)
  // success
} catch (e) {
  // failure
}

// 新写法
if (Reflect.defineProperty(target, property, attributes)) {
  // success
} else {
  // failure
}
  1. 让 Object 操作都变成函数行为。某些 Object 操作是命令式,比如 name in objdelete obj[name],而 Reflect.has(obj,name)Reflect.deleteProperty(obj,name) 让它们变成了函数行为
// 旧写法
'assign' in Object// true

// 新写法
Reflect.has(Object,'assign')// true
  1. Reflect 对象的方法与 Proxy 对象的方法对应,只要是 Proxy 对象的方法,就能在 Reflect 对象上找到对应的方法。这就使得 Proxy 对象可以方便地调用对应的 Reflect 方法来完成默认行为,作为修改行为的基础。也就是说,无论 Proxy 怎么修改默认行为,我们总可以在 Reflect 上获取默认行为
// Proxy 对象拦截 target 对象的属性赋值行为。
// 它采用 Reflect.set 方法将值赋给对象的属性
// 确保完成原有行为,然后再部署额外的功能
Proxy(target, {
  set (target, name, value, receiver) {
    let success = Reflect.set(targe, name, value, receiver)
    if (success) {
      console.log(`property ${name} on ${target} set to ${value}`)
    }
    return success
  },
})
  1. 有了 Reflect 对象以后,很多操作会更易读懂
// 旧写法
console.log(Function.prototype.apply.call(Math.floor, undefined, [1.67]))// 1

// 新写法
console.log(Reflect.apply(Math.floor, undefined, [1.67]))// 1

静态方法

下面的这些方法的作用大部分与 Object 对象的同名方法的作用是相同的,而且与 Proxy 对象的方法是对应的

 Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)

实例

Reflect.get(target, name, receiver)

get 方法查找并返回 target 对象的 name 属性,如果没有该属性,则返回 undefined

let myObject = {
  foo: 1,
  bar: 2,
  get baz () {
    return this.foo + this.bar
  },
}

let [a, b, c, d] = [
  Reflect.get(myObject, 'foo'),// 1
  Reflect.get(myObject, 'bar'),// 2
  Reflect.get(myObject, 'baz'),// 3
  Reflect.get(myObject, 'lucy'),// undefined
]

console.log(a, b, c, d)

如果 name 属性部署了读取函数(getter),则读取函数的 this 绑定 receiver

let myObject = {
  foo: 1,
  bar: 2,
  get baz () {
    return this.foo + this.bar
  },
}

let myReceiverObject = {
  foo: 4,
  bar: 3,
}

console.log(Reflect.get(myObject, 'baz', myReceiverObject))// 7

Reflect.set(target, name, value, receiver)

set 方法设置 target 对象的 name 属性等于 value

let myObject = {
  foo: 1,
  set bar (value) {
    return this.foo = value
  },
}

console.log(myObject.foo)// 1

Reflect.set(myObject, 'foo', 2)
console.log(myObject.foo)// 2

Reflect.set(myObject, 'bar', 3)
console.log(myObject.foo)// 3

Reflect.set(myObject, 'baz', 4)// 无效
console.log(myObject.foo)// 3

如果 name 属性设置了赋值函数(setter),则赋值函数的 this 绑定 receiver

let myObject = {
  foo: 1,
  set bar (value) {
    return this.foo = value
  },
}

let myReceiverObject = {
  foo: 2,
}

Reflect.set(myObject, 'bar', 3, myReceiverObject)

console.log(myObject.foo)// 1
console.log(myReceiverObject.foo)// 3

注意:Reflect.set 会触发 Proxy.defineProperty 拦截

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
defineProperty
'set' on proxy: trap returned falsish for property 'a'
*/

上面代码中,Proxy.set 拦截使用了 Reflect.set,导致触发了 Proxy.defineProperty 拦截

let p = {
  a: 'a',
}

let handler = {
  set (target, key, value, receiver) {
    console.log('set')
    return Reflect.set(target, key, value, receiver)
  },
}

let obj = new Proxy(p, handler)
obj.a = 'A'
console.log(obj.a)// A

Reflect.has(obj, name)

has 方法对应 name in obj 中的 in 运算符

let myObject = {
  foo: 1,
}

// 旧写法
console.log('foo' in myObject)// true

// 新写法
console.log(Reflect.has(myObject, 'foo'))// true

Reflect.deleteProperty(obj, name)

deleteProperty 方法等同于 delete obj[name] ,用于删除对象的属性

const myObj = { foo: 'bar' }

// 旧写法
delete myObj.foo

// 新写法
Reflect.deleteProperty(myObj, 'foo')

该方法返回的一个布尔值,如果删除成功或者被删除的属性不存在,就返回 true;如果删除失败或者被删除的属性依然存在,则返回 false

Reflect.construct(target, args)

construct 方法等同于 new target(...args) ,提供了一种不适用 new 来调用构造函数的方法

class Greenting {
  constructor (name) {
    this.name = name
  }

  greenting () {
    console.log(`hello ${this.name}`)
  }
}

// new 写法
const instance1 = new Greenting('lucy1')

// Reflect.construct 写法
const instance2 = Reflect.construct(Greenting, ['lucy2'])

instance1.greenting()// hello lucy1
instance2.greenting()// hello lucy2

Reflect.getPrototypeOf(obj)

getPrototypeOf 方法用于读取对象的 __proto__ 属性,对应 Object.getPrototypeOf(obj)

const myObj = new FancyThing()

// 旧写法
console.log(Object.getPrototypeOf(myObj) === FancyThing.prototype)

// 新写法
console.log(Reflect.getPrototypeOf(myObj) === FancyThing.prototype)

Object.getPrototypeOf(obj) 的区别:如果参数不为对象会报错,而 Object 会将其转换为对象,如果参数为 undefined 或 null,则两个都会报错

console.log(Object.getPrototypeOf(1))// Number {0, constructor: ƒ, toExponential: ƒ, toFixed: ƒ, toPrecision: ƒ, …}
console.log(Reflect.getPrototypeOf(1))// 报错

Reflect.setPrototypeOf(obj, newProto)

setPrototypeOf 方法用于设置对象的 __proto__ 属性,返回第一个参数对象,对应 Object.setPrototypeOf(obj, newProto)

const myObj = new FancyThing()

// 旧写法
Object.setPrototypeOf(myObj, OtherThing.prototype)

// 新写法
Reflect.setPrototypeOf(myObj, OtherThing.prototype)

如果第一个参数不是对象,Object.setPrototypeOf 会返回第一个参数本身,而 Reflect.setPrototyepOf 会报错,如果第一个参数是 undefined 或 null,都报错

console.log(Object.setPrototypeOf(1, {}))// 1
console.log(Reflect.setPrototypeOf(1, {}))// 报错

Reflect.apply(func, thisArg, args)

apply 方法等同于 Function.prototype.apply.call(func, thisArg),用于绑定 this 对象后执行给指定函数
一般来说,如果要绑定一个函数的 this 对象,可以写成 fn.apply(obj, args) 的形式,但是如果函数定义了自己的 apply 方法,那么只能写成 Function.prototype.apply.call(fn, obj, args) 的形式,采用 Reflect 对象可以简化这种操作

const ages = [55, 22, 99, 66, 77, 33, 88, 11, 44]

// 旧写法
const youngest = Math.min.apply(Math, ages)
const oldest = Math.max.apply(Math, ages)
const type = Object.prototype.toString.call(youngest)

// 新写法
const youngest = Math.min.apply(Math, ages)
const oldest = Math.max.apply(Math, ages)
const type = Reflect.apply(Object.prototype.toString, youngest, [])

Reflect.defineProperty(target, propertyKey, attributes)

Reflect.defineProperty 方法基本等同于 Object.defineProperty ,用来为对象定义属性。今后,后者会被逐渐废除,因此从现在开始请使用 Reflect.defineProperty 来代替它

let myDate = {}

// 旧写法
Object.defineProperty(myDate, 'now', {
  get: function () {
    return Date.now()
  },
})

// 新写法
Reflect.defineProperty(myDate, 'time', {
  value: () => Date.now(),
})

console.log(myDate.now)// 1557818029893
console.log(myDate)// {time: ƒ}

使用 Proxy 和 Reflect 实现观察者模式

观察者模式(Observer mode)指的是函数自动观察数据对象的模式,一旦对象有变化,函数就会自动执行

const queuedObservers = new Set()

const observe = fn => queuedObservers.add(fn)
// observable 函数返回一个原始对象的 Proxy 代理,拦截赋值操作,触发充当观察者的各个函数
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
}

// 执行
const person = observable({
  name: 'bob',
  age: 18,
})

function print () {
  console.log(`${person.name}, ${person.age}`)
}

observe(print)

// 这里值一修改,便会跟踪打印
person.name = 'lucy'// lucy, 18

定义一个 Set 集合,所有观察者函数都放进这个集合中。然后,observable 函数返回原始对象的代理,拦截赋值操作。拦截函数 set 会自动执行所有观察者

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值