浅谈Reflect

  • Reflect是一个内置的对象,它提供拦截JavaScript操作的方法,是ES6为了操作对象而提供的新API。
  • Reflect不是一个函数对象,因此它是不可构造
  • Reflect的所有属性和方法都是静态的
  • Reflect的操作是函数式

存在意义

  • 调用对象的基本方法
  • 修改某些Object方法的返回结果,让其变得更规范化
  • Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,即能在Reflect对象上找到对应的方法

Object的缺陷

书写不规范可能导致不可预估的错误

Object.defineProperty上对一个不可写不可枚举的属性进行gettersetter时会抛出错误,对于这个错误,我们需要try catch去捕获,而Reflect.defineProperty则会抛出false,表示本次操作失败(Reflect对对象的操作都会抛出true和false来表示是否操作成功)

  • Object
const obj = {
  name: "ray",
};
Object.defineProperty(obj, "age", {
  value: 30,
  writable: true, //只读
  configurable: false, // 不可删除和修改
});
Object.defineProperty(obj, "age", {
  get() {
    return;
  },
});
console.log(obj.age);
/**
 * Uncaught TypeError: Cannot redefine property: age(无法重新定义:age)
    at Function.defineProperty (<anonymous>)
    at <anonymous>
 */
  • Reflect
const obj = {
  name: "ray",
};
Object.defineProperty(obj, "age", {
  value: 30,
  writable: true, //只读
  configurable: false, // 不可删除和修改
});
const age = Reflect.defineProperty(obj, "age", {
  get() {
    return;
  },
});
console.log(age); // false
console.log(obj.age); // 30

无法准确读取对象的所有属性

Object.defineProperty上设置一个不可枚举的属性或者这个属性的key为Symbol类型时,使用Object.keys、Object.values无法读取对应的key、value

  • Object
const obj = {
  name: "ray",
  [Symbol("job")]:"Frontend"
};
Object.defineProperty(obj, "age", {
  value: 30,
  enumerable: false, //不可枚举
});
console.log(Object.keys(obj));  
// ['name']
console.log(Object.values(obj));  
// ['ray']
  • Reflect
const obj = {
  name: ()=>{
    return "ray"
  },
  [Symbol("job")]:"Frontend"
};
Object.defineProperty(obj, "age", {
  value: 30,
  enumerable: false, //不可枚举
});
console.log(Reflect.ownKeys(obj));
// ['name', 'age', Symbol(job)]

无法修改this

  • Object
const obj = {
  a: 1,
  b: 2,
  get c() {
    return this.a + this.b;
  },
};
console.log(obj.c); // 3
const obj1 = {
  a: 3,
  b: 4,
};
obj.a = obj1.a;
obj.b = obj1.b;
console.log(obj.c); // 7

上面的代码其实我们想要得到obj1ab的相加之和,而因为无法修改this,因此不得不如此处理

  • Reflect
const obj = {
  a: 1,
  b: 2,
  get c() {
    return this.a + this.b;
  },
};
console.log(obj.c); // 3
const obj1 = {
  a: 3,
  b: 4,
};
console.log(Reflect.get(obj, "c", obj1));  // 7

我们看一个相对复杂的例子

const obj = {
  a: 1,
  b: 2,
  get c() {
    return this.a + this.b;
  },
};
const p = new Proxy(obj, {
  get(target, key) {
    console.log(key);
    return target[key];
  },
});
const p1 = new Proxy(obj, {
  get(target, key, receiver) {
    console.log(key);
    return Reflect.get(target, key, receiver);
  },
});
console.log(p.a);
// a
// 1
console.log(p.b);
// b
// 2
console.log(p.c);
// c
// 3
console.log(p1.a);
// a
// 1
console.log(p1.b);
// b
// 2
console.log(p1.c);
// c
// a
// b
// 2

Reflect的一些常用方法

Reflect.get(target,name,receiver)

Reglect.get()有三个参数,分别是:

  • target:目标对象
  • key:对象属性
  • receiver:代理对象(可忽略)。作用:查找并返回target对象的keyvalue,如果该属性不存在则返回undefined
const obj = {
  name: "ray"
};
console.log(Reflect.get(obj,"name"))
// ray

Reflect.set(target, name, value, receiver)

用于设置target对象的keyvalue,如果修改成功返回true,失败返回false

const obj = {
  name: "ray"
};
const job = Reflect.set(obj,'job',"Frontend")
console.log(job)
// true
console.log(obj)
// { name: 'ray', job: 'Frontend' }

Reflect.has(target, key)

用于判断当前key在目标target内是否存在,如果存在返回true,否则返回false

const obj = {
  name: "ray"
};
console.log("name" in obj)
// true
console.log(Object.prototype.hasOwnProperty.call(obj,"name"))
// true
console.log(Reflect.has(obj,"name"))
// true

