# ES6 Reflect
# 前言
此文总结了Reflect
对象的部分语法,对比了与Object
方法的差异性,希望对你有用。
# 语法
;Reflect
与Math
类似,都是JavaScript
内置对象,提供了工具方法。
typeof Reflect // object
# get
;Reflect.get(target, property, receiver) (opens new window) 用于读取对象属性,其中target
为目标对象,property
为属性名称。
var object = { x: 1 }
Reflect.get(object, 'x') // 1
读取目标对象的访问器属性时,访问器getter
内this
上下文就是参数receiver
。未指定参数receiver
,默认为目标对象。
var object = {
y: 1,
get x() {
return this
},
}
var receiver = {}
Reflect.get(object, 'x') === object // true
Reflect.get(object, 'x', receiver) === receiver // true
# set
;Reflect.set(target, property, value, receiver) (opens new window) 用于设置对象属性,其中target
为目标对象,property
为属性名称,value
为属性值。
var object = { x: 1 }
Reflect.set(object, 'x', 2)
object // {x: 2}
类似的,访问器setter
内this
上下文就是参数receiver
,默认为目标对象。
var object = {
y: 1,
set x(v) {
this.y = v
},
}
var receiver = {}
Reflect.set(object, 'x', 2)
object // {y: 2}
Reflect.set(object, 'x', 3, receiver)
receiver // {y: 3}
# has
;Reflect.has(object, property) (opens new window) 判断对象是否有此属性,本质上与in
操作符功能相同。
var object = { x: undefined }
Reflect.has(object, 'x') // true
# deleteProperty
;Reflect.deleteProperty(target, property) (opens new window) 用于删除对象属性,本质上与delete
操作符功能相同。
var object = { x: 1 }
Reflect.deleteProperty(object, 'x')
object // {}
# ownKeys
;Reflect.ownKeys(target) (opens new window) 返回对象自身所有属性,等价于Object.getOwnPropertyNames(target)
与Object.getOwnPropertySymbols(target)
之和。
var object = { x: 1, [Symbol('y')]: 2 }
Object.defineProperty(object, 'z', {
value: 3,
enumerable: false,
})
Reflect.ownKeys(object) // ['x', 'z', Symbol(y)]
# getOwnPropertyDescriptor
;Reflect.getOwnPropertyDescriptor(target, property) (opens new window) 用于获取对象属性描述符。
var object = { x: 1 }
Reflect.getOwnPropertyDescriptor(object, 'x')
// {
// configurable: true,
// enumerable: true,
// value: 1,
// writable: true,
// }
与Object.getOwnPropertyDescriptor
不同之处在于,target
为非对象时,Object
版本静默失败并返回undefined
。而Reflect
版本则抛出错误,提示开发者注意参数类型。
Object.getOwnPropertyDescriptor(1, 'x')
// undefined
Reflect.getOwnPropertyDescriptor(1, 'x')
// Uncaught TypeError: Reflect.getOwnPropertyDescriptor called on non-object
# defineProperty
;Reflect.defineProperty(target, property, descriptor) (opens new window) 用于定义对象属性,其中target
为目标对象,value
为属性名称,descriptor
为属性描述符。
var object = {}
Reflect.defineProperty(object, 'x', { value: 1 })
Reflect.getOwnPropertyDescriptor(object, 'x')
// {
// configurable: false,
// enumerable: false,
// value: 1,
// writable: false,
// }
若属性定义失败,Object
版本将抛出错误,而Reflect
版本将返回false
。
var object = Object.freeze({})
Reflect.defineProperty(object, 'x', { value: 1 })
// false
Object.defineProperty(object, 'x', { value: 1 })
// Uncaught TypeError: Cannot define property x, object is not extensible
# preventExtensions
;Reflect.preventExtensions(target) (opens new window) 阻止对象拓展。
var object = {}
Reflect.preventExtensions(object)
Reflect.isExtensible(object) // false
类似的,target
为非对象时,Object
版本静默失败,而Reflect
版本将抛出错误。
Object.preventExtensions(1)
// 1
Reflect.preventExtensions(1)
// Uncaught TypeError: Reflect.preventExtensions called on non-object
# isExtensible
;Reflect.isExtensible(target) (opens new window) 判断对象是否可拓展。
var object = {}
Reflect.preventExtensions(object)
Reflect.isExtensible(object) // false
若参数为非对象,Reflect
版本将抛出错误,而Object
版本则静默失败并返回false
。不合理之处在于参数为非对象,讨论是否可拓展并没有任何意义。
Reflect.isExtensible(1)
// Uncaught TypeError: Reflect.isExtensible called on non-object
Object.isExtensible(1)
// false
# getPrototypeOf
;Reflect.getPrototypeOf(target) (opens new window) 获取对象原型。
Reflect.getPrototypeOf({}) === Object.prototype // true
参数target
为非对象时,Object
版本存在类型转换,而Reflect
版本将抛出错误。
Object.getPrototypeOf(1) === Number.prototype
// true
Reflect.getPrototypeOf(1)
// Uncaught TypeError: Reflect.getPrototypeOf called on non-object
# setPrototypeOf
;Reflect.setPrototypeOf(target, prototype) (opens new window) 用于设置原型,返回值为布尔值。
var object = {}
Reflect.setPrototypeOf(object, null)
Reflect.getPrototypeOf(object) // null
类似的,参数target
为非对象时,Object
版本静默失败并返回target
,而Reflect
版本将抛出错误。
Object.setPrototypeOf(1, null)
// 1
Reflect.setPrototypeOf(1, null)
// Uncaught TypeError: Reflect.setPrototypeOf called on non-object
# apply
;Reflect.apply(target, thisArg, args) (opens new window) 用于调用函数,其中target
为目标函数,thisArg
为函数被调用时的上下文对象this
,args
为函数参数。
function fn(x, y) {
return this.v + x + y
}
Reflect.apply(fn, { v: 1 }, [2, 3]) // 6
若函数apply
属性被占用,运行apply
方法绑定this
将抛出错误。
function fn(x, y) { return x + y }
fn.apply = 1
fn.apply(null, [3, 4])
// Uncaught TypeError: fn.apply is not a function
替换为原型apply
方法可规避,但语义不明显。
Function.prototype.apply.call(fn, null, [3, 4]) // 7
而Reflect.apply
执行方式则更简洁清晰。
Reflect.apply(fn, null, [3, 4]) // 7
# construct
;Reflect.construct(target, args, newTarget) (opens new window) 与new
操作符行为类似,其中target
为构造函数,args
为函数参数。
function F(x, y) {
this.x = x
this.y = y
}
Reflect.construct(F, [1, 2]) // F {x: 1, y: 2}
参数newTarget
有两个用处,第一个是指定新对象的原型为newTarget
的原型对象。
function F() {}
function NT() {}
var object = Reflect.construct(F, [], NT)
Reflect.getPrototypeOf(object) === NT.prototype // true
除此之外,原构造函数内部new.target
会被指向newTarget
函数。
function F() {
console.log(new.target === NT) // true
}
function NT() {}
Reflect.construct(F, [], NT)
# 小结
;Reflect
对象的设计目的主要包括。
- 语言内部的元编程行为,统一移动至
Reflect
,未来新的元编程行为将只添加到Reflect
Object
部分函数的行为不合理,在Reflect
版本进行修正- 符合函数式编程,语义更清晰
Proxy
与Reflect
结合在代理同时还能保持默认行为
# 🎉 写在最后
🍻伙伴们,如果你已经看到了这里,觉得这篇文章有帮助到你的话不妨点赞👍或 Star (opens new window) ✨支持一下哦!
手动码字,如有错误,欢迎在评论区指正💬~
你的支持就是我更新的最大动力💪~
GitHub (opens new window) / Gitee (opens new window)、GitHub Pages (opens new window)、掘金 (opens new window)、CSDN (opens new window) 同步更新,欢迎关注😉~