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/...

相关推荐
ssshooter13 分钟前
Node.js 天生就是异步的,为什么还要消息队列?
javascript·后端·面试
爱吃红星柚13 分钟前
【学习】Elpis 抽离与发布 npm 包
前端·前端框架·node.js
PedroQue9944 分钟前
0.5.0重磅发布:动画插件+H5体验全面优化
前端·uni-app
金虹桥程序员1 小时前
【动画】 📚 CSS 动画与 GPU 合成层优化全链路指南
前端·面试
程序员老赵1 小时前
Docker 部署填鸭表单完整教程:搭建私有化问卷与表单收集平台
前端·docker·开源
无限压榨切图仔1 小时前
向量库能搜到内容,为什么还不算学会 RAG
前端·agent
mmsx1 小时前
MapLibre 实战 11|用户说"我的地块丢了":一个 sealed class 图层模型,和四个让我重构三版的坑
android·前端·开源
xqchen1 小时前
代码差异可视化方案选型:diff2html 实战指南
前端
名字还没想好☜1 小时前
用 Zustand 做 React 全局状态管理:告别 Context 重渲染,3 个实战模式与持久化
前端
IMPYLH1 小时前
HTML 的 <section> 元素
前端·html