深入理解 ES6中的 Reflect用法


Posted in Javascript onJuly 18, 2020

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); // 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

如下图所示:

深入理解 ES6中的 Reflect用法

// 使用 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. 如下图所示:

深入理解 ES6中的 Reflect用法

五: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://3water.com/article/191097.htm)。

因此总结一下:如果使用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));

打印 如下图所示:

深入理解 ES6中的 Reflect用法

十三: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用法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery插件 cluetip 关键词注释
Jan 12 Javascript
JavaScript toFixed() 方法
Apr 15 Javascript
JQuery中getJSON的使用方法
Dec 13 Javascript
javascript实现跳转菜单的具体方法
Jul 05 Javascript
两种方法基于jQuery实现IE浏览器兼容placeholder效果
Oct 14 Javascript
JavaScript设计模式学习之“类式继承”
Mar 12 Javascript
javascript检测移动设备横竖屏
May 21 Javascript
vue自定义全局组件(自定义插件)的用法
Jan 30 Javascript
vue.js,ajax渲染页面的实例
Feb 11 Javascript
jsonp格式前端发送和后台接受写法的代码详解
Nov 07 Javascript
JS实现旋转木马轮播图
Jan 01 Javascript
javascript设计模式 ? 组合模式原理与应用实例分析
Apr 14 Javascript
详谈Object.defineProperty 及实现数据双向绑定
Jul 18 #Javascript
webpack+vue-cil 中proxyTable配置接口地址代理操作
Jul 18 #Javascript
Vue项目前后端联调(使用proxyTable实现跨域方式)
Jul 18 #Javascript
完美解决通过IP地址访问VUE项目的问题
Jul 18 #Javascript
Vue移动端项目实现使用手机预览调试操作
Jul 18 #Javascript
vue中移动端调取本地的复制的文本方式
Jul 18 #Javascript
vue中用 async/await 来处理异步操作
Jul 18 #Javascript
You might like
php出现Cannot modify header information问题的解决方法大全
2008/04/09 PHP
解析PHP中的file_get_contents获取远程页面乱码的问题
2013/06/25 PHP
利用php+mcDropdown实现文件路径可在下拉框选择
2013/08/07 PHP
php使用PDO方法详解
2014/12/27 PHP
PHP中key和current,next的联合运用实例分析
2016/03/29 PHP
php实现在线通讯录功能(附源码)
2016/05/13 PHP
Javascript优化技巧(文件瘦身篇)
2008/01/28 Javascript
IE的事件传递-event.cancelBubble示例介绍
2014/01/12 Javascript
jQuery Trim去除字符串首尾空字符的实现方法说明
2014/02/11 Javascript
举例讲解JavaScript中将数组元素转换为字符串的方法
2015/10/25 Javascript
jQuery焦点图轮播效果实现方法
2016/12/19 Javascript
Jquery鼠标放上去显示全名的实现方法
2017/02/06 Javascript
详解angularJs指令的3种绑定策略
2017/04/13 Javascript
深入浅析angular和vue还有jquery的区别
2018/08/13 jQuery
详解微信图片防盗链“此图片来自微信公众平台 未经允许不得引用”的解决方案
2019/04/04 Javascript
基于JS实现table导出Excel并保留样式
2020/05/19 Javascript
jquery+ajax实现异步上传文件显示进度条
2020/08/17 jQuery
完美解决Pycharm无法导入包的问题 Unresolved reference
2018/05/18 Python
Python3最长回文子串算法示例
2019/03/04 Python
python跳出双层for循环的解决方法
2019/06/24 Python
opencv 图像礼帽和图像黑帽的实现
2020/07/07 Python
Python调用SMTP服务自动发送Email的实现步骤
2021/02/07 Python
福克斯租车:Fox Rent A Car
2017/04/13 全球购物
JACK & JONES英国官方网站:欧洲领先的男装生产商
2017/09/27 全球购物
Expedia法国:全球最大在线旅游公司
2018/09/30 全球购物
Topshop美国官网:英国快速时尚品牌
2019/05/16 全球购物
Foot Locker澳洲官网:美国运动服和鞋类零售商
2019/10/11 全球购物
哈萨克斯坦最大的时装、鞋子和配饰在线商店:Lamoda.kz
2019/11/19 全球购物
英国礼品和生活方式品牌:Treat Republic
2020/11/21 全球购物
Roxy俄罗斯官方网站:冲浪和滑雪板的一切
2020/06/20 全球购物
Java面试题:为什么要用Java
2012/05/11 面试题
运动会广播稿200字
2014/01/15 职场文书
天猫某品牌专卖店运营计划书
2014/03/21 职场文书
《少年王冕》教学反思
2014/04/11 职场文书
农林经济管理专业自荐信
2014/09/01 职场文书
2015年文秘个人工作总结
2015/10/14 职场文书