Reflect 对象提供了若干个能对任意对象进行某种特定的可拦截操作(interceptable operation)的方法。
一个全局的对象,虽然首字母是大写的,但是并不表示它是一个构造函数,所以不能用new运算符来初始化“Reflect对象”,它的所有方法都是静态的。有点类似于Math。
对一个函数进行调用操作,关键在于其指定了特定的this对象。使用方法为:
Reflect.apply(fun, target, argvs);
和我们熟知的fun.apply(target,argvs)
效果是一样的,使用Reflect更加简洁易懂。
注意:argvs
必须是数组或者类似数组的对象。
对构造函数进行初始化,类似于new Xxx()
的操作。
var date = Reflect.construct(Date,[2016,7,17]);
等同于
var date = new Date(2016,7,17);
该方法有第三个参数,用于修改new.target
function someConstructor() {}
var result = Reflect.construct(Array, [], someConstructor);
Reflect.getPrototypeOf(result); // 输出:someConstructor.prototype
Array.isArray(result); // true
可以理解把对象的prototype修改成第三个参数的prototype
function Foo(arg){this.name = arg+'foo';}
function Bar(arg){this.age = arg+'bar';}
Bar.prototype.show = function(){
console.log(this.age);
}
var result = Reflect.construct(Foo, ['test'], Bar);
result.age // ?
result.name // ?
result.show() // ?
result.constructor // ?
为对象定义属性和值
var obj = {};
Reflect.defineProperty(obj, "x", {value: 7}); // true
obj.x; // 7
Reflect.defineProperty(obj, "x", {value: 8}); // false
类似于Object.defineProperty()
,但是会有一个boolean
的返回值,表示该值是否被成功定义,而Object.defineProperty()
会返回对象或报错
删除对象的某个属性
var obj = { x: 1, y: 2 };
Reflect.deleteProperty(obj, "x"); // true
obj; // { y: 2 }
类似于delete obj[xx]
,返回boolean
值表示是否删除成功
该方法会返回一个包含有目标对象身上所有可枚举的自身字符串属性以及继承字符串属性的迭代器,for...in 操作遍历到的正是这些属性。
var obj = { x: 1, y: 2 };
for (var name of Reflect.enumerate(obj)) {
console.log(name);
}
注意:已弃用
获取对象身上某个属性的值。
// Object
var obj = { x: 1, y: 2 };
Reflect.get(obj, "x"); // 1
// Array
Reflect.get(["zero", "one"], 1); // "one"
类似于我们经常使用的获取对象属性的target[name]
设置对象身上某个属性的值。
// Object
var obj = {};
Reflect.set(obj, "prop", "value"); // true
obj.prop; // "value"
// Array
var arr = ["duck", "duck", "duck"];
Reflect.set(arr, 2, "goose"); // true
arr[2]; // "goose"
// 参数只有一个的时候,并不会报错,但是key和value都是undefined
var obj = {};
Reflect.set(obj); // true
Reflect.getOwnPropertyDescriptor(obj, "undefined");
// { value: undefined, writable: true, enumerable: true, configurable: true }
类似于target.name = xxx;
返回对象中属性的描述,如果对象中不存在该属性的话,返回undefined
Reflect.getOwnPropertyDescriptor({x: "hello"}, "x");
// {value: "hello", writable: true, enumerable: true, configurable: true}
类似于Object.getOwnPropertyDescriptor()
获取一个对象原型上的属性
Reflect.getPrototypeOf({}); // Object.prototype
var date = new Date();
Reflect.getPrototypeOf(date) === Date.prototype; // true
类似于Object.getPrototypeOf()
设置对象的原型属性或置空
Reflect.setPrototypeOf({}, Object.prototype); // true
// Returns false if target is not extensible.
Reflect.setPrototypeOf(Object.freeze({}), null); // false
类似于Object.setPrototypeOf()
判断一个对象是否存在某个属性,和 in
运算符 的功能完全相同。
Reflect.has({x: 0}, "x"); // true
Reflect.has({x: 0}, "y"); // false
判断一个对象是否是可扩展的,即是否可以增加新的属性。
var empty = {};
Reflect.isExtensible(empty); // === true
Reflect.preventExtensions(empty);
Reflect.isExtensible(empty); // === false
var sealed = Object.seal({});
Reflect.isExtensible(sealed); // === false
var frozen = Object.freeze({});
Reflect.isExtensible(frozen); // === false
类似于Object.isExtensible()
,但是有一点点不同,Reflect.isExtensible
的第一个参数必须是对象,否则会报错,而Object.isExtensible()
并没有这个限制。
Reflect.isExtensible(1);
// TypeError: 1 is not an object
Object.isExtensible(1);
// false
不允许再在对象上新增属性值。用法见Reflect.isExtensible
。
类似于Object.preventExtensions
,但是也有不同点,即必须传递对象参数。
返回一个包含所有自身属性(不包含继承属性)的数组。
Reflect.ownKeys({z: 3, y: 2, x: 1});
// [ "z", "y", "x" ]
Reflect.ownKeys([]); // ["length"]
var sym = Symbol.for("comet");
var sym2 = Symbol.for("meteor");
var obj = {[sym]: 0, "str": 0, "773": 0, "0": 0,
[sym2]: 0, "-1": 0, "8": 0, "second str": 0};
Reflect.ownKeys(obj);
// [ "0", "8", "773", "str", "-1", "second str", Symbol(comet), Symbol(meteor) ]
类似于Object.getOwnPropertyNames
,但是更加强大,相当于
Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)).
Reflect比较简单,并没有特别新的东西,只是对原来就有的内容做了些修改(貌似是的)。这样设计的目的是什么?
Object
对象的一些明显属于语言内部的方法(比如Object.defineProperty
),放到Reflect
对象上。现阶段,某些方法同时在Object
和Reflect
对象上部署,未来的新方法将只部署在Reflect
对象上。修改某些Object
方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)
在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)
则会返回false
。
// 老写法
try {
Object.defineProperty(target, property, attributes);
// success
} catch (e) {
// failure
}
// 新写法
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}
函数化。让Object
操作都变成函数行为。某些Object
操作是命令式,比如name in obj
和delete obj[name]
,而Reflect.has(obj, name)
和Reflect.deleteProperty(obj, name)
让它们变成了函数行为。
Reflect
对象的方法与Proxy
对象的方法一一对应,只要是Proxy
对象的方法,就能在Reflect
对象上找到对应的方法。这就让Proxy
对象可以方便地调用对应的Reflect
方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy
怎么修改默认行为,你总可以在Reflect
上获取默认行为。
有了Reflect
对象以后,很多操作会更易读。
// 老写法
Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1
// 新写法
Reflect.apply(Math.floor, undefined, [1.75]) // 1