今天我们来学习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
不是构造函数,不能使用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()
方法类似于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带来的很多反射方法的使用。
如果本文有帮助,微信搜索【小帅的编程笔记】,让我们每天进步