Reflect
是一个内置的对象,它提供拦截 JavaScript 操作 的方法,这些方法与 proxy handler 的方法相同。Reflect
不是一个函数对象,因此它是不可构造的,所以不能通过 new
运算符对其进行调用 ,或者将 Reflect
对象作为一个函数来调用。Reflect 的所有属性和方法都是静态的(就像 Math 对象)。
静态方法
Reflect.apply(target, thisArgument, argumentsList)
对一个函数进行调用 操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply()
功能类似。
静态方法 Reflect.apply()
通过指定的参数列表发起对目标 (target) 函数的调用。
javascript
console.log(Reflect.apply(Math.floor, undefined, [1.75]))
// 输出: 1
Reflect.construct(target, argumentsList[, newTarget])
对构造函数进行 new
操作,相当于执行 new target(...args)
。
javascript
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()
)来创建一个对象的。
javascript
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
。
javascript
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
来判断结果。
javascript
if (Reflect.defineProperty(target, property, attributes)) {
// 成功
} else {
// 失败
}
Reflect.deleteProperty(target, propertyKey)
作为函数的delete
操作符,相当于执行 delete target[name]
。
javascript
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)。
改进:
javascript
// 方案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]
。
javascript
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
javascript
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
。
javascript
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
,非对象的第一个参数将被强制转换为一个对象处理。javascript// 尝试获取非对象的属性描述符 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()
。
javascript
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 类型
javascript
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
运算符 的功能完全相同。
javascript
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()
javascript
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))
。
javascript
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。
javascript
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 参数将被强制转换为对象。
javascriptconsole.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。
javascript
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。
javascript
function reflectSetPrototypeOfExample() {
let obj = {}
console.log(Reflect.setPrototypeOf(obj, null)) // 输出: true
}
-
对象设置freeze
javascriptlet 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
javascriptlet 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
javascriptlet 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
javascriptconst target = {} const proto = Object.create(target) console.log(Reflect.setPrototypeOf(target, proto)) // 输出: false