跳到主要内容

元编程 Reflect 反射

  • Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与 proxy handler (en-US) 的方法相同。Reflect 不是一个函数对象,因此它是不可构造的。

描述

  • 与大多数全局对象不同 Reflect 并非一个构造函数,所以不能通过 new 运算符对其进行调用,或者将 Reflect 对象作为一个函数来调用。
  • Reflect 的所有属性和方法都是静态的(就像 Math 对象)。
  • Reflect 对象提供了静态方法,这些方法与 proxy handler 方法的命名相同。
检测一个对象是否存在特定属性
const duck = {
name: 'Maurice',
color: 'white',
greeting: function () {
console.log(`Quaaaack! My name is ${this.name}`)
},
}

Reflect.has(duck, 'color')
// true
Reflect.has(duck, 'haircut')
// false
返回这个对象自身的属性
Reflect.ownKeys(duck)
// [ "name", "color", "greeting" ]
为这个对象添加一个新的属性
Reflect.set(duck, 'eyes', 'black')
// 返回 "true" 表示成功!
// “duck”现在包含属性“eyes:'black'”

Reflect.apply()

  • 静态方法 Reflect.apply() 通过指定的参数列表发起对目标 (target) 函数的调用。
语法:Reflect.apply(target, thisArgument, argumentsList)
console.log(Reflect.apply(Math.floor, undefined, [1.75]))
// output: 1

console.log(
Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111])
)
// output: "hello"

console.log(Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index)
// output: 4

console.log(Reflect.apply(''.charAt, 'ponies', [3]))
// output: "i"

参数

  • target 目标函数。

  • thisArgument target 函数调用时绑定的 this 对象。

  • argumentsList target 函数调用时传入的实参列表,该参数应该是一个类数组的对象。

返回值

返回值是调用完带着指定参数和 this 值的给定的函数后返回的结果。

Reflect.construct()

  • Reflect.construct() 方法的行为有点像 new 操作符 构造函数,相当于运行 new target(...args).
语法
Reflect.construct(target, argumentsList[, newTarget])

参数

  • target 被运行的目标构造函数

  • argumentsList 类数组,目标构造函数调用时的参数。

  • newTarget 可选 作为新创建对象的原型对象的 constructor 属性,参考 new.target 操作符,默认值为 target。

返回值

  • 以 target(如果 newTarget 存在,则为 newTarget)函数为构造函数,argumentList 为其初始化参数的对象实例。

异常

  • 如果 target 或者 newTarget 不是构造函数,抛出 TypeError,异常。

Reflect.defineProperty()

  • 静态方法 Reflect.defineProperty() 基本等同于 Object.defineProperty() 方法,唯一不同是返回 Boolean 值。
  • Reflect.defineProperty 方法允许精确添加或修改对象上的属性。更多的细节请参阅类似的 Object.defineProperty 。

备注:

  • Object.defineProperty 返回一个对象,或者如果属性没有被成功定义,抛出一个 TypeError。
  • 相比之下,Reflect.defineProperty 方法只返回一个 Boolean,来说明该属性是否被成功定义。
语法
Reflect.defineProperty(target, propertyKey, attributes)

参数

  • target 目标对象。

  • propertyKey 要定义或修改的属性的名称。

  • attributes 要定义或修改的属性的描述。

返回值

  • Boolean 值指示了属性是否被成功定义。

异常

  • 如果 target 不是 Object,抛出一个 TypeError。

Reflect.deleteProperty()

  • 静态方法 Reflect.deleteProperty() 允许用于删除属性。它很像 delete operator ,但它是一个函数。
  • Reflect.deleteProperty 允许你删除一个对象上的属性。返回一个 Boolean 值表示该属性是否被成功删除。它几乎与非严格的 delete operator 相同。
语法
Reflect.deleteProperty(target, propertyKey)

参数

  • target 删除属性的目标对象。

  • propertyKey 需要删除的属性的名称。

