es6 Reflect对象详解
Reflect是ES6为操作对象而提供的新API,而这个API设计的目的只要有:
- 将Object对象的一些属于语言内部的方法放到Reflect对象上,从Reflect上能拿到语言内部的方法。如:Object.defineProperty
- 修改某些object方法返回的结果。如:Object.defineProperty(obj, name, desc)在无法定义属性的时候会报错,而Reflect.defineProperty(obj, name, desc)则会返回false
- 让Object的操作都变成函数行为。如object的命令式:name in obj和delete obj[name] 则与 Reflect.has(obj, name)、Reflect.deleteProperty(obj, name)相等
- Reflect对象的方法与Proxy对象的方法一一对应,只要proxy对象上有的方法reflect也能找到。
Proxy(target, {
set: function(target, name, value, receiver) {
var success = Reflect.set(target,name, value, receiver);
if (success) {
log('property ' + name + ' on ' + target + ' set to ' + value);
}
return success;
}
});
var loggedObj = new Proxy(obj, {
get(target, name) {
console.log('get', target, name);
return Reflect.get(target, name);
},
deleteProperty(target, name) {
console.log('delete' + name);
return Reflect.deleteProperty(target, name);
},
has(target, name) {
console.log('has' + name);
return Reflect.has(target, name);
}
});
有了Reflect对象,很多操作会更易读
// 老写法
Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1 // 新写法
Reflect.apply(Math.floor, undefined, [1.75]) //
Reflect一共有13个静态方法
Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)
上面这些方法的作用大部分与Object对象的同名方法都是相同的,与Proxy对象的方法一一对应的。
Reflect.get(target, name, receiver)
Reflect.get方法查找并返回target的name属性,如果没有,则返回undefined。
var myObject = {
foo: 1,
bar: 2,
get baz() {
return this.foo + this.bar;
},
}
Reflect.get(myObject, 'foo') //
Reflect.get(myObject, 'bar') //
Reflect.get(myObject, 'baz') //
如果name属性部署了读取函数(getter),则读取函数的this绑定的receiver。
var myObject = {
foo: 1,
bar: 2,
get baz() {
return this.foo + this.bar;
},
};
var myReceiverObject = {
foo: 4,
bar: 4,
};
Reflect.get(myObject, 'baz', myReceiverObject) //
如果第一个参数不是对象,则Reflect.get则会报错。
Reflect.set(target, name, value, receiver)
Reflect.set方法设置target对象的name属性等于value。
var myObject = {
foo: 1,
set bar(value) {
return this.foo = value;
},
}
myObject.foo //
Reflect.set(myObject, 'foo', 2);
myObject.foo //
Reflect.set(myObject, 'bar', 3)
myObject.foo //
如果name属性设置的赋值函数,则赋值函数的this绑定receiver。
var myObject = {
foo: 4,
set bar(value) {
return this.foo = value;
},
};
var myReceiverObject = {
foo: 0,
};
Reflect.set(myObject, 'bar', 1, myReceiverObject);
myObject.foo //
myReceiverObject.foo //
如果Proxy与Reflect联合使用,前者完成拦截赋值操作,后者完成赋值默认行为,而且传入了receiver,则Reflect.set会触发Proxy.defineProperty拦截。
let p = {
a: 'a'
};
let handler = {
set(target, key, value, receiver) {
console.log('set');
Reflect.set(target, key, value, receiver)
},
defineProperty(target, key, attribute) {
console.log('defineProperty');
Reflect.defineProperty(target, key, attribute);
}
};
let obj = new Proxy(p, handler);
obj.a = 'A';
// set
// defineProperty
如果不传,则Proxy不会触发defineProperty拦截。
let p = {
a: 'a'
};
let handler = {
set(target, key, value, receiver) {
console.log('set');
Reflect.set(target, key, value)
},
defineProperty(target, key, attribute) {
console.log('defineProperty');
Reflect.defineProperty(target, key, attribute);
}
};
let obj = new Proxy(p, handler);
obj.a = 'A';
// set
如果第一个参数不是对象,则Reflect.set会报错。
Reflect.has(obj, name)
Reflect.has对应 name in obj 里面的in操作
var myObject = {
foo: 1,
};
// 旧写法
'foo' in myObject // true
// 新写法
Reflect.has(myObject, 'foo') // true
如果第一个参数不是对象,Reflect.has和in都会报错。
Reflect.deleteProperty(obj, name)
Reflect.deleteProperty方法等同于delete obj[name],用于删除对象属性。
const myObj = { foo: 'bar' };
// 旧写法
delete myObj.foo;
// 新写法
Reflect.deleteProperty(myObj, 'foo');
该方法返回一个布尔值。如果删除成功或删除的属性不存在,则返回true,如果删除失败,删除的属性依然还在,则返回false。
Reflect.construct(target, args)
Reflect.construct方法等同于new target(...args),这提供了一种不使用new,来调用构造函数的方法。
function Greeting(name) {
this.name = name;
}
// new 的写法
const instance = new Greeting('张三');
// Reflect.construct 的写法
const instance = Reflect.construct(Greeting, ['张三']);
Reflect.getPrototypeOf(obj)
Reflect.getPrototypeOf方法用读取对象的__proto__属性,对应Object.getPrototypeOf(obj)方法。
const myObj = new FancyThing(); // 旧写法
Object.getPrototypeOf(myObj) === FancyThing.prototype; // 新写法
Reflect.getPrototypeOf(myObj) === FancyThing.prototype;
它们的区别是,如果参数不是对象,Object.getPrototypeOf会将参数转化为对象,而Reflect.getPrototypeOf会报错。
Reflect.setPrototypeOf(obj, newProto)
Reflect.setPrototypeOf方法是设置对象的__proto__属性,返回第一个参数对象,对应Object.setPrototypeOf(obj, newProto
const myObj = new FancyThing(); // 旧写法
Object.setPrototypeOf(myObj, OtherThing.prototype); // 新写法
Reflect.setPrototypeOf(myObj, OtherThing.prototype);
如果第一个参数不是对象,Object.setPrototypeOf会返回第一个参数对象,而Reflect.setPrototypeOf会报错。
如果第一个参数是undefined或null,则两个都会报错。
Reflect.apply(func, thisArgs, args)
Reflect.apply等同于Function.prototype.apply.call(func, thisArgs, args),用于绑定this对象后执行给定函数。
一般来说,如果要绑定一个函数的this对象,可以写成这样fn.apply(obj, args),但是如果函数定义了自己的apply方法就只能写成Function.prototype.apply.call(fn, obj, args),采用Reflect简化这种操作
const ages = [11, 33, 12, 54, 18, 96]; // 旧写法
const youngest = Math.min.apply(Math, ages);
const oldest = Math.max.apply(Math, ages);
const type = Object.prototype.toString.call(youngest); // 新写法
const youngest = Reflect.apply(Math.min, Math, ages);
const oldest = Reflect.apply(Math.max, Math, ages);
const type = Reflect.apply(Object.prototype.toString, youngest, []);
Reflect.defineProperty(target, propertyKey, attributes)
Reflect.defineProperty等同于Object.defineProperty,用来为对象定义属性。未来后者会被逐渐废除。
function MyDate() {
/*…*/
}
// 旧写法
Object.defineProperty(MyDate, 'now', {
value: () => Date.now()
});
// 新写法
Reflect.defineProperty(MyDate, 'now', {
value: () => Date.now()
});
如果第一个参数不是对象,就会抛出错误信息。
该方法配合Proxy.defineProperty使用:
const p = new Proxy({}, {
defineProperty(target, prop, descriptor) {
console.log(descriptor);
return Reflect.defineProperty(target, prop, descriptor);
}
});
p.foo = 'bar';
// {value: "bar", writable: true, enumerable: true, configurable: true}
p.foo // "bar"
上面代码中,Proxy.defineProperty对属性赋值设置了拦截,Reflect.defineProperty完成了赋值。
Reflect.getOwnPropertyDescriptor(target, propertyKey)
Reflect.getOwnPropertyDescriptor方法等同于Object.getOwnPropertyDescriptor,用于得到指定属性的描述对象,将来会代替后者。
var myObject = {};
Object.defineProperty(myObject, 'hidden', {
value: true,
enumerable: false,
});
// 旧写法
var theDescriptor = Object.getOwnPropertyDescriptor(myObject, 'hidden');
// 新写法
var theDescriptor = Reflect.getOwnPropertyDescriptor(myObject, 'hidden');
如果第一个参数不是对象Object.getOwnPropertyDescriptor不报错,返回undefined,而Reflect.getOwnPropertyDescriptor会报错,表示参数非法。
Reflect.isExtensible (target)
Reflect.isExtensible等同于Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展。
const myObject = {};
// 旧写法
Object.isExtensible(myObject) // true
// 新写法
Reflect.isExtensible(myObject) // true
如果参数不是对象,Object.isExtensible会返回false,因为本来就是不可扩展的,而Reflect.isExtensible则报错。
Reflect.preventExtensions(target)
Reflect.preventExtensions等同于Object.preventExtensions,用于让一个对象变为不可扩展,返回一个布尔值,表示是否操作成功。
var myObject = {};
// 旧写法
Object.preventExtensions(myObject) // Object {}
// 新写法
Reflect.preventExtensions(myObject) // true
如果参数不是对象,Object.preventExtensions在ES5下会报错,ES6下会返回传入的值,Reflect.preventExtensions则会报错。
Reflect.ownKeys (target)
Reflect.ownKeys方法用于返回对象的所有属性,等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和。
var myObject = {
foo: 1,
bar: 2,
[Symbol.for('baz')]: 3,
[Symbol.for('bing')]: 4,
};
// 旧写法
Object.getOwnPropertyNames(myObject)
// ['foo', 'bar']
Object.getOwnPropertySymbols(myObject)
//[Symbol(baz), Symbol(bing)]
// 新写法
Reflect.ownKeys(myObject)
// ['foo', 'bar', Symbol(baz), Symbol(bing)]
实例:使用Proxy实现观察者模式
观察者模式(Obsever mode)指的是函数自动观察数据变化,一旦对象有变化,函数会自动执行。
const person = observable({
name: '张三',
age: 20
});
function print() {
console.log(`${person.name}, ${person.age}`)
}
observe(print);
person.name = '李四';
// 输出
// 李四, 20
上面代码中,数据对象person是观察目标,函数print是观察者,一旦person变化,print则自动执行。
下面使用Proxy写一个最简单的观察者模式,即实现observable和observe这两个函数。思路observable函数返回一个原始对象Proxy代理,拦截赋值操作,c触发充当观察者的各个函数。
const queuedObservers = new Set(); const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {set}); function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
queuedObservers.forEach(observer => observer());
return result;
}
上面代码中,先定义一个set集合,所有观察者函数都放进这个集合。然后,observable函数返回原始对象的代理,拦截赋值操作。拦截函数set中,会自动执行所有观察者。
原文链接:http://es6.ruanyifeng.com/#docs/reflect
es6 Reflect对象详解的更多相关文章
- es6 Proxy对象详解
Proxy用于修改某些操作的默认行为,也可以理解为在目标对象之前架设一层拦截,外部所有的访问都必须先通过这层拦截,因此提供了一种机制,可以对外部的访问进行过滤和修改.这个词的原理为代理,在这里可以表示 ...
- js对象详解(JavaScript对象深度剖析,深度理解js对象)
js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...
- JavaScript进阶知识点——函数和对象详解
JavaScript进阶知识点--函数和对象详解 我们在上期内容中学习了JavaScript的基本知识点,今天让我们更加深入地了解JavaScript JavaScript函数 JavaScript函 ...
- jQuery的deferred对象详解
jQuery的deferred对象详解请猛击下面的链接 http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_ ...
- Window 对象详解 转自 http://blog.csdn.net/jcx5083761/article/details/41243697
详解HTML中的window对象和document对象 标签: HTMLwindowdocument 2014-11-18 11:03 5884人阅读 评论(0) 收藏 举报 分类: HTML& ...
- jQuery的deferred对象详解(转载)
本文转载自: jQuery的deferred对象详解(转载)
- mvc-servlet---ServletConfig与ServletContext对象详解(转载)
ServletConfig与ServletContext对象详解 一.ServletConfig对象 在Servlet的配置文件中,可以使用一个或多个<init-param>标签为s ...
- JS中的event 对象详解
JS中的event 对象详解 JS的event对象 Event属性和方法:1. type:事件的类型,如onlick中的click:2. srcElement/target:事件源,就是发生事件的 ...
- JavaWeb学习----JSP内置对象详解
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
随机推荐
- vue2.0路由写法、传参和嵌套
前置知识请戳这里 vue-routerCDN地址:https://unpkg.com/vue-router@3.0.1/dist/vue-router.js vue-router下载地址:https: ...
- DevExpress中 TreeList控件的常规配置
//以下为TreeList控件样式相关设置 this.treelist_SystemCfg.BackColor = Color.Transparent; this.treelist_SystemCfg ...
- request.getRequestDispatcher().forward(request.response)
request.getRequestDispatcher().forward(request.response)中的那两个参数是哪里来的? 2010-11-09 23:13 QQ357169111 | ...
- 【Leetcode】【Medium】Triangle
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent n ...
- zookeeper 的监控工具
zookeeper 的监控工具 公司很多产品会使用zookeeper,比如Meta消息中间件,在测试的过程中,我们经常需要查询zookeeper里面的信息来精确定位问题.目前项目中有开 ...
- 根据ip抓 包
tcpdump -i any -s 0 host 101.81.134.53 -c 1000 -w ./zhj.cap
- centos无法用password登录,只能用public key的解决办法
如上图只能用public key登录,只是我在17年申请的阿里云免费体验半年的服务器上遇到的, 那么我们用阿里云后台的远程连接按钮进入服务器,进入后 就看/etc/ssh/sshd_config文件配 ...
- JavaScript的DOM_其他的扩展
一.呈现模式 从 IE6 开始开始区分标准模式和混杂模式(怪异模式),主要是看文档的声明. IE 为document 对象添加了一个名为 compatMode 属性,这个属性可以识别 IE 浏览器的文 ...
- 使用ViewPager和FragmentPagerAdapter实现Tab
前面我们分别利用ViewPager和Fragment实现了Tab效果.但是使用Fragment实现的Tab不能够左右滑动.如果我们既想使用Fragment又想让Tab能够滑动,那么怎么办呢?这 就是今 ...
- C 语言实现多态的原理:函数指针
C语言实现多态的原理:函数指针 何为函数指针?答案:C Programming Language. 能够查阅下,从原理上来讲,就是一个内存地址.跳过去运行相应的代码段. 既然如此,在运行时决定跳到哪个 ...