深入理解 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 相关文章推荐
JS代码优化技巧之通俗版(减少js体积)
Dec 23 Javascript
jQuery选择器全面总结
Jan 06 Javascript
IE6已终止操作问题的2种情况及解决
Apr 23 Javascript
JavaScript中的全局对象介绍
Jan 01 Javascript
浅谈轻量级js模板引擎simplite
Feb 13 Javascript
Vuex2.0+Vue2.0构建备忘录应用实践
Nov 30 Javascript
Angularjs的键盘事件的绑定
Jul 27 Javascript
Three.js利用dat.GUI如何简化试验流程详解
Sep 26 Javascript
小程序实现多选框功能
Oct 30 Javascript
Vue项目History模式404问题解决方法
Oct 31 Javascript
Vue模板语法中数据绑定的实例代码
May 17 Javascript
JavaScript语句错误throw、try及catch实例解析
Aug 18 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 网页过期时间的控制代码
2009/06/29 PHP
使用PHP免费发送定时短信的实例
2016/10/24 PHP
javascript 单选框,多选框美化代码
2008/08/01 Javascript
javascript 按回车键相应按钮提交事件
2009/11/02 Javascript
jQuery 表格插件整理
2010/04/27 Javascript
jQuery 阴影插件代码分享
2012/01/09 Javascript
结合JQ1.9通过js正则判断各种浏览器版本的方法
2013/12/30 Javascript
JQuery EasyUI 数字格式化处理示例
2014/05/05 Javascript
js调试系列 控制台命令行API使用方法
2014/06/18 Javascript
jQuery+ajax实现无刷新级联菜单示例
2015/05/21 Javascript
jQuery实现类似淘宝网图片放大效果的方法
2015/07/08 Javascript
详解Vue.js——60分钟组件快速入门(上篇)
2016/12/05 Javascript
Javascript blur与click冲突解决办法
2017/01/09 Javascript
AngularJS+bootstrap实现动态选择商品功能示例
2017/05/17 Javascript
原生javascript实现的全屏滚动功能示例
2017/09/19 Javascript
ionic2中使用自动生成器的方法
2018/03/04 Javascript
微信小程序实现文字跑马灯
2020/05/26 Javascript
Vue.js中该如何自己维护路由跳转记录
2019/05/19 Javascript
解决webpack多页面内存溢出的方法示例
2019/10/08 Javascript
微信小程序一周时间表功能实现
2019/10/17 Javascript
React组件设计模式之组合组件应用实例分析
2020/04/29 Javascript
Vue如何基于vue-i18n实现多国语言兼容
2020/07/17 Javascript
vue实现广告栏上下滚动效果
2020/11/26 Vue.js
python实现类似ftp传输文件的网络程序示例
2014/04/08 Python
Python生成随机密码
2015/03/10 Python
Python中分数的相关使用教程
2015/03/30 Python
python Django框架实现自定义表单提交
2016/03/25 Python
python Popen 获取输出,等待运行完成示例
2019/12/30 Python
Python unittest 自动识别并执行测试用例方式
2020/03/09 Python
VSCode中autopep8无法运行问题解决方案(提示Error: Command failed,usage)
2021/03/02 Python
CSS3中background-clip和background-origin的区别示例介绍
2014/03/10 HTML / CSS
HTML5实现锚点时请使用id取代name
2013/09/06 HTML / CSS
举例详解HTML5中使用JSON格式提交表单
2015/06/16 HTML / CSS
法国发饰品牌:Alexandre De Paris
2018/12/04 全球购物
C#中有没有静态构造函数,如果有是做什么用的?
2016/06/04 面试题
班级聚会策划书
2014/01/16 职场文书