返回值

  • Boolean 值表明该属性是否被成功删除。

异常

  • 抛出一个 TypeError,如果 target 不是 Object。
实例:使用 Reflect.deleteProperty()
var obj = { x: 1, y: 2 }
Reflect.deleteProperty(obj, 'x') // true
obj // { y: 2 }

var arr = [1, 2, 3, 4, 5]
Reflect.deleteProperty(arr, '3') // true
arr // [1, 2, 3, , 5]

// 如果属性不存在,返回 true
Reflect.deleteProperty({}, 'foo') // true

// 如果属性不可配置,返回 false
// Object.freeze 冻结对象
Reflect.deleteProperty(Object.freeze({ foo: 1 }), 'foo') // false

Reflect.get()

  • Reflect.get() 方法与从 对象 (target[propertyKey]) 中读取属性类似,但它是通过一个函数执行来操作的。
  • Reflect.get 方法允许你从一个对象中取属性值。就如同属性访问器 语法,但却是通过函数调用来实现。
语法
Reflect.get(target, propertyKey[, receiver])

参数

  • target 需要取值的目标对象

  • propertyKey 需要获取的值的键值

  • receiver 如果 target 对象中指定了 getter,receiver 则为 getter 调用时的 this 值。

返回值

  • 属性的值。

异常

  • 如果目标值类型不是 Object,则抛出一个 TypeError。
使用 Reflect.get()
// Object
var obj = { x: 1, y: 2 }
Reflect.get(obj, 'x') // 1

// Array
Reflect.get(['zero', 'one'], 1) // "one"

// Proxy with a get handler
var x = { p: 1 }
var obj = new Proxy(x, {
get(t, k, r) {
return k + 'bar'
},
})
Reflect.get(obj, 'foo') // "foobar"

Reflect.getOwnPropertyDescriptor()

  • 静态方法 Reflect.getOwnPropertyDescriptor() 与 Object.getOwnPropertyDescriptor() 方法相似。
  • 如果在对象中存在,则返回给定的属性的属性描述符。否则返回 undefined。
  • Reflect.getOwnPropertyDescriptor 方法返回一个属性描述符,如果给定的属性存在于对象中,否则返回 undefined 。
  • 与 Object.getOwnPropertyDescriptor() 的唯一不同在于如何处理非对象目标。
语法
Reflect.getOwnPropertyDescriptor(target, propertyKey)

参数

  • target 需要寻找属性的目标对象。

  • propertyKey 获取自己的属性描述符的属性的名称。

返回值

  • 如果属性存在于给定的目标对象中,则返回属性描述符;否则,返回 undefined。

异常

  • 抛出一个 TypeError,如果目标不是 Object。
使用 Reflect.getOwnPropertyDescriptor()
Reflect.getOwnPropertyDescriptor({ x: 'hello' }, 'x')
// {value: "hello", writable: true, enumerable: true, configurable: true}

Reflect.getOwnPropertyDescriptor({ x: 'hello' }, 'y')
// undefined

Reflect.getOwnPropertyDescriptor([], 'length')
// {value: 0, writable: true, enumerable: false, configurable: false}
  • 与 Object.getOwnPropertyDescriptor() 的不同点
  • 如果该方法的第一个参数不是一个对象(一个原始值),那么将造成 TypeError 错误。
  • 而对于 Object.getOwnPropertyDescriptor,非对象的第一个参数将被强制转换为一个对象处理。
Reflect.getOwnPropertyDescriptor('foo', 0)
// TypeError: "foo" is not non-null object

Object.getOwnPropertyDescriptor('foo', 0)
// { value: "f", writable: false, enumerable: true, configurable: false }

Reflect.getPrototypeOf()

  • 静态方法 Reflect.getPrototypeOf() 与 Object.getPrototypeOf() 方法几乎是一样的。
  • 都是返回指定对象的原型(即内部的 [[Prototype]] 属性的值)。
const object1 = {
property1: 42,
}

