JavaScript Reflect 学习笔记

今天我们来学习JavaScript中的反射和ES6的Reflect对象。

什么是反射?

反射机制是指在程序运行期间能够获取自身的信息,比如一个对象能够在运行时就知道自己有哪些属性和方法。

在ES6之前,JavaScript已经具有反射的特性,即使社区或者规范没有称之为反射特性。比如Object.keys(), Object.getOwnPropertyDescriptor(), Array.isArray() 等这些方法都具有反射特性。

比如我们可以通过for…in语句可以查看对象的所有属性和方法

for (var key in window) {
  console.log(key, window[key])
}

在ES6中引入了一个名为Reflect的新的全局对象,可以用它来调用方法、构造对象、获取和添加属性、操作或拓展属性。

Reflect API

与其他全局对象不同,Reflect不是构造函数,不能使用new来调用,也不能作为函数来调用。它类似Math,JSON对象。Reflect的所有方法都是静态方法。

  • Reflect.apply() – 使用指定参数调用函数
  • Reflect.construct() – 像new操作符一样,相当于调用了new target(...args)
  • Reflect.defineProperty() – 类似于 Object.defineProperty(),但返回一个布尔值,表示是否在对象上成功定义了属性。
  • Reflect.deleteProperty() – 类似于 delete 操作符,相当于调用了delete objectName[propertyName]
  • Reflect.get() – 返回一个属性的值
  • Reflect.getOwnPropertyDescriptor() – 类似于 Object.getOwnPropertyDescriptor()。如果属性存在于对象上,则返回属性的属性描述符,否则返回undefined
  • Reflect.getPrototypeOf() – 和Object.getPrototypeOf() 一样。
  • Reflect.has() – 和 in 操作符一样工作,它返回一个布尔值,表示属性(自身的或继承的)是否存在。
  • Reflect.isExtensible() – 和 Object.isExtensible() 一样。
  • Reflect.ownKeys() – 返回对象的属性(不包括继承的)的数组。
  • Reflect.preventExtensions() – 类似于 Object.preventExtensions(),返回一个布尔值。
  • Reflect.set() – 为属性赋值并返回一个布尔值,如果该属性设置成功,则返回true
  • Reflect.setPrototypeOf() – 设置对象的prototype

下面来看看使用 Reflect API的例子:

创建对象: Reflect.construct()

Reflect.construct() 方法类似于new运算符,相当于调用了new target(...args)

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

Reflect.construct() 返回target类的新实例对象,或者返回newTarget,如果传入的话。

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
};

let args = ['小帅', '的编程笔记'];

let xiaoshuai = Reflect.construct(
  Person,
  args
);

console.log(xiaoshuai instanceof Person);
console.log(xiaoshuai.fullName);

// 输出:
// true
// 小帅 的编程笔记

在这个例子中:

  • 首先定义一个类 Person.
  • 定义一个参数的数组
  • 然后使用Reflect.construct() 方法创建 Person 类的新实例。xiaoshuai 对象是 Person 类的一个实例,所以它有 fullName 属性。

调用函数: Reflect.apply()

在ES6之前,可以使用Function.prototype.apply() 方法来去调用具有指定this 值和 arguments的函数。例如

let result = Function.prototype.apply.call(Math.max, Math, [10, 20, 30]);
console.log(result);

// 输出:
// 30

语法很长,并且也难以理解

有些同学可能不是很理解Function.prototype.apply.call,引用知乎上的一个解释的比较好

如何理解Function.prototype.apply.call(fn,thisArg,args)

根据 call 方法的调用规则,Function.prototype.apply.call( fn, thisArg, args ) 中的第一个参数 fn,将作为 Function.prototype.apply(以下简称为: apply) 中 this 的值,剩余的两个参数 thisArg 和 args 都将被传递给 apply。

(为便于以下的说明,我们先来看一下 apply 的正常使用方式:fn.apply( thisArg, args ),也就是说,我们要通过 apply 的方式来调用函数 fn,此时 fn 中 this 的值为 apply 的第一个参数 thisArg, apply 的第二个参数 args 则被传递给了 fn,从而实现对 fn 的调用。然而,这里有一个要点,一般来说,我们都不会太去关注,那就是,apply 方法中的 this 此时应该指向哪个值呢?没错,应该指向 fn。好了,我们继续往下看)

虽然我们对 apply 的具体实现细节不清楚,但可以肯定的是,apply 中 this 的值即是要通过 apply 的方式来调用的函数(在此例中为 fn)。既然已经知道要通过 apply 方法来调用 fn,那么我们继续往下看:

根据 apply 方法的调用规则,在此例中,传递给 apply 方法的第一个参数 thisArg 将作为 fn 中 this 的值,第二个参数 args 将被传递给 fn,从而实现对 fn 的调用。到这里我们就可以看到 Function.prototype.apply.call( fn, thisArg, args ) 这个调用其实等价于 fn.apply( thisArg, args ) 这个调用。

出处:https://zhuanlan.zhihu.com/p/62678594

Reflect.apply() 提供了和 Function.prototype.apply() 相同的功能,更容易理解

let result = Reflect.apply(Math.max, Math, [10, 20, 30]);
console.log(result);

// 输出:
// 30

Reflect.apply方法的语法:

Reflect.apply(target, thisArg, args)

定义属性: Reflect.defineProperty()

Reflect.defineProperty() 类似于 Object.defineProperty()。 但是,它返回一个布尔值,用来表示属性是否定义成功,而不是抛出异常:

Reflect.defineProperty(target, propertyName, propertyDescriptor)j

简单的例子:

let person = {
  name: '小帅'
};

if (Reflect.defineProperty(person, 'age', {
  writable: true,
  configurable: true,
  enumerable: false,
  value: 25,
})) {
  console.log(person.age);
} else {
  console.log('age属性定义失败');
}

总结

今天我们学习JavaScript 反射和Reflect API带来的很多反射方法的使用。

如果本文有帮助,微信搜索【小帅的编程笔记】,让我们每天进步

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值