ES6新特性:Javascript中的Reflect对象
Reflect介绍:
Reflect这个对象在我的node(v4.4.3)中还没有实现, babel(6.7.7)也没有实现 ,新版本的chrome是支持的, ff比较早就支持Proxy和Reflect了,要让node支持Reflect可以安装harmony-reflect ;
Reflect不是构造函数, 要使用的时候直接通过Reflect.method()调用, Reflect有的方法和Proxy差不多, 而且多数Reflect方法原生的Object已经重新实现了。
什么要使用Reflect
这里列举几个为什么要使用Reflect的原因, 译文地址:Reflect , 大概翻译了一遍:
1:更加有用的返回值: Reflect有一些方法和ES5中Object方法一样样的, 比如: Reflect.getOwnPropertyDescriptor和Reflect.defineProperty, 不过, Object.defineProperty(obj, name, desc)执行成功会返回obj, 以及其它原因导致的错误, Reflect.defineProperty只会返回false或者true来表示对象的属性是否设置上了, 如下代码可以重构:
try {Object.defineProperty(obj, name, desc);// property defined successfully } catch (e) {// possible failure (and might accidentally catch the wrong exception) }
重构成这样:
if (Reflect.defineProperty(obj, name, desc)) {// success } else {// failure }
其余的方法, 比如Relect.set , Reflect.deleteProperty, Reflect.preventExtensions, Reflect.setPrototypeOf, 都可以进行重构;
2:函数操作, 如果要判断一个obj有定义或者继承了属性name, 在ES5中这样判断:name in obj ; 或者删除一个属性 :delete obj[name], 虽然这些很好用, 很简短, 很明确, 但是要使用的时候也要封装成一个类;
有了Reflect, 它帮你封装好了, Reflect.has(obj, name), Reflect.deleteProperty(obj, name);
3:更加可靠的函数式执行方式: 在ES中, 要执行一个函数f,并给它传一组参数args, 还要绑定this的话, 要这么写:
f.apply(obj, args)
但是f的apply可能被重新定义成用户自己的apply了,所以还是这样写比较靠谱:
Function.prototype.apply.call(f, obj, args)
上面这段代码太长了, 而且不好懂, 有了Reflect, 我们可以更短更简洁明了:
Reflect.apply(f, obj, args)
4:可变参数形式的构造函数: 想象一下, 你想通过不确定长度的参数实例化一个构造函数, 在ES5中, 我们可以使用扩展符号, 可以这么写:
var obj = new F(...args)
不过在ES5中, 不支持扩展符啊, 所以, 我们只能用F.apply,或者F.call的方式传不同的参数, 可惜F是一个构造函数, 这个就坑爹了, 不过有了Reflect, 我们在ES5中能够这么写:
var obj = Reflect.construct(F, args)
5:控制访问器或者读取器的this: 在ES5中, 想要读取一个元素的属性或者设置属性要这样:
var name = ... // get property name as a string obj[name] // generic property lookup obj[name] = value // generic property update
Reflect.get和Reflect.set方法允许我们做同样的事情, 而且他增加了一个额外的参数reciver, 允许我们设置对象的setter和getter的上下this:
var name = ... // get property name as a string Reflect.get(obj, name, wrapper) // if obj[name] is an accessor, it gets run with `this === wrapper` Reflect.set(obj, name, value, wrapper)
访问器中不想使用自己的方法,而是想要重定向this到wrapper:
var obj = {set foo(value) { return this.bar(); },bar: function() {alert(1);} }; var wrapper = {bar : function() {console.log("wrapper");} } Reflect.set(obj, "foo", "value", wrapper);
6:避免直接访问 __proto__ : ES5提供了 Object.getPrototypeOf(obj),去访问对象的原型, ES6提供也提供了Reflect.getPrototypeOf(obj)
和 Reflect.setPrototypeOf(obj, newProto), 这个是新的方法去访问和设置对象的原型:
Reflect.apply的使用
Reflect.apply其实就是ES5中的 Function.prototype.apply() 替身, 执行Reflect.apply需要三个参数
第一个参数为: 需要执行的函数;
第二个参数为: 需要执行函数的上下文this;
第三个参数为: 是一个数组或者伪数组, 会作为执行函数的参数;
<script> let fn = function() {this.attr = [0,1,2,3]; }; let obj = {}; Reflect.apply(fn, obj, []) console.log(obj); </script>
Reflect.apply的DEMO:
<script> Reflect.apply(Math.floor, undefined, [1.75]); // 输出:1; Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]); // 输出:"hello" Reflect.apply(RegExp.prototype.exec, /ab/, ["confabulation"]).index; //输出: 4 Reflect.apply("".charAt, "ponies", [3]); // 输出:"i" </script>
Reflect可以与Proxy联合使用:
{var Fn = function(){};Fn.prototype.run = function() {console.log( "runs out" );};var ProxyFn = new Proxy(Fn, {construct (target ,arugments) {console.log("proxy constructor");var obj = new target(...arugments);//Reflect.apply的使用方法; Reflect.apply(target.prototype.run, obj, arugments);return obj;}});new ProxyFn (); //会先输出: "proxy constructor" ; 再输出: runs out }
Reflect.construct()的使用:
Reflect.construct其实就是实例化构造函数,通过传参形式的实现, 执行的方式不同, 效果其实一样, construct的第一个参数为构造函数, 第二个参数由参数组成的数组或者伪数组, 基本的使用方法为:
var Fn = function(arg) {this.args = [arg] }; console.log( new Fn(1), Reflect.construct(Fn,[1]) ); // 输出是一样的var d = Reflect.construct(Date, [1776, 6, 4]); d instanceof Date; // true d.getFullYear(); // 1776 //所以Reflect.consturct和new 构
所以Reflect.consturct和new 构造函数是一样, 至少到目前为止..
我们可以给Reflect.construct传第三个参数 , 第三个参数为一个超类, 新元素会继承这个超类;
<script> function someConstructor() {} var result = Reflect.construct(Array, [], someConstructor); Reflect.getPrototypeOf(result); // someConstructor.prototype Array.isArray(result); // true //or var Fn = function() {this.attr = [1]; }; var Person = function() { }; Person.prototype.run = function() { }; console.log( Reflect.construct(Fn, [], Person) ); </script>
所以我们可以用这个实现一个特殊的的数组, 继承数组, 但是也有自己的方法;
var Fn = function() {Array.apply(this, arguments);this.shot = ()=> {console.log("heheda");}; }; var arr = Reflect.construct(Fn, [])
Reflect.defineProperty的使用;
Reflect.defineProperty返回的是一个布尔值, 通过直接赋值的方式把属性和属性值添加给对象返回的是一整个对象, 如果添加失败会抛错;
var obj = {}; obj.x = 10; console.log(obj.x) //输出:10;
使用Reflect.defineProperty的方式添加值;
<script> var obj = {}; if( Reflect.defineProperty(obj, "x", {value : 7 }) ) {console.log("added success"); }else{console.log("添加失败"); }; </script>
如果我们执行preventExtensions, 通过Object.defindProperty定义新属性报错了, 但是通过Reflect.defineProperty没有报错, 返回了一个false的值:
var obj = {}; Object.preventExtensions(obj); Object.defineProperty(obj, "x" , {value: 101,writable: false,enumerable: false,configurable: false });// 直接抛错了; console.log( Reflect.defineProperty(obj, "x", {value:101}) ) //返回false:
如果通过直接赋值的方式, 无论是否正确赋值, 都返回设置的值, 除非我们手动确认对象的属性值是否设置成功;
<script> var obj = {}; Object.preventExtensions(obj); console.log( obj.aa = 1 ); //输出:1; console.log(obj.aa) //输出:undefined; </script>
Reflect.deleteProperty的使用:
Reflect.deleteProperty和Reflect.defineProperty的使用方法差不多, Reflect.deleteProperty和 delete obj.xx的操作结果是一样, 区别是使用形式不同:一个是操作符,一个是函数调用;
Reflect.deleteProperty(Object.freeze({foo: 1}), "foo"); // false delete Object.freeze({foo: 1}).foo; //输出:false;
Reflect.get()方法的使用;
这个方法的有两个必须的参数: 第一个为obj目标对象, 第二个为属性名对象, 第三个是可选的,是作为读取器的上下文(this);
var obj = {}; obj.foo = 1; console.log( obj.foo ); //输出:1; console.log( Reflect.get(obj, "foo") ) //输出:1;
如果Reflect.get有第三个参数的话, 第三个参数会作为读取器的上下文:
var Reflect = require('harmony-reflect');var obj = {"foo" : 1,get bar() {return this.foo;} }; var foo = {}; foo.foo = "heheda"; console.log(Reflect.get(obj, "bar", foo));
Reflect.getOwnPropertyDescritptor()方法的使用:
通过Reflect.getOwnPropertyDescritptor获取属性描述:
Reflect.getOwnPropertyDescriptor({x: "hello"}, "x"); //也可以这样获取: Object.getOwnPropertyDescriptor({x:"1"},"x"); //这两个的区别是一个会包装对象, 一个不会: Reflect.getOwnPropertyDescriptor("hello",0); //抛出异常 Object.getOwnPropertyDescriptor("hello",0); //输出: {value: "h", writable: false, enumerable: true, configurable: false}
Reflect.getPrototypeOf()方法的使用:
Reflect.getPrototypeOf和Object.getPrototypeOf是一样的, 他们都是返回一个对象的原型
Reflect.getPrototypeOf({}); // 输出:Object.prototype Reflect.getPrototypeOf(Object.prototype); // 输出:null Reflect.getPrototypeOf(Object.create(null)); // 输出: null
Reflect.has的使用
Reflect.has这个方法有点像操作符:in , 比如这样: xx in obj;
<script> Reflect.has({x:0}, "x") //输出: true; Reflect.has({y:0}, "y") //输出:true
; var obj = {x:0}; console.log( "x" in obj); var proxy = new Proxy(obj, { has : function(target, args) { console.log("执行has方法"); return Reflect.has(target,...args); } }); console.log( "x" in proxy); //输出:true; console.log(Reflect.has(proxy, "x")) //输出:true; </script>
这个demo的obj相当于变成了一个方法了, 没他什么用 , 只是利用了他的has方法:
obj = new Proxy({}, {has(t, k) { return k.startsWith("door"); } }); Reflect.has(obj, "doorbell"); // true Reflect.has(obj, "dormitory"); // false
Reflect.isExtensible()的使用
// 现在这个元素是可以扩展的; var empty = {}; Reflect.isExtensible(empty); // === true// 使用preventExtensions方法, 让这个对象无法扩展新属性; Reflect.preventExtensions(empty); Reflect.isExtensible(empty); // === false// 这个对象无法扩展新属性, 可写的属性依然可以改动 var sealed = Object.seal({}); Reflect.isExtensible(sealed); // === false// 这个对象完全被冻结了 var frozen = Object.freeze({}); Reflect.isExtensible(frozen); // === false
Reflect.isExtensible和Object.isExtensible的区别是, 如果参数不对,一个会抛错, 另一个只是返回true或者false:
Reflect.isExtensible(1); // 抛错了: 1 is not an object Object.isExtensible(1); // 返回false;
Reflect.ownKeys()方法的使用:
Reflect.ownKeys, Object可没有ownKeys方法, Reflect.ownKeysz他的作用是返回对象的keys;
console.log(Reflect.ownKeys({"a":0,"b":1,"c":2,"d":3})); //输出 :["a", "b", "c", "d"] console.log(Reflect.ownKeys([])); // ["length"] var sym = Symbol.for("comet"); var sym2 = Symbol.for("meteor"); var obj = {[sym]: 0, "str": 0, "773": 0, "0": 0,[sym2]: 0, "-1": 0, "8": 0, "second str": 0}; Reflect.ownKeys(obj); //输出:/ [ "0", "8", "773", "str", "-1", "second str", Symbol(comet), Symbol(meteor) ]
Reflect.ownKeys的排序是根据: 先显示数字, 数字根据大小排序,然后是 字符串根据插入的顺序排序, 最后是symbol类型的key也根据插入插入顺序排序;
出现这中排序是因为,你给一个对象属性赋值时候, 对象的key的排序规则就是先数字, 在字符串, 最后是symbol类型的数据;
Reflect.preventExtensions()的使用方法:
Object也有preventExtensions方法, 和Reflect.preventExtensions()有一点区别, 如果Reflect.preventExtensions参数不是对象会抛错;
var empty = {}; Reflect.isExtensible(empty); // === true// 执行preventExtensions后的对象可以修改; Reflect.preventExtensions(empty); Reflect.isExtensible(empty); // === false Reflect.preventExtensions(1); // TypeError: 1 is not an object Object.preventExtensions(1); //不会抛错, 会返回:1
Reflect.set()
Reflect.set方法和get是差不多的;
var obj = {}; Reflect.set(obj, "prop", "value"); // 输出:true console.log( obj.prop ); // 输出:"value"var arr = ["duck", "duck", "duck"]; Reflect.set(arr, 2, "goose"); // true console.log( arr[2] ); // "goose" Reflect.set(arr, "length", 1); // true console.log( arr );// ["duck"];
Reflect.set(obj)相当于 Reflect.set(obj, undefined, undefined);
var obj = {}; Reflect.set(obj); // 输出:true //以上的代码相当于 Reflect.set(obj, undefined, undefined); Reflect.getOwnPropertyDescriptor(obj, "undefined"); // { value: undefined, writable: true, enumerable: true, configurable: true }
Reflect.set也可以有第四个参数, 这个参数会作为stter的this;
var obj = {value : 10,set key( value ) {console.log("setter");this.value = value;},get key() {return this.value;} }; Reflect.set(obj,"key","heheda", obj); console.log(obj);
Reflect.setPrototypeOf()
Reflect.setPrototypeOf()方法和Object.setPrototypeOf差不多一样样的, 会给对象设置原型, 就是更改对象的__proto__属性了...;
Reflect.setPrototypeOf({}, Object.prototype); // 输出true// 给该对象数组[[Prototype]] 为null. Reflect.setPrototypeOf({}, null); // true // 此时的obj.__proto__为undefine//把对象冻结以后重新设置[[prototype]] Reflect.setPrototypeOf(Object.freeze({}), null); // false// 如果原型链循环依赖的话就会返回false. var target = {}; var proto = Object.create(target); Reflect.setPrototypeOf(target, proto); // false
参考:
MDN:mdn: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect
让node环境支持Proxy和Reflect:https://github.com/tvcutsem/harmony-reflect/
作者: NONO
出处:http://www.cnblogs.com/diligenceday/
QQ:287101329
微信:18101055830
ES6新特性:Javascript中的Reflect对象相关推荐
- ES6新特性(中)——ES6的集合(set集合、map集合等)
这里写目录标题 ES6的集合 一.Set集合 1.操作方法 2.遍历方法: 二.WeakSet集合 1.概念理解 2.方法: 3.WeakSet 的应用场景/好处 三.Map集合 1.概念理解 2.属 ...
- ES6新特性_ES6中模块暴露数据语法汇总---JavaScript_ECMAScript_ES6-ES11新特性工作笔记043
上一节说了,在浏览器中使用es6的模块化,来引用js, 上面是之前我们写的这个 m1.js文件 可以看到我们在我们想暴露的,变量或者 函数前面加上了一个 export 关键字 然后我们通过 <s ...
- ES6新特性_ES6中Map的介绍与API---JavaScript_ECMAScript_ES6-ES11新特性工作笔记032
ES6中的map,真的是太灵活了,比起java来说,很灵活了. 可以看到介绍 首先我们创建一个map,名字是m然后 我们添加一个元素,name,尚硅谷,name是key,尚硅谷是value 打印一下右 ...
- javascript中的Reflect对象是什么?如何使用Reflect?
JavaScript是一种非常流行的编程语言,广泛用于web开发.服务器端开发.移动应用开发等领域.在JavaScript中,Reflect对象是一个重要的内置对象,提供了一些实用的方法,可以用于实现 ...
- lsdyna如何设置set中的node_list_如何快速掌握es6+新特性及核心语法?
国庆刚刚结束,我们开始一波新的学习进程吧. ECMAScript 6.0(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了.作为前端必备技能,我们来快速开始吧 接 ...
- es6 获取对象的所有值_前端开发必备 - ES6 新特性之 Set和Map数据结构
往期回顾: 前端开发必备 - ES6 新特性之 let 和 const 命令 前端开发必备 - ES6 新特性之 变量的解构赋值 前端开发必备 - ES6 新特性之 字符串的拓展 前端开发必备 - E ...
- javascript ES6 新特性之 扩展运算符 三个点 ...
对于 ES6 新特性中的 ... 可以简单的理解为下面一句话就可以了: 对象中的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中. 作用类似于 Object.assign() ...
- 尚硅谷es6新特性笔记
尚硅谷es6新特性笔记 一.let与const let的变量声明以及声明特性 const的变量声明以及声明特性 const.let.var 三者之间的区别 二.变量解构赋值 三.模板字符串 四.对象的 ...
- ES6新特性(部分语法)
ES6新特性 文章目录 ES6新特性 1.0let关键字 1.1let小案例 1.2const关键字 1.3解构赋值 1.4模板字符串 1.5简化对象写法 1.6箭头函数 1.7箭头函数的案例 1.7 ...
最新文章
- Dwr 框架简单实例
- php array 关联数组,php array_merge关联数组
- 人脸检测-- Face R-FCN + Face R-CNN
- 《javascript设计模式》笔记之第十章 和 第十一章:门面模式和适配器模式
- 分页请求json数据_pyspider抓取虎嗅网文章数据
- zcmu1862(模拟)
- TCP协议属性设置之SO_LINGER属性
- Confluence 6 修改日志文件的大小数量和级别
- php限制上传类型,php 上传类型限制的简单示例
- Nginx配置HTTP2.0 1
- 来,说说什么是运维人的情怀?
- wojilu框架代码分析之ActionProcessor.Process()
- When Startup Disk is Full
- @Trasactional 事务解读
- oracle 多表去重sql语句,去重语句
- 在x64上构建智能家居(home assistant) (一) Supervised版本安装
- cv2.imshow无法正常显示图片,而是一闪而过解决办法
- java学习day10(Java基础)特殊类
- python中 f代表什么_python 中下拉框中的f,v,m是什么意思??
- 计算机组装硬件要求,组装电脑必懂的硬件知识,全是干货,教你选购硬件不求人...
热门文章
- 1. Action 实现 ModelDriven 接口后的运行流程
- 电脑b站html加速播放,b站投稿如何提高播放速度?如何2倍速?b站播放器选择倍速快捷方式...
- Windows下Wireshark安装版本选择方式
- Xamarin iOS教程之添加和定制视图
- 以计算机为主题的英语作文范例,myfamily英语作文范文示例
- tinyxml 内存泄露_有关TinyXML使用的简单总结
- 三步快删EXCEL工作表下面出现1000多万行无用数据或者空白行(空值行)
- eeglab教程系列(7)-数据叠加平均{1}(Data averaging)
- 脑电数据分析工具汇总
- DIY混合BCI刺激系统:SSVEP-P300 LED刺激