是什么
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() |
如果对象的原型设置成功,则()返回对象本身。如果设置的原型不是Object 或null ,或者被修改的对象的原型不可扩展,则抛出TypeError 。 |
如果在对象上成功设置了原型,则() 返回 true,否则返回 false(包括原型是否不可扩展)。如果传入的目标不是Object ,或者设置的原型不是Object 或null ,则抛出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 属性(虽然很小),为了避免这个问题,可以使用 外,还可以使用 来代替