阅读目录

Reflect对象是一个全局的普通的对象。Reflect的原型就是Object.

我们首先来验证下 看看Reflect的原型是否是Object, 基本代码如下:

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。

比如 旧的写法如下:

try {
Object.defineProperty(target, property, attributes);
} catch(e) {
// 失败
} // 新写法
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}

等等这些考虑,所以就新增了这个静态对象。

Reflect对象一共有13个静态方法。

一: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); // // ES5的语法如下: const min2 = Math.min.apply(arrs, arrs);
console.log(min2); // // 或者我们使用 Finction.prototype 代码如下演示 const min3 = Function.prototype.apply.call(Math.min, arrs, arrs);
console.log(min3); // // 下面是截取字符串的方法演示下 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); //
console.log(yyyy.age); // undefined
console.log(yyyy instanceof YYYY); // true
console.log(yyyy instanceof XXXX); // false
console.log(yyyy.getAge()); //

如上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

深入理解 ES6中的 Reflect的更多相关文章

  1. 前端知识体系:JavaScript基础-原型和原型链-理解 es6 中class构造以及继承的底层实现原理

    理解 es6 中class构造以及继承的底层实现原理 原文链接:https://blog.csdn.net/qq_34149805/article/details/86105123 1.ES6 cla ...

  2. 理解ES6中的Symbol

    一.为什么ES6引入Symbol 有时候我们在项目开发的过程中可能会遇到这样的问题,我写了一个对象,而另外的同时则在这个对象里面添加了一个属性或是方法,倘若添加的这个属性或是方法是原本的对象中本来就有 ...

  3. 【JS】325- 深度理解ES6中的解构赋值

    点击上方"前端自习课"关注,学习起来~ 对象和数组时 Javascript 中最常用的两种数据结构,由于 JSON 数据格式的普及,二者已经成为 Javascript 语言中特别重 ...

  4. 理解ES6中的Iterator

    一.为什么使用Iterator 我们知道,在ES6中新增了很多的特性,包括Map,Set等新的数据结构,算上数组和对象已经有四种数据集合了,就像数组可以使用forEach,对象可以使用for...in ...

  5. 理解ES6中的Promise

    一.Promise的作用 在ajax请求数据的过程中,我们可以异步拿到我们想要的数据,然后在回调中做相应的数据处理. 这样做看上去并没有什么麻烦,但是如果这个时候,我们还需要做另外一个ajax请求,这 ...

  6. 理解es6 中 arrow function的this

    箭头函数相当于定义时候,普通函数.bind(this)箭头函数根本没有自己的this,导致内部的this就是定义时候的外层代码块中的this.外层代码块中的this,则取决于执行时候环境上下文cont ...

  7. 理解es6中的const与“不变”

    const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动. 效果 对于简单类型的数据(数值.字符串.布尔值),值就保存在变量指向的那个内存地址,因此等同于常量. 对于复合类型 ...

  8. 深入理解es6中的Promise

    https://www.jianshu.com/p/9e4af5b77253 https://zhuanlan.zhihu.com/p/30797777 https://segmentfault.co ...

  9. ES6中的元编程-Proxy & Reflect

    前言 ES6已经出来好久了,但是工作中比较常用的只有let const声明,通过箭头函数改this指向,使用promise + async 解决异步编程,还有些数据类型方法...所以单独写一篇文章学习 ...

随机推荐

  1. 洛谷P3209 [HNOI2010]PLANAR(2-SAT)

    题目描述 若能将无向图G=(V,E)画在平面上使得任意两条无重合顶点的边不相交,则称G是平面图.判定一个图是否为平面图的问题是图论中的一个重要问题.现在假设你要判定的是一类特殊的图,图中存在一个包含所 ...

  2. Java NIO 学习

    Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(B ...

  3. 在“非软件企业”开发软件的困局 ZT

    软件产品广泛服务于各行业,其开发具有高科技.高投入.高产出.高风险的特点.在项目开发和软件应用中,只有将人员能力的发挥与科学技术的使用应用市场的认识进行最佳的融合,才能发挥软件的效益.普通企业虽涉足软 ...

  4. python 标准类库-并行执行之subprocess-子进程管理

    标准类库-并行执行之subprocess-子进程管理 by:授客QQ:1033553122 1.使用subprocess模块 以下函数是调用子进程的推荐方法,所有使用场景它们都能处理.也可用Popen ...

  5. tornado 模板引擎

    在tornado的模板引擎中,有两种方式,UImethod与UImodule 自定义方法 在模板中调用方法: tornado:与Django一样使用{{}},但是对于for循环之类,Django以{% ...

  6. 【爬虫】在使用xpath时,排除指定标签

    xpath排除某个节点 主要时应用name()这个函数获取便签名 res = html.xpath("//*[name(.)!='style']")

  7. git 入门教程之撤销更改

    撤销更改 相信你已经了解了 git 的基本概念,也清楚了工作区,暂存区和版本库的关系,现在让我们用所学的知识继解决实际问题吧! 背景 正常看得见的目录是我们最为熟悉的工作区,在工作中不可能总是100% ...

  8. pyHook和pythoncom的安装

    pyHook包为Windows中的全局鼠标和键盘事件提供回调.Python应用程序为用户输入事件注册事件处理程序,例如鼠标左键,鼠标左键,按键等,并设置键盘和/或鼠标挂钩.底层C库报告的信息包括事件的 ...

  9. linux:644、755、777权限详解

    第一位7等于4+2+1,rwx,所有者具有读取.写入.执行权限: 第二位5等于4+1+0,r-x,同组用户具有读取.执行权限但没有写入权限: 第三位5,同上,也是r-x,其他用户具有读取.执行权限但没 ...

  10. 自动化测试基础篇--Selenium浏览器操作

    摘自https://www.cnblogs.com/sanzangTst/p/7462056.html  学习 Selenium 主要提供的是操作页面上各种元素的方法,但它也提供了操作浏览器本身的方法 ...