阅读目录

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. JS中的柯里化(currying)

    何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名). 柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参 ...

  2. jQuery 对AMD的支持(Require.js中如何使用jQuery)

    AMD 模块 AMD(异步模块定义,Asynchronous Module Definition)格式总体的目标是为现在的开发者提供一个可用的模块化 JavaScript 的解决方案. AMD 模块格 ...

  3. Jump Flood Algorithms for Centroidal Voronoi Tessellation

    Brief Implemented both CPU and GPU version, you could consider this as the basic playground to imple ...

  4. The value of ESP was not properly saved across a function call 快速解决

    The value of ESP was not properly...快速解决 今天遇到这个问题,真的是非常头疼,期间电脑居然崩掉一次.所以,分享一下解决办法. 如果是:类定义的时候,新添加了属性, ...

  5. Redis常用命令【列表】

    一.简介 基于Linked List实现,元素是字符串类型,列表头尾增删快,中间增删慢,增删元素是常态. 元素可以重复出现,最多包含2^32-1个元素. 二.命令 1.说明 1.1 B block 块 ...

  6. SQL Server中如何识别、查找未使用的索引(unused indexes)

    在SQL Server中,索引是优化SQL性能的一大法宝.但是由于各种原因,索引会被当做"银弹"滥用,一方面有些开发人员(甚至是部分数据库管理员)有一些陋习,不管三七二十一,总是根 ...

  7. SQL语句(floor、ceiling和round以及left和right)

    前言:个人认为命令没有必要记,学过的知识总结一下,用到了可以快速找到派上用场.用的多了,自然会记住,但是一定要理解每一个字符代表的是什么,多一个少一个会怎么样 要点概述 floor 和ceiling和 ...

  8. 第八章 Hyper-V 2012 R2 故障转移群集

    和终端用户相比,企业用户对于业务的连续性和可靠性更为在意.相对而言,企业一般不会将追逐单一硬件的性能排在第一位. 如何衡量业务是否持续可用,一般使用"x 个 9"这种方式来定义.如 ...

  9. AI学习---深度学习&TensorFlow安装

    深度学习   深度学习学习目标: 1. TensorFlow框架的使用 2. 数据读取(解决大数据下的IO操作) + 神经网络基础 3. 卷积神经网络的学习 + 验证码识别的案例   机器学习与深度学 ...

  10. centos7 下安装Apache2+MariaDB+PHP5过程详解

    1.启用Apache2 Centos7默认已经安装httpd服务,只是没有启动.如果你需要全新安装,可以 yum install -y httpd 启动服务:systemctl start httpd ...