Reflect
是一个内置的对象,它提供拦截 JavaScript 操作的方法,这些方法与 proxy handler 的方法相同。Reflect
不是一个函数对象,因此它是不可构造的,所以不能通过 new
运算符对其进行调用,或者将 Reflect
对象作为一个函数来调用。Reflect 的所有属性和方法都是静态的(就像 Math 对象)。
静态方法
Reflect.apply(target, thisArgument, argumentsList)
对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply()
功能类似。
静态方法 Reflect.apply()
通过指定的参数列表发起对目标 (target) 函数的调用。
console.log(Reflect.apply(Math.floor, undefined, [1.75]))
// 输出: 1
Reflect.construct(target, argumentsList[, newTarget])
对构造函数进行 new
操作,相当于执行 new target(...args)
。
function reflectConstructExample() {
const Person = function (name, age) {
this.name = name
this.age = age
}
const person = Reflect.construct(Person, ['John', 30])
console.log(person)
// 输出: Person { name: 'John', age: 30 }
}
参数
target
: 被运行的目标构造函数argumentsList
: 类数组,目标构造函数调用时的参数newTarget
(可选): 作为新创建对象的原型对象的constructor
属性,参考new.target
操作符,默认值为target
new.target
: 是一个元属性(meta property),在ECMAScript 2015 (ES6) 中引入,用于检测函数是否通过 new
关键字调用。简单来说,当一个函数用 new
关键字调用时,new.target
会指向这个函数本身;如果函数是直接调用,new.target
的值则为 undefined。
Reflect.construct() vs Object.create()
在新语法 Reflect出现之前,是通过明确指定构造函数和原型对象(使用Object.create()
)来创建一个对象的。
function reflectConstructExample2() {
const OneClass = function () {
this.name = 'oneClass'
}
const TwoClass = function () {
this.name = 'twoClass'
}
const obj = Reflect.construct(OneClass, [])
console.log(obj) // 输出: OneClass {name: 'oneClass'}
console.log(obj instanceof OneClass) // 输出: true
console.log(obj instanceof TwoClass) // 输出: false
// 原型指向 TwoClass.prototype
const obj1 = Reflect.construct(OneClass, [], TwoClass)
console.log(obj1) // 输出: TwoClass {name: 'oneClass'}
console.log(obj1 instanceof OneClass) // 输出: false
console.log(obj1 instanceof TwoClass) // 输出: true
//Reflect.construct之前的原型指向 TwoClass.prototype实现方法
const obj2 = Object.create(TwoClass.prototype) // object.create 创建一个新对象,原型指向 TwoClass.prototype
OneClass.call(obj2) // “借用” OneClass 的构造函数逻辑来初始化 obj2,对 OneClass 本身及其原型链无影响。
console.log(obj2) // 输出: TwoClass {name: 'oneClass'}
console.log(obj2 instanceof OneClass) // 输出: false
console.log(obj2 instanceof TwoClass) // 输出: true
}
虽然两种方式结果相同,但在创建对象过程中仍一点不同。
当使用
Object.create()
和Function.prototype.apply()
时,如果不使用new
操作符调用构造函数,构造函数内部的new.target
值会指向undefined
。当调用
Reflect.construct()
来创建对象,new.target
值会自动指定到target
(或者newTarget
,前提是newTarget
指定了)。
Reflect.defineProperty(target, propertyKey, attributes)
和 Object.defineProperty()
类似,如果设置成功就会返回 true
。
function reflectDefinePropertyExample() {
let obj = {}
Reflect.defineProperty(obj, 'name', {
value: 'kk'
})
console.log(obj.name) // 输出: kk
console.log(Object.getOwnPropertyDescriptor(obj, 'name'))
//输出:{value: 'kk', writable: false, enumerable: false, configurable: false}
}
检查属性是否被成功定义:
Object.defineProperty
方法,如果成功则返回一个对象,否则抛出一个 TypeError
。所以,当定义一个属性时,可以使用 try...catch
去捕获其中任何的错误。
Reflect.defineProperty
返回 Boolean
值作为成功的标识,所以使用 if...else
来判断结果。
if (Reflect.defineProperty(target, property, attributes)) {
// 成功
} else {
// 失败
}
Reflect.deleteProperty(target, propertyKey)
作为函数的delete
操作符,相当于执行 delete target[name]
。
function reflectDeletePropertyExample() {
let obj = {
name: 'kk',
age: 18
}
console.log(Reflect.deleteProperty(obj, 'name')) // 输出: true
console.log(obj) // 输出: { age: 18 }
// 尝试删除被冻结的属性会失败
Object.freeze(obj)
console.log(Reflect.deleteProperty(obj, 'age')) // 输出: false
// 尝试删除不存在的属性会返回 true
console.log(Reflect.deleteProperty(obj, 'number')) // 输出: true
var arr = [1, 2, 3, 4, 5]
Reflect.deleteProperty(arr, '3') // true
console.log(arr, arr.length) // 输出: [1, 2, 3, empty, 5] 5
}
上面当删除数组元素时,JavaScript 不会自动重新索引数组,而是将该位置标记为 “empty”(稀疏数组),数组长度保持为5,索引3的位置变成空位(empty)。
改进:
// 方案1:使用 splice 保持数组连续性
arr.splice(3, 1) // 输出: [1, 2, 3, 5]
// 方案2:使用 filter 创建新数组(不修改原数组)
const newArr = arr.filter((_, index) => index !== 3) // 输出: [1, 2, 3, 5]
// 方案3:显式设置为 undefined(保留位置)
Reflect.set(arr, 3, undefined) // 输出: [1, 2, 3, undefined, 5]
Reflect.get(target, propertyKey[, receiver])
获取对象身上某个属性的值,类似于 target[name]
。
function reflectGetExample() {
let obj = {
name: 'kk',
age: 18
}
console.log(Reflect.get(obj, 'name')) // 输出: kk
console.log(Reflect.get(obj, 'number')) // 输出: undefined
let arr = [1, 2]
console.log(Reflect.get(arr, 0)) // 输出: 1
console.log(Reflect.get(arr, 2)) // 输出: undefined
}
receiver
参数用于指定 getter 函数中的 this
上下文。
当目标属性是访问器属性(getter)时,receiver
会作为 getter 函数的 this
值。如果省略该参数,则默认使用目标对象本身作为 this
function reflectGetExample2() {
let obj = {
name: 'kk',
get greeting() {
return `Hello, ${this.name}!`
}
}
console.log(Reflect.get(obj, 'greeting')) // 输出: Hello, kk!
const receiver = { name: 'll' }
console.log(Reflect.get(obj, 'greeting', receiver)) // 输出: Hello, ll!
}
Reflect.getOwnPropertyDescriptor(target, propertyKey)
类似于 Object.getOwnPropertyDescriptor()
。如果对象中存在该属性,则返回对应的属性描述符,否则返回 undefined
。
function reflectGetOwnPropertyDescriptorExample() {
let obj = {
name: 'kk',
age: 18
}
console.log(Reflect.getOwnPropertyDescriptor(obj, 'name'))
// 输出: {value: 'kk', writable: true, enumerable: true, configurable: true}
console.log(Reflect.getOwnPropertyDescriptor(obj, 'number')) // 输出: undefined
console.log(Reflect.getOwnPropertyDescriptor([], 'length'))
// 输出: {value: 0, writable: true, enumerable: false, configurable: false}
}
- 如果该方法的第一个参数不是一个对象(一个原始值),那么将造成 TypeError 错误。
Object.getOwnPropertyDescriptor
,非对象的第一个参数将被强制转换为一个对象处理。// 尝试获取非对象的属性描述符 console.log(Object.getOwnPropertyDescriptor('a', '0')) //输出: {value: 'a', writable: false, enumerable: true, configurable: false} console.log(Reflect.getOwnPropertyDescriptor('a', '0')) // 输出报错: TypeError: Reflect.getOwnPropertyDescriptor called on non-object
Reflect.getPrototypeOf(target)
类似于 Object.getPrototypeOf()
。
function reflectGetPrototypeOfExample() {
const object1 = {
property1: 42
}
const proto1 = Reflect.getPrototypeOf(object1)
console.log(proto1)
// 输出: {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
console.log(Reflect.getPrototypeOf({}))
// 输出: {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
console.log(Reflect.getPrototypeOf(Reflect.getPrototypeOf({}))) // 输出: null
console.log(Reflect.getPrototypeOf(proto1)) // 输出: null
}
在 ES2015 规范下,Reflect 抛异常,Object 强制转换非 Object 类型
console.log(Object.getPrototypeOf('foo'))
// 输出: String {'', constructor: ƒ, anchor: ƒ, at: ƒ, big: ƒ, …}
console.log(Reflect.getPrototypeOf('foo'))
// 输出报错: TypeError: Reflect.getPrototypeOf called on non-object
Reflect.has(target, propertyKey)
判断一个对象是否存在某个属性,和 in
运算符 的功能完全相同。
function reflectHasExample() {
let obj = {
name: 'kk',
age: 18
}
console.log(Reflect.has(obj, 'name')) // 输出: true
console.log(Reflect.has(obj, 'number')) // 输出: false
console.log(Reflect.has([], 'length')) // 输出: true
// Reflect.has 可以用于检查数组的索引
console.log(Reflect.has([1, 2, 3], '0')) // 输出: true
console.log(Reflect.has([], '0')) // 输出: false
console.log(Reflect.has([0], '1')) // 输出: false
// Reflect.has 也可以用于检查 Symbol 属性
let sym = Symbol('test')
obj[sym] = 'symbol value'
console.log(Reflect.has(obj, sym)) // 输出: true
}
Reflect.isExtensible(target)
类似于 Object.isExtensible()
function reflectIsExtensibleExample() {
let obj = {}
console.log(Reflect.isExtensible(obj)) // 输出: true
Object.preventExtensions(obj) // 阻止扩展
console.log(Reflect.isExtensible(obj)) // 输出: false
let sealedObj = Object.seal({ name: 'kk' })
console.log(Reflect.isExtensible(sealedObj)) // 输出: false
let frozenObj = Object.freeze({ age: 18 })
console.log(Reflect.isExtensible(frozenObj)) // 输出: false
// Reflect.isExtensible 也可以用于检查数组
let arr = [1, 2, 3]
console.log(Reflect.isExtensible(arr)) // 输出: true
Object.preventExtensions(arr) // 阻止扩展
console.log(Reflect.isExtensible(arr)) // 输出: false
// 尝试在不可扩展的字符串上使用 Reflect.isExtensible
console.log(Reflect.isExtensible('hello'))
// 输出报错: TypeError: Reflect.isExtensible called on non-object
}
Reflect.ownKeys(target)
返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys()
, 但不会受enumerable
影响)。它的返回值等同于Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
。
function reflectOwnKeysExample() {
let obj = {
[Symbol.for('comet')]: 'comet',
name: 'kk',
age: 18,
773: 773,
0: 0,
'-1': '-1',
[Symbol.for('meteor')]: 'meteor'
}
console.log(Reflect.ownKeys(obj))
// 输出: ['0', '773', 'name', 'age', '-1', Symbol(comet), Symbol(meteor)]
let arr = [1, 2, 3]
console.log(Reflect.ownKeys(arr))
// 输出: ['0', '1', '2', 'length']
}
Reflect.preventExtensions(target)
类似于 Object.preventExtensions()
。返回一个Boolean。
function reflectPreventExtensionsExample() {
let obj = {
name: 'kk',
age: 18
}
console.log(Reflect.preventExtensions(obj)) // 输出: true
console.log(Reflect.isExtensible(obj)) // 输出: false
}
- 如果该方法的 target 参数不是一个对象(是原始值),那么将造成一个 TypeError 异常。
- 对于Object.preventExtensions() 方法,非对象的 target 参数将被强制转换为对象。
console.log(Object.preventExtensions(1)) // 输出: 1 console.log(Reflect.preventExtensions(1)) // 输出报错: TypeError: Reflect.preventExtensions called on non-object
Reflect.set(target, propertyKey, value[, receiver])
将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回 true。
function reflectSetExample() {
let obj = {
name: 'kk',
age: 18
}
console.log(Reflect.set(obj, 'name', 'll')) // 输出: true
console.log(obj.name) // 输出: ll
console.log(Reflect.set(obj, 'age', 20)) // 输出: true
console.log(obj.age) // 输出: 20
console.log(Reflect.set('hello', 0, 'a'))
// 输出报错: TypeError: Reflect.set called on non-object
}
Reflect.setPrototypeOf(target, prototype)
设置对象原型的函数。返回一个 Boolean,如果更新成功,则返回 true。
function reflectSetPrototypeOfExample() {
let obj = {}
console.log(Reflect.setPrototypeOf(obj, null)) // 输出: true
}
- 对象设置freeze
let obj = {} console.log(Reflect.setPrototypeOf(obj, null)) // 输出: true let obj2 = Object.freeze({}) console.log(Reflect.setPrototypeOf(obj2, null)) // 输出: false let obj2_1 = Object.freeze(obj) console.log(Reflect.setPrototypeOf(obj2_1, null)) // 输出: true,因为 Object.freeze() 冻结的对象的原型已经是 null,再次设置null返回true console.log(Reflect.setPrototypeOf(obj2_1, {})) // 输出: false
- 对象设置seal
let obj = {} let obj3 = Object.seal({}) console.log(Reflect.setPrototypeOf(obj3, null)) // 输出: false let obj3_1 = Object.seal(obj) console.log(Reflect.setPrototypeOf(obj3_1, null)) // 输出: true console.log(Reflect.setPrototypeOf(obj3_1, {})) // 输出: false
- 对象设置preventExtensions
let obj = {} let obj4 = Object.preventExtensions({}) console.log(Reflect.setPrototypeOf(obj4, null)) // 输出: false let obj4_1 = Object.preventExtensions(obj) console.log(Reflect.setPrototypeOf(obj4_1, null)) // 输出: true console.log(Reflect.setPrototypeOf(obj4_1, {})) // 输出: false
- 如果导致原型链循环,则返回 false
const target = {} const proto = Object.create(target) console.log(Reflect.setPrototypeOf(target, proto)) // 输出: false