js之Reflect 反射

时间:2025-03-30 19:49:39

是什么

Reflect是一个内置的对象,它提供了拦截JavaScript操作的方法。它不是一个函数对象,因此不可构造。Reflect对象提供了一些静态方法来操作对象,例如等。这些方法可以用于读取、修改或删除对象的属性,并返回相应的结果。

在Vue 3中,Reflect也被用作一个修饰符(decorator),用于监听DOM元素上的属性变化并将其反映到Vue实例的数据上。当DOM元素的属性发生变化时,Vue会捕获这些变化,并更新相应的数据,从而保持数据和视图的同步。

总的来说,Reflect在Vue 3中扮演着重要的角色,它提供了一种机制来拦截和操作JavaScript对象,从而实现响应式数据绑定和视图更新。

对象的设计目的

 1 .将Object对象的一些明显属于语言内部的方法(比如),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。
 2 .修改某些Object方法的返回结果,让其变得更合理。
 3 .让Object操作都变成函数行为
 4 .Reflect对象的方法与Proxy对象的方法一一对应  

3. Reflect 13 个静态方法  

(target, name, receiver) 查找并返回target对象的name属性,receiver绑定this
(target, name, value, receiver) 设置target对象的name属性等于value
(obj, name) 方法对应name in obj里面的in运算符
(obj, name) 方法等同于delete obj[name],用于删除对象的属性。
(target, args) 等同于new target(...args),调用构造函数的方法。
(obj) 读取对象的__proto__属性,对应
(obj, newProto) 设置目标对象的原型 对应
(func, thisArg, args) 等同于(func, thisArg, args)
(target, propertyKey, attributes) 等同于
(target, propertyKey) 等同于
 (target) 对应 表示当前对象是否可扩展。
(target) 对应 让一个对象变为不可扩展
 (target) 返回对象的所有属性,可以返回Symbol类型

 

4.静态方法

  • (target, thisArg, args)

对一个函数进行调用操作,同时可以传入一个数组作为调用参数。

 
var obj1 = {};
(, obj1, [1.88]) // 1;
  • (target, args)

对构造函数进行 new 操作,相当于执行 new target(...args)。

 
const obj2 = (Date, [2021, 3, 1]);
  • (target, name, receiver)

获取对象身上某个属性的值,类似于 target[name]。如果没有该属性,则返回undefined。

 
var obj3 = { x: 1, y: 2 }; 
(obj3, "x"); // 1
  • (target, name, value, receiver) 将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。
 
var obj4 = {}; 
(obj4, "prop", "value"); // true
  • (target, name, desc)

方法基本等同于,直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,不同的是,返回此对象。而会返回布尔值.

 
const obj5 = {}; 
(obj5, 'property', { 
    value: 666, 
    writable: false 
}); // true
  • (target, name)

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

 
var obj6 = { x: 1, y: 2 }; 
(obj6, "x"); // true 
obj; // { y: 2 }
  • (target, name)

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

 
const obj7 = {x: 0};
(obj7, "x"); // true
  • (target)

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

 
const obj8 = {z: 3, y: 2, x: 1};
(obj8); // [ "z", "y", "x" ]
  • (target)

判断一个对象是否是可扩展的(是否可以在它上面添加新的属性),类似于 ()。返回表示给定对象是否可扩展的一个Boolean 。( 或 方法都可以标记一个对象为不可扩展。)

 
var obj9 = {}; 
(obj9); // true
  • (target)

让一个对象变的不可扩展,也就是永远不能再添加新的属性。

 
var obj10 = {}; 
(obj10); // true 
(obj10); 
(obj10); // false
  • (target, name)

如果对象中存在该属性,如果指定的属性存在于对象上,则返回其属性描述符对象(property descriptor),否则返回 undefined。类似于 ()。

 
const obj11 = {x: "hello"};
(obj11, "x");
// {value: "hello", writable: true, enumerable: true, configurable: true}

(target)

返回指定对象的原型.类似于 ()。

 
var obj12 = {};
(obj12); // 等同于
  • (target, prototype)

设置对象原型的函数. 返回一个 Boolean, 如果更新成功,则返回true。如果 target 不是 Object ,或 prototype 既不是对象也不是 null,抛出一个 TypeError 异常。

 
var obj13 = {}; 
(obj13, null); // true

 和 Reflect API 上可用方法之间的差异

如果 API 中不存在某种方法,则将其标记为 N/A。