Reflect.deleteProperty(target, key)

用于删除taget中的key属性

const obj = {
  name: "ray",
  age: 32,
  job: "Frontend",
};
delete obj.age;
console.log(obj);
// { name: 'ray', job: 'Frontend' }
Reflect.deleteProperty(obj, "job");
console.log(obj);
// { name: 'ray' }

Reflect.ownKeys (target)

用于返回目标对象的所有属性,包含Symbol

const obj = {
  name: ()=>{
    return "ray"
  },
  [Symbol("job")]:"Frontend"
};
Object.defineProperty(obj, "age", {
  value: 30,
  enumerable: false, //不可枚举
});
console.log(Reflect.ownKeys(obj));
// ['name', 'age', Symbol(job)]

Reflect对象一共有13个静态方法,下表详细介绍了ObjectReflectAPI上可用方法之间的差异。请注意,如果API中不存在某种方法,则将其标记为N/A

方法ObjectReflect
defineProperty()Object.defineProperty() 返回传递给函数的对象。如果未在对象上成功定义属性,则返回TypeError。如果在对象上定义了属性,则Reflect.defineProperty()返回true,否则返回false。
defineProperties()Object.defineProperties() 返回传递给函数的对象。如果未在对象上成功定义属性,则返回TypeError。N/A
set()N/A如果在对象上成功设置了属性,则Reflect.set()返回true,否则返回false。如果目标不是Object,则抛出TypeError
get()N/AReflect.get()返回属性的值。如果目标不是Object,则抛出TypeError。
getOwnPropertyDescriptor()如果传入的对象参数上存在Object.getOwnPropertyDescriptor() ,则会返回给定属性的属性描述符,如果不存在,则返回undefined。如果给定属性存在于对象上,则Reflect.getOwnPropertyDescriptor() 返回给定属性的属性描述符。如果不存在则返回undefined,如果传入除对象(原始值)以外的任何东西作为第一个参数,则返回TypeError
getOwnPropertyDescriptors()Object.getOwnPropertyDescriptors() 返回一个对象,其中包含每个传入对象的属性描述符。如果传入的对象没有拥有的属性描述符,则返回一个空对象。N/A
getPrototypeOf()Object.getPrototypeOf()返回给定对象的原型。如果没有继承的原型,则返回null。在 ES5 中为非对象抛出TypeError,但在 ES2015 中强制为非对象。Reflect.getPrototypeOf()返回给定对象的原型。如果没有继承的原型,则返回 null,并为非对象抛出TypeError。
setPrototypeOf()如果对象的原型设置成功,则Object.setPrototypeOf()返回对象本身。如果设置的原型不是Object或null,或者被修改的对象的原型不可扩展,则抛出TypeError。如果在对象上成功设置了原型,则Reflect.setPrototypeOf() 返回 true,否则返回 false(包括原型是否不可扩展)。如果传入的目标不是Object,或者设置的原型不是Object或null,则抛出TypeError。
isExtensible()如果对象是可扩展的,则 Object.isExtensible()返回 true,否则返回 false。如果第一个参数不是对象(原始值),则在 ES5 中抛出TypeError。在 ES2015 中,它将被强制为不可扩展的普通对象并返回false。如果对象是可扩展的,则Reflect.isExtensible() 返回true,否则返回false。如果第一个参数不是对象(原始值),则抛出TypeError。
preventExtensions()Object.preventExtensions() 返回被设为不可扩展的对象。如果参数不是对象(为原始值),则在 ES5 中抛出 TypeError。在 ES2015 中,则将参数视为不可扩展的普通对象,并返回对象本身。如果对象已变得不可扩展,则 Reflect.preventExtensions() 返回 true,否则返回 false。如果参数不是对象(为原始值),则抛出 TypeError。
keys()Object.keys()返回一个字符串数组,该字符串映射到目标对象自己的(可枚举)属性键。如果目标不是对象,则在 ES5 中抛出TypeError,但将非对象目标强制为 ES2015 中的对象N/A
ownKeys()N/AReflect.ownKeys()返回一个属性名称数组,该属性名称映射到目标对象自己的属性键。如果目标不是Object,则抛出TypeError。
deleteProperty()N/A如果属性从对象中删除,则Reflect.deleteProperty()返回true,否则返回false。
values()Object.values()返回一个字符串数组,该字符串映射到目标对象自己的(可枚举)属性的值。如果目标不是对象,则在 ES5 中抛出TypeError,但将非对象目标强制为 ES2015 中的对N/A
apply()N/A通过指定的参数列表发起对目标 (target) 函数的调用
construct()N/AReflect.construct() 方法的行为有点像 new 操作符 构造函数,相当于运行 new target(…args)。
has()N/A用于判断当前key在目标target内是否存在,如果存在返回true,否则返回false

参考资料

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值