阅读目录html
Reflect对象是一个全局的普通的对象。Reflect的原型就是Object.数组
咱们首先来验证下 看看Reflect的原型是不是Object, 基本代码以下:app
let obj = {}; console.log(Reflect.__proto__ === Object.prototype); // true console.log(obj.__proto__ === Reflect.__proto__); // true let str = '111'; console.log(str.__proto__); // String {"", length: 0, constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, …}
Reflect是ES6为了操做对象而新增的API, 为何要添加Reflect对象呢?它这样设计的目的是为了什么?函数
1)将Object对象的一些明显属于语言内部的方法(好比Object.defineProperty),放到Reflect对象上,那么之后咱们就能够从Reflect对象上能够拿到语言内部的方法。测试
2)在使用对象的 Object.defineProperty(obj, name, {})时,若是出现异常的话,会抛出一个错误,须要使用try catch去捕获,可是使用 Reflect.defineProperty(obj, name, desc) 则会返回false。this
好比 旧的写法以下:es5
try { Object.defineProperty(target, property, attributes); } catch(e) { // 失败 } // 新写法 if (Reflect.defineProperty(target, property, attributes)) { // success } else { // failure }
等等这些考虑,因此就新增了这个静态对象。spa
Reflect对象一共有13个静态方法。prototype
一:Reflect.get(target, name, receiver)设计
该方法是用来读取一个对象的属性。
参数以下解析:
target: 目标对象
name: 是咱们要读取的属性。
receiver(可选): 能够理解为上下文this对象。
先看以下demo来理解下 Reflect中的get方法的使用以下:
const obj = { name: 'kongzhi', age: 30, get xxx() { console.log(this.name); console.log('-------'); } }; console.log(Reflect.get(obj, 'name')); // kongzhi console.log(Reflect.get(obj, 'yyy')); // undefined /* 先执行 xxx 方法 打印 kongzhi 和 ----, 而后在打印undefined, 由于该xxx()函数没有返回值 */ console.log(Reflect.get(obj, 'xxx')); /* 会执行 xxx() 方法,打印 happy, 所以第三个参数指向上下文 就指向了这个对象,而后打印 ----- ,最后打印undefined 由于该函数没有返回值 */ console.log(Reflect.get(obj, 'xxx', {name: 'happy'})); /* 会执行 xxx() 方法,打印 undefined, 所以第三个参数指向上下文 就指向了这个对象,而这个对象里面又没有name属性,所以会打印undefined 而后打印 ----- ,最后打印undefined. 由于该函数没有返回值 */ console.log(Reflect.get(obj, 'xxx', {age: 'happy'})); const obj2 = { name: 'kongzhi2', age: 30, get xxx() { console.log(this.name); console.log('----xxxx---'); return 0; } }; /* 先执行 obj2 该对象中的 xxx 方法,指定了第三个参数做为该上下文对象, 所以会打印 happy2, 而后继续打印 ----xxxx---, 最后咱们能够看到 有返回值为0,所以打印0了 */ console.log(Reflect.get(obj2, 'xxx', {name: 'happy2'}));
二:Reflect.set(target,name,value,receiver)
上面的get方法是获取对象中的值,那么set就是设置该对象的属性值了,参数解析简单以下:
target: 咱们须要操做的对象。
name: 咱们须要设置该对象的属性名。
value: 咱们要设置的属性值。
receiver: 能够理解为上下文this对象。若是咱们在设置值的时候遇到setter函数,该参数就指向与setter中上下文this对象。
该函数会返回一个Boolean的值,表明在目标对象上设置属性是否成功。
以下代码演示:
const obj = { age: 30, set name(name) { console.log(this); console.log('-------'); } }; const res = Reflect.set(obj, 'age', 31); console.log(res); // true console.log(obj); // {age: 31, set name:function} 这样的 console.log(obj.age); // 打印 31 /* 以下代码,设置 obj对象中的name属性,所以打印 console.log(this) 返回 {age: 31, set name:function} 这样的, console.log(res2)返回true,设置成功 */ const res2 = Reflect.set(obj, 'name', 'xxxx'); console.log(res2); // true /* 先执行 set 中的name方法,打印 console.log(this);this就指向了第四个参数 {test: 'test'} 而后会打印 '-----'; */ const r2 = Reflect.set(obj, 'name', 'dreamapple', {test: 'test'}); // this: --> { test: 'test' } console.log(r2); // true console.log(obj); // { name: [Setter], age: 31 }
三:Reflect.apply(target,thisArg,args)
该方法的含义是:经过指定的参数列表对该目标函数的调用。该方法相似于咱们以前的 Function.prototype.apply 方法的。
参数解析以下:
target: 咱们的目标函数.
thisArg: target函数调用的时候绑定的this对象。
args: 就是函数参数列表。
以下代码demo演示:
// 查找数组里面最小的元素值 const arrs = [1, 2, 3, 4]; // ES6 的语法以下 const min = Reflect.apply(Math.min, arrs, arrs); console.log(min); // 1 // ES5的语法以下: const min2 = Math.min.apply(arrs, arrs); console.log(min2); // 1 // 或者咱们使用 Finction.prototype 代码以下演示 const min3 = Function.prototype.apply.call(Math.min, arrs, arrs); console.log(min3); // 1 // 下面是截取字符串的方法演示下 const strs = 'kongzhi'; // 使用ES6的语法 代码演示以下: const str1 = Reflect.apply(String.prototype.slice, strs, [0, 3]); console.log(str1); // 打印 kon // 使用 ES5的语法 const str2 = strs.slice(0, 3); console.log(str2); // 打印 kon // 或者咱们使用 String.prototype 代码以下演示 const str3 = String.prototype.slice.apply(strs, [0, 3]); console.log(str3); // kon
四:Reflect.construct(target,args[, newTarget])
该方法的做用和 new AAA() 建立一个实列方法做用相似,那么使用该方法,咱们就能够提供一种不使用new来调用构造函数的方法,
参数含义以下:
target: 被运行的目标函数。
args: 调用构造函数传递的参数数组或伪数组。
newTarget: 也是构造函数,表示使用 Reflect.construct后生成的实列对象是谁的实列。若是没有该参数,默认生成的实列对象就和target构造函数是同样的。
代码演示以下:
function XXXX(name) { this.name = name; } XXXX.prototype.getName = function() { return this.name; } function YYYY(age) { this.age = age; } YYYY.prototype.getAge = function() { return this.age || 31; } // 使用 XXXX函数做为构造函数, 那么构造函数就指向了 XXXX函数 const xxxx = Reflect.construct(XXXX, ['xx']); console.log(xxxx); // 打印 XXXX {name: xx} console.log(xxxx.getName()); // 打印 xx
以下图所示:
// 使用 YYYY 函数做为构造函数,那么构造函数就指向了 YYYY函数 const yyyy = Reflect.construct(XXXX, ['30'], YYYY); console.log(yyyy); // 打印 YYYY {name: 30} console.log(yyyy.name); // 30 console.log(yyyy.age); // undefined console.log(yyyy instanceof YYYY); // true console.log(yyyy instanceof XXXX); // false console.log(yyyy.getAge()); // 31
如上demo所示:当const xxxx = Reflect.construct(XXXX, ['xx']); 没有第三个参数的时候,那么构造函数指向了 XXXX 函数。
咱们继续看第二个demo,const yyyy = Reflect.construct(XXXX, ['30'], YYYY); 有第三个参数,所以 yyyy的实列指向了 YYYY.
如上代码打印的信息看到 console.log(yyyy instanceof YYYY); 返回true, console.log(yyyy instanceof XXXX); 返回false.
可是呢 console.log(yyyy.getAge()); 返回的是 31. 若是咱们没有默认的 31值的话,那么就应该返回undefined了,能够看到,请看下面的注意总结:
注意:若是有第三个参数的话,那么咱们的实列由两部分组成,实列的属性部分由第一部分构造函数生成。实列的方法由第三个参数对象生成。
好比上面打印的 console.log(yyyy); // 打印 YYYY {name: 30} 看到只返回了 XXXX中的name属性,XXXX中的getName方法并无拿到。
同理如上 console.log(yyyy.age); 为undefined, console.log(yyyy.getAge()); 返回了31. 以下图所示:
五:Reflect.defineProperty(target,name,desc)
该方法与Object.defineProperty方法相似的,不过惟一的区别是 Reflect.defineProperty返回值是一个Boolean的值。
好比以下基本的代码比较:
const obj = {}; // 使用 Object.defineProperty try { Object.defineProperty(obj, 'a', { value: 22 }) } catch(e) { console.log('define property failed'); } // 使用 Reflect.defineProperty const res = Reflect.defineProperty(obj, 'b', { configurable: true, enumerable: true }); console.log(res); // true
既然二者的用法是同样的,那配置项也是同样的,那这边就很少介绍了,只是返回值不同而已,那么Object.defineProperty 的具体用法,
请看我上一篇文章(https://www.cnblogs.com/tugenhua0707/p/10261170.html)。
所以总结一下:若是使用Object.defineProperty的属性定义失败了,就会抛出一个错误,成功的话就会返回这个对象;
Reflect.defineProperty若是定义属性失败的话就会返回false,若是成功定义的话,就会返回true。
可是若是使用Reflect.defineProperty函数,它的第一个参数不是对象的话,也会抛出错误。
六:Reflect.deleteProperty(target,name)
该方法用于删除一个对象上的属性,它和delete操做符相似的。
参数以下:
target: 表示要操做的对象。
name: 表示要删除该对象上的属性。
该函数返回值是一个Boolean的值,若是成功的话,返回true,失败的话返回false。好比以下demo演示:
const obj = { name: 'kongzhi', age: 30 }; let test1 = Reflect.deleteProperty(obj, 'name'); console.log(test1); // true console.log(obj); // {age: 30} // 若是删除对象上不存在的属性的话,也是返回true的 let test2 = Reflect.deleteProperty(obj, 'xx'); console.log(test2); // true console.log(obj); // {age: 30} let test3 = Reflect.deleteProperty(obj, 'age'); console.log(test3); // true console.log(obj); // {}
七:Reflect.has(target,name)
该方法的含义是:检查一个对象上是否含有特定的属性。至关于es5中的in操做符。
那么参数 target: 就是改对象哦,name的含义是:该对象上的属性。
具体的demo演示以下:
// 通常的对象 const obj = { name: 'kongzhi', age: 30 }; console.log(Reflect.has(obj, 'name')); // true console.log(Reflect.has(obj, 'username')); // 该对象上没有 username属性 返回false console.log(Reflect.has(obj, 'age')); // true // 函数的实列 function Obj(name) { this.name = name; } Obj.prototype.getName = function() { return this.name; } const test = new Obj(); // 使用in操做符测试 console.log('name' in test); // true console.log('getName' in test); // true // 使用Reflect.has 测试 console.log(Reflect.has(test, 'name')); // true console.log(Reflect.has(test, 'getName')); // true
八:Reflect.ownKeys(target)
该函数的做用是:返回由目标对象自身的属性键组成的数组。若是这个目标对象不是一个对象的话,那么该函数就会抛出一个异常。
target参数:它是一个对象。以下代码演示:
const obj = { name: 'kongzhi', age: 30 }; console.log(Reflect.ownKeys(obj)); // ['name', 'age'];
九:Reflect.preventExtensions(target)
该方法的做用是 阻止新的属性添加到对象中去。target参数必须是一个对象,不然的话会抛出一个异常。
以下代码演示:
const obj = {}; // 判断该对象是否能够扩展,使用 Reflect.isExtensible 该方法 const t1 = Reflect.isExtensible(obj); console.log(t1); // true // 使用 Reflect.preventExtensions 来阻止该对象扩展 Reflect.preventExtensions(obj); // 再来扩展下该对象,看是否能够 const t2 = Reflect.isExtensible(obj); console.log(t2); // false
十:Reflect.isExtensible(target)
该方法的做用是检查一个对象是否能够扩展的,也就是说对象里面是否能够添加新的属性或方法。
target参数表示目标对象。若是该目标对象不是一个对象的话,那么函数会抛出一个异常。
该函数会返回一个Boolean值,若是为true的话,说明该对象能够扩展,不然的话返回false,表示该对象不能够扩展。
以下demo来演示下:
const obj = {}; // 判断该对象是否能够扩展,使用 Reflect.isExtensible 该方法 const t1 = Reflect.isExtensible(obj); console.log(t1); // true // 使用 Reflect.preventExtensions 来阻止该对象扩展 Reflect.preventExtensions(obj); // 再来扩展下该对象,看是否能够 const t2 = Reflect.isExtensible(obj); console.log(t2); // false
十一:Reflect.getOwnPropertyDescriptor(target, name)
该方法的参数以下解析:
target: 表示的是目标对象。
name: 表示目标对象的属性
该方法的具体含义是:若是目标对象中的属性描述符存在的话,就返回这个属性描述符,若是不存在,就返回undefined。
以下demo演示:
const obj = {}; Reflect.defineProperty(obj, 'name', { configurable: true, enumerable: true, writable: true, value: '30' }); const test1 = Reflect.getOwnPropertyDescriptor(obj, 'name'); /* 打印值以下: { configurable: true enumerable: true value: "30" writable: true } */ console.log(test1); const test2 = Reflect.getOwnPropertyDescriptor(obj, 'age'); console.log(test2); // undefined // 若是第一个参数不是对象 const test3 = Object.getOwnPropertyDescriptor('kkkk', 'name'); console.log(test3); // undefined // 使用 try catch 包围,会执行 catch方法内部代码 try { const test4 = Reflect.getOwnPropertyDescriptor('kkkk', 'name'); console.log(test4); } catch (e) { console.log('error'); }
十二:Reflect.getPrototypeOf(target)
该方法是返回一个对象的原型的,也就是说内部的 [[Prototype]] 属性的值。来看以下代码:
function testA() {}; testA.prototype.xxx = function() {}; const a = new testA(); console.log(Object.getPrototypeOf(a));
打印 以下图所示:
十三:Reflect.setPrototypeOf(target, prototype)
该方法的做用是设置一个对象的原型。若是设置成功的话,这个对象就返回一个true,若是设置失败的话,这个对象就返回一个false。
好比以下代码:
const obj = {}; const test1 = Reflect.setPrototypeOf(obj, Object.prototype); console.log(test1); // true let test2 = Reflect.setPrototypeOf(Object.freeze({}), null); console.log(test2); // false