Method Name Object Reflect
defineProperty() () 返回传递给函数的对象。如果未在对象上成功定义属性,则返回TypeError 如果在对象上定义了属性,则()返回true,否则返回false
defineProperties() () 返回传递给函数的对象。如果未在对象上成功定义属性,则返回TypeError N/A
set() N/A 如果在对象上成功设置了属性,则()返回true,否则返回false。如果目标不是Object,则抛出TypeError
get() N/A ()返回属性的值。如果目标不是Object,则抛出TypeError
deleteProperty() N/A 如果属性从对象中删除,则()返回true,否则返回false
getOwnPropertyDescriptor() 如果传入的对象参数上存在() ,则会返回给定属性的属性描述符,如果不存在,则返回undefined 如果给定属性存在于对象上,则() 返回给定属性的属性描述符。如果不存在则返回undefined,如果传入除对象(原始值)以外的任何东西作为第一个参数,则返回TypeError
getOwnPropertyDescriptors() () 返回一个对象,其中包含每个传入对象的属性描述符。如果传入的对象没有拥有的属性描述符,则返回一个空对象。 N/A
getPrototypeOf() ()返回给定对象的原型。如果没有继承的原型,则返回null。在 ES5 中为非对象抛出TypeError,但在 ES2015 中强制为非对象。 ()返回给定对象的原型。如果没有继承的原型,则返回 null,并为非对象抛出TypeError
setPrototypeOf() 如果对象的原型设置成功,则()返回对象本身。如果设置的原型不是Objectnull,或者被修改的对象的原型不可扩展,则抛出TypeError 如果在对象上成功设置了原型,则() 返回 true,否则返回 false(包括原型是否不可扩展)。如果传入的目标不是Object,或者设置的原型不是Objectnull,则抛出TypeError
isExtensible() 如果对象是可扩展的,则 ()返回 true,否则返回 false。如果第一个参数不是对象(原始值),则在 ES5 中抛出TypeError。在 ES2015 中,它将被强制为不可扩展的普通对象并返回false 如果对象是可扩展的,则() 返回true,否则返回false。如果第一个参数不是对象(原始值),则抛出TypeError
preventExtensions() () 返回被设为不可扩展的对象。如果参数不是对象(原始值),则在 ES5 中抛出TypeError。在 ES2015 中,参数如为不可扩展的普通对象,然后返回对象本身。 returns true if the object has been made non-extensible, and false if it has not. Throws a TypeError if the argument is not an object (a primitive).如果对象已变得不可扩展,则() 返回true,否则返回false。如果参数不是对象(原始值),则抛出TypeError
keys() ()返回一个字符串数组,该字符串映射到目标对象自己的(可枚举)属性键。如果目标不是对象,则在 ES5 中抛出TypeError,但将非对象目标强制为 ES2015 中的对象 N/A
ownKeys() N/A ()返回一个属性名称数组,该属性名称映射到目标对象自己的属性键。如果目标不是Object,则抛出TypeError

6.它可以做什么? 

使用Reflect可以实现诸如 属性的赋值与取值、调用普通函数、调用构造函数、判断属性是否存在与对象中 等等功能

7.这些功能已经存在了,为什么还需要用Reflect实现一次? 

有一个理念,在ES5就被提出:减少魔法、让代码更加纯粹

这种理念很大程度上是受到函数式编程的影响

ES6进一步贯彻了这种理念,它认为,对属性内存的控制、原型链的修改、函数的调用等等,这些都属于底层实现,属于一种魔法,因此,需要将它们提取出来,形成一个正常的API,并高度聚合到某个对象中,于是,就造就了Reflect对象

因此,你可以看到Reflect对象中有很多的API都可以使用过去的某种语法或其他API实现。

  API 的好处

状态标记

或许 Object 上也有相同的方法,但是通常 Object 会因为报错而阻塞程序,而 Reflect 返回操作的 boolean 状态值,表示操作成功与否,返回 true 表示操作成功

常见的 Reflect 提供状态标记的 api 有

const obj = {};

try {
  (obj, "key", "xxx");
} catch (err) {
  log("err: ", err);
}

// 可以使用 状态标记来 重构上述代码
if (!(obj, "key", "xx")) {
  log("obj define key failed");
}

用一等函数替代操作符

  • 替代 / obj["key"]
  • 替代 = value / obj["key"] = value;
  • 替代 in 或者 with
  • 替代 delete 操作符
  • 替代 new 操作符
const person = {
  name: "jakequc",
  age: 23,
};

// 替代  / person["name"]
log((person, "name")); // log: jakequc

// 替代  = "new_name" or person["name"] = "new_name"
(person, "name", "new_name");

log((person, "name")); // log: new_name

// 替代 ( "name" in person )或者 with()
log((person, "name")); // log: true

// 替代 delete 操作符
log((person, "name")); // log: true 表示删除成功
log((person, "name")); // log: fasle, 因为上一行已经删除了

// 替代 new 操作符
const arr = (Array, [1, 2, 3, 4]);
log(arr); // log: [ 1, 2, 3, 4 ]

安全地应用函数

可能某些方法或属性自定义的覆盖了内置的;比如 apply 方法调用函数时,被调用的函数可能也定义了自己的 apply 属性(虽然很小),为了避免这个问题,可以使用 外,还可以使用 来代替