const proto1 = Reflect.getPrototypeOf(object1)

console.log(proto1)
// Expected output: Object { }

console.log(Reflect.getPrototypeOf(proto1))
// Expected output: null
使用 Reflect.getPrototypeOf()
Reflect.getPrototypeOf({}) // Object.prototype
Reflect.getPrototypeOf(Object.prototype) // null
Reflect.getPrototypeOf(Object.create(null)) // null
与 Object.getPrototypeOf() 比较
// 如果参数为 Object,返回结果相同
Object.getPrototypeOf({}) // Object.prototype
Reflect.getPrototypeOf({}) // Object.prototype

// 在 ES5 规范下,对于非 Object,抛异常
Object.getPrototypeOf('foo') // Throws TypeError
Reflect.getPrototypeOf('foo') // Throws TypeError

// 在 ES2015 规范下,Reflect 抛异常,Object 强制转换非 Object
Object.getPrototypeOf('foo') // String.prototype
Reflect.getPrototypeOf('foo') // Throws TypeError

// 如果想要模拟 Object 在 ES2015 规范下的表现,需要强制类型转换
Reflect.getPrototypeOf(Object('foo')) // String.prototype

Reflect.has()

  • 静态方法 Reflect.has() 作用与 in 操作符 相同。
使用 Reflect.has()
Reflect.has({ x: 0 }, 'x') // true
Reflect.has({ x: 0 }, 'y') // false

// 如果该属性存在于原型链中,返回 true
Reflect.has({ x: 0 }, 'toString')

// Proxy 对象的 .has() 句柄方法
obj = new Proxy(
{},
{
has(t, k) {
return k.startsWith('door')
},
}
)
Reflect.has(obj, 'doorbell') // true
Reflect.has(obj, 'dormitory') // false

Reflect.isExtensible()

  • 静态方法 Reflect.isExtensible() 判断一个对象是否可扩展(即是否能够添加新的属性)。
  • 与它 Object.isExtensible() 方法相似,但有一些不同,详情可见 与 Object.isExtensible() 的不同点。
  • Reflect.isExtensible 判断一个对象是否可扩展(即是否能够添加新的属性)。
  • 它与 Object.isExtensible() 方法一样。
使用 Reflect.isExtensible()
// New objects are extensible.
var empty = {}
Reflect.isExtensible(empty) // === true

// ...but that can be changed.
Reflect.preventExtensions(empty)
Reflect.isExtensible(empty) // === false

// Sealed objects are by definition non-extensible.
var sealed = Object.seal({})
Reflect.isExtensible(sealed) // === false

// Frozen objects are also by definition non-extensible.
var frozen = Object.freeze({})
Reflect.isExtensible(frozen) // === false
  • 与 Object.isExtensible() 的不同点
  • 如果该方法的第一个参数不是一个对象(原始值),那么将造成一个 TypeError 异常。
  • 对于 Object.isExtensible(),非对象的第一个参数会被强制转换为一个对象。
Reflect.isExtensible(1)
// TypeError: 1 is not an object

Object.isExtensible(1)
// false

Reflect.ownKeys()

  • 静态方法 Reflect.ownKeys() 返回一个由目标对象自身的属性键组成的数组。
  • Reflect.ownKeys 方法返回一个由目标对象自身的属性键组成的数组。
  • 它的返回值等同于 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。
语法:Reflect.ownKeys(target)
const object1 = {
property1: 42,
property2: 13,
}
const array1 = []
console.log(Reflect.ownKeys(object1))
// output: Array ["property1", "property2"]
console.log(Reflect.ownKeys(array1))
// output: Array ["length"]
使用 Reflect.ownKeys()
Reflect.ownKeys({ z: 3, y: 2, x: 1 }) // [ "z", "y", "x" ]
Reflect.ownKeys([]) // ["length"]

