Reflect ES6 新增的内置对象

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

Reflect 的所有属性和方法都是静态的(就像 Math 对象)。

静态方法

Reflect.apply(target, thisArgument, argumentsList)

对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。手写 call 和 apply 的时候直接用来才操作了。

javascript 复制代码
console.log(Reflect.apply(Math.floor, undefined, [1.75]));
// Expected output: 1

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

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

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

Reflect.construct(target, argumentsList[, newTarget])

对构造函数进行 new 操作,相当于执行 new target(...args)。可以帮助我们不在不使用 new 的方式创建实例

ini 复制代码
var obj = new Foo(...args);
var obj = Reflect.construct(Foo, args);

Reflect.defineProperty(target, propertyKey, attributes)

Object.defineProperty() 类似。如果设置成功就会返回 true

javascript 复制代码
const obj = {};

// 用 Reflect 定义一个只读属性
if (Reflect.defineProperty(obj, "a", { value: 10, writable: false })) {
  console.log("定义成功");
} else {
  console.log("定义失败");
}

console.log(obj.a); // 10

// 尝试在冻结对象上定义属性
Object.freeze(obj);

if (Reflect.defineProperty(obj, "b", { value: 20 })) {
  console.log("定义成功");
} else {
  console.log("定义失败"); // 这里不会抛错,而是 false
}

Reflect.deleteProperty(target, propertyKey)

作为函数的delete操作符,相当于执行 delete target[name]

javascript 复制代码
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
Reflect.deleteProperty(Object.freeze({ foo: 1 }), "foo"); // false

Reflect.get(target, propertyKey[, receiver])

获取对象身上某个属性的值,类似于 target[name]

javascript 复制代码
// 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(target, propertyKey)

类似于 Object.getOwnPropertyDescriptor()。如果对象中存在该属性,则返回对应的属性描述符,否则返回 undefined

yaml 复制代码
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}

Reflect.getPrototypeOf(target)

类似于 Object.getPrototypeOf()。获取对象的原型

javascript 复制代码
const object1 = {
  property1: 42,
};

const proto1 = Reflect.getPrototypeOf(object1);

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

console.log(Reflect.getPrototypeOf(proto1));
// Expected output: null

Reflect.has(target, propertyKey)

判断一个对象是否存在某个属性,和 in运算符 的功能完全相同。

javascript 复制代码
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(target)

类似于 Object.isExtensible(). 判断一个对象是否可扩展(即是否能够添加新的属性)。

javascript 复制代码
// 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.
// 密封对象, 不允许新增属性、删除属性、修改已有属性的值、修改属性的特性(configurable/writable)。
var sealed = Object.seal({});
Reflect.isExtensible(sealed); // === false

// Frozen objects are also by definition non-extensible.
// 冻结对象, 不允许新增属性、删除属性、修改已有属性的值、修改属性的特性(writable、configurable、enumerable)
// 常用于:定义常量对象,例如配置项、枚举值,不希望被修改。定义三方库不想让别人操作你的对象是可以使用
var frozen = Object.freeze({});
Reflect.isExtensible(frozen); // === false

Reflect.ownKeys(target)

返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受enumerable 影响).

ini 复制代码
const object1 = {
  property1: 42,
  property2: 13,
};

const array1 = [];

console.log(Reflect.ownKeys(object1));
// Expected output: Array ["property1", "property2"]

console.log(Reflect.ownKeys(array1));
// Expected output: Array ["length"]

Reflect.preventExtensions(target)

类似于 Object.preventExtensions()。返回一个Boolean。防止新属性被添加到对象中(即防止该对象被扩展)。它还可以防止对象的原型被重新指定。

javascript 复制代码
const object1 = {};

console.log(Reflect.isExtensible(object1));
// Expected output: true

Reflect.preventExtensions(object1);

console.log(Reflect.isExtensible(object1));
// Expected output: false
 
try {
  Reflect.defineProperty(object1, "property1", {
    value: 42,
  });
} catch (e) {
  console.log(e);
  // Expected output: TypeError: Cannot define property property1, object is not extensible
}

Reflect.set(target, propertyKey, value[, receiver])

将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true

javascript 复制代码
// 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(target, prototype)

设置对象原型的函数。返回一个 Boolean,如果更新成功,则返回 true

javascript 复制代码
const object1 = {};

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

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

const object2 = {};

console.log(Reflect.setPrototypeOf(Object.freeze(object2), null));
// Expected output: false

使用场景

操作对象、配合 Proxy,用于底层拦截与标准化。

javascript 复制代码
const target = { x: 1 };
const proxy = new Proxy(target, {
  get(t, prop, receiver) {
    console.log("拦截 get");
    return Reflect.get(t, prop, receiver); // 调用默认行为
  }
});
console.log(proxy.x); // 拦截 get → 1

装饰器

reflect-metadata 就是扩展了 Reflect,往里面加了 defineMetadata / getMetadata 等方法。所以在装饰器代码里看到的 Reflect.getMetadata 其实并不是原生的 Reflect,而是 reflect-metadata 给它扩展的。 可以查看 # reflect-metadata 依赖注入 文章介绍

参考资料
developer.mozilla.org/zh-CN/docs/...

相关推荐
Mintopia5 分钟前
🌌 Next.js 服务端组件(Server Components)与客户端组件(`"use client"`)
前端·javascript·next.js
Mintopia7 分钟前
⚔️ WebAI 推理效率优化:边缘计算 vs 云端部署的技术博弈
前端·javascript·aigc
诗书画唱25 分钟前
JavaScript 基础核心知识点总结:从使用方式到核心语法
开发语言·javascript·ecmascript
水冗水孚1 小时前
通俗易懂地理解深度遍历DFS、和广度遍历BFS
javascript·算法
未来之窗软件服务1 小时前
网页提示UI操作-适应提示,警告,信息——仙盟创梦IDE
javascript·ide·ui·仙盟创梦ide·东方仙盟
爱学大树锯1 小时前
【Ruoyi 解密 - 09. 前端探秘2】------ 接口路径及联调实战指南
前端
老华带你飞1 小时前
校园二手书交易|基于SprinBoot+vue的校园二手书交易管理系统(源码+数据库+文档)
java·前端·数据库·vue.js·小程序·毕设·校园二手书交易管理系统
萌程序.1 小时前
创建Vue项目
前端·javascript·vue.js
VT.馒头2 小时前
【力扣】2704. 相等还是不相等
前端·javascript·算法·leetcode·udp