var sym = Symbol.for('comet')
var sym2 = Symbol.for('meteor')
var obj = {
[sym]: 0,
str: 0,
773: 0,
0: 0,
[sym2]: 0,
'-1': 0,
8: 0,
'second str': 0,
}
Reflect.ownKeys(obj)
// [ "0", "8", "773", "str", "-1", "second str", Symbol(comet), Symbol(meteor) ]
// Indexes in numeric order,
// strings in insertion order,
// symbols in insertion order

Reflect.preventExtensions()

  • 静态方法 Reflect.preventExtensions() 方法阻止新属性添加到对象 (例如:防止将来对对象的扩展被添加到对象中)。
  • 该方法与 Object.preventExtensions()相似,但有一些不同点。
  • 详情可见 differences。
  • Reflect.preventExtensions 方法阻止新属性添加到对象 (例如:防止将来对对象的扩展被添加到对象中)。
  • 该方法与 Object.preventExtensions() 方法相似。
语法:Reflect.preventExtensions(target)
const object1 = {}
console.log(Reflect.isExtensible(object1))
// Expected output: true
Reflect.preventExtensions(object1)
console.log(Reflect.isExtensible(object1))
// Expected output: false
使用 Reflect.preventExtensions()
// Objects are extensible by default.
var empty = {}
Reflect.isExtensible(empty) // === true

// ...but that can be changed.
Reflect.preventExtensions(empty)
Reflect.isExtensible(empty) // === false
  • 与 Object.preventExtensions() 的不同点
  • 如果该方法的 target 参数不是一个对象(是原始值),那么将造成一个 TypeError 异常。
  • 对于 Object.preventExtensions() 方法,非对象的 target 参数将被强制转换为对象。
Reflect.preventExtensions(1)
// TypeError: 1 is not an object
Object.preventExtensions(1)
// 1

Reflect.set()

  • 静态方法 Reflect.set() 工作方式就像在一个对象上设置一个属性。
  • Reflect.set 方法允许你在对象上设置属性。
  • 它的作用是给属性赋值并且就像 property accessor 语法一样,但是它是以函数的方式。
使用 Reflect.set()
// Object
var obj = {}
Reflect.set(obj, 'prop', 'value') // true
obj.prop // "value"

// Array
var arr = ['duck', 'duck', 'duck']
Reflect.set(arr, 2, 'goose') // true
arr[2] // "goose"

// It can truncate an array.
Reflect.set(arr, 'length', 1) // true
arr // ["duck"];

// With just one argument, propertyKey and value are "undefined".
var obj = {}
Reflect.set(obj) // true
Reflect.getOwnPropertyDescriptor(obj, 'undefined')
// { value: undefined, writable: true, enumerable: true, configurable: true }

Reflect.setPrototypeOf()

  • 除了返回类型以外,静态方法 Reflect.setPrototypeOf() 与 Object.setPrototypeOf() 方法是一样的。
  • 它可设置对象的原型(即内部的 [[Prototype]] 属性)为另一个对象或 null,如果操作成功返回 true,否则返回 false。
  • Reflect.setPrototypeOf 方法改变指定对象的原型(即,内部的 [[Prototype]] 属性值)。
语法:Reflect.setPrototypeOf(target, prototype)
const object1 = {}

console.log(Reflect.setPrototypeOf(object1, Object.prototype))
// output: true

console.log(Reflect.setPrototypeOf(object1, null))
// output: true

const object2 = {}

console.log(Reflect.setPrototypeOf(Object.freeze(object2), null))
// output: false
使用 Reflect.setPrototypeOf()
Reflect.setPrototypeOf({}, Object.prototype) // true
// It can change an object's [[Prototype]] to null.
Reflect.setPrototypeOf({}, null) // true
// Returns false if target is not extensible.
Reflect.setPrototypeOf(Object.freeze({}), null) // false
// Returns false if it cause a prototype chain cycle.
var target = {}
var proto = Object.create(target)
Reflect.setPrototypeOf(target, proto) // false