深度揭秘ES6代理Proxy
最近在博客上看到关于ES6代理的文章都是一些关于如何使用Proxy的例子,很少有说明Proxy原理的文章,要知道只有真正掌握了一项技术的原理,才能够写出精妙绝伦的代码,所以我觉得有必要写一篇关于深刻揭露ES6 Proxy的文章。
看完这篇文章你不会学到一些大型的使用Proxy的例子,但是你可以了解以下几方面的内容:
- 你将知道代理是个什么东西
- 你将知道所有代理对象可覆盖的方法
- 一些代理对象使用的小场景
[[GetPrototypeOf]] ( )
获取对象的原型时调用,在执行obj[__proto__]或Object.getPrototypeOf(obj)时调用。
[[SetPrototypeOf]] (V)
设置一个对象的原型时调用,在执行obj.prototype=otherObj或则Object.SetPrototypeOf(v)的时候调用
[[IsExtensible]] ( )
获取对象的可扩展性时调用,执行Object.isExtensible(object)时被调用。
[[GetOwnProperty]] (P)
获取自有属性时调用
- [[PreventExtensions]]()
扩展一个不可扩展的对象时调用
[[DefineOwnProperty]] (P, Desc)
定义自有属性时调用
[[HasProperty]](P)
检测对象是否存在某个属性时调用,如key in obj
[[Get]] (P, Receiver)
获取属性时调用,如obj.key,obj[key]。
[[Set]] ( P, V, Receiver)
为对象的属性赋值时调用,如obj.key=value或obj[key]=value。
[[Delete]] (P)
删除某个属性时调用
[[Enumerate]] ()
列举对象的可枚举属性时调用,如for (var key in obj)。
[[OwnPropertyKeys]] ( )
列举对象的自有属性时调用
- functionObj.[[Call]](thisValue, arguments)
调用一个函数时被调用,functionObj()或者x.method()。
- constructorObj.[[Construct]](arguments, newTarget)
使用new操作的时候调用,如new Date()。
var target = {}, handler = {};
var proxy = new Proxy(target, handler);
target
对象的属性时,就会经过
handler
对象,因此,我们可以通过重写handler对象中的一些方法来做一些拦截的操作。以下是一个简单的代理使用例子。var person = {
name: "Jhon",
age: 23
};
var p = new Proxy(person,{
get: function(target, prop, receiver){
console.log("你访问了person的属性");
return target["name"];
}
});
console.log(p.age);
// 你访问了person的属性
// Jhon
你看,我们虽然访问了age属性,它却输出了额外的字符串和属性name的值,这就是拦截器的作用。
handler.get()
方法用于拦截对象的读取属性操作。var p = new Proxy(target, {
get: function(target, property, receiver) {
}
});
- target,目标对象
- property,被获取的属性名
- receiver,Proxy或者继承Proxy的对象
- 可以返回任何值
- this绑定到handler对象上
TypeError:
- 如果要访问的目标属性是不可写以及不可配置的,则返回的值必须与该目标属性的值相同。
- 如果要访问的目标属性没有配置访问方法,即get方法是undefined的,则返回值必须为undefined。
handler.set()
方法用于拦截设置属性值的操作var p = new Proxy(target, {
set: function(target, property, value, receiver) {
}
});
- target,目标对象
- property,被设置的属性名
- value,被设置的新值
- receiver,最初被调用的对象。通常是proxy本身,但handler的set方法也有可能在原型链上或以其他方式被间接地调用(因此不一定是proxy本身)
- this绑定到handler对象上
- 返回一个布尔值,返回true代表此次设置属性成功了,如果返回false且设置属性操作发生在严格模式下,那么会抛出一个
TypeError
TypeError
:- 若目标属性是不可写及不可配置的,则不能改变它的值
- 如果目标属性没有配置存储方法,即set方法是undefined的,则不能设置它的值
- 在严格模式下,若set方法返回false,则会抛出一个
TypeError
异常
handler.has()
方法可以看作是针对 in
操作的钩子var p = new Proxy(target, {
has: function(target, prop) {
}
});
- targe,t目标对象
- prop,需要检查是否存在的属性
- this绑定到handler对象上
- 返回一个boolean值
- 如果目标对象的某一属性本身不可被配置,则该属性不能够被代理隐藏
- 如果目标对象为不可扩展对象,则该对象的属性不能够被代理隐藏
handler.getPrototypeOf()
是一个代理方法,当读取代理对象的原型时,该方法就会被调用var p = new Proxy(obj, {
getPrototypeOf(target) {
...
}
});
- target,被代理的目标对象
this
指向的是它所属的处理器对象- 必须返回一个对象值或者返回
null
getPrototypeOf()
方法返回的不是对象也不是null
目标对象是不可扩展的,且
getPrototypeOf()
方法返回的原型不是目标对象本身的原型
handler.defineProperty()
用于拦截对对象的 Object.defineProperty()
操作var p = new Proxy(target, {
defineProperty: function(target, property, descriptor) {
}
});
- target,目标对象
- property,待检索其描述的属性名
- descriptor,待定义或修改的属性的描述符
this
绑定在
handler 对象上- 返回一个boolean值
- 如果目标对象不可扩展, 将不能添加属性、
- 不能添加或者修改一个属性为不可配置的,如果它不作为一个目标对象的不可配置的属性存在的话
- 如果目标对象存在一个对应的可配置属性,这个属性可能不会是不可配置的
- 如果一个属性在目标对象中存在对应的属性,那么
Object.defineProperty(target,
将不会抛出异常
prop, descriptor) - 在严格模式下,
false
作为handler.defineProperty
方法的返回值的话将会抛出TypeError
异
handler.deleteProperty()
方法用于拦截对对象属性的 delete
操作var p = new Proxy(target, {
deleteProperty: function(target, property) {
}
});
- target,目标对象
- property,待删除的属性名
this
被绑定在
handler上- 返回一个boolean值
- 如果目标对象的属性是不可配置的,那么该属性不能被删除
handler.setPrototypeOf()
用于拦截对对象的 Object.setPrototypeOf()
操作var p = new Proxy(target, {
setPrototypeOf: function(target, prototype) {
}
});
- target,目标对象
- prototype,待设置的属性名或者null
this
被绑定在
handler上- 返回一个boolean值
- 如果目标对象是不可扩展的,则原型的参数必须和Object.getPrototypeOf(target)相同
handler.getOwnPropertyDescriptor()
用于拦截对对象的 Object.getOwnPropertyDescriptor()
操作var p = new Proxy(target, {
getOwnPropertyDescriptor: function(target, prop) {
}
});
- target,目标对象
- prop,返回属性名的描述符
- this绑定到处理函数
- 必须返回一个 对象 或 u
ndefined
getOwnPropertyDescriptor
必须返回一个 object
或 undefined
如果属性作为目标对象的不可配置的属性存在,则该属性无法报告为不存在
如果属性作为目标对象的属性存在,并且目标对象不可扩展,则该属性无法报告为不存在
如果属性不存在作为目标对象的属性,并且目标对象不可扩展,则不能将其报告为存在
属性不能被报告为不可配置,如果它不作为目标对象的自身属性存在,或者作为目标对象的可配置的属性存在
Object.getOwnPropertyDescriptor(target)的结果可以使用
Object.defineProperty 应用于目标对象,也不会抛出异常
var p = new Proxy(target, {
ownKeys: function(target) {
}
});
- target,目标对象
- this绑定到处理函数
- 返回一个数组
- 返回值必须是一个数组
- 数组的每一个元素必须是字符串或者Symbol
- 数组必须包含目标对象的所有非可配置属性的键
- 如果目标对象不可扩展,则数组必须包含目标对象自身属性的所有键,并且没有其他值
andler.isExtensible()
用于拦截对对象的 Object.isExtensible()
操作var p = new Proxy(target, {
isExtensible: function(target) {
}
});
- target,目标对象
- this绑定到处理函数
- 返回一个boolean值
Object.isExtensible(proxy)
必须返回和Object.isExtensible(target)相同的值
handler.apply()
方法用于拦截函数的调用var p = new Proxy(target, {
apply: function(target, thisArg, argumentsList) {
}
});
- target,目标对象(函数)
- thisArg,被调用时的上下文对象
- argumentsList,被调用时的参数列表
- this绑定到handler对象
- 可以返回任何值
- 无
handler.construct()用于来接new操作
var p = new Proxy(target, {
construct: function(target, argumentsList, newTarget) {
}
});
- target,目标对象
- argumensList,构造器参数列表
- newTarget,最初调用的构造函数
- this绑定到handler
- 返回一个对象
- 返回值必须是一个对象
var p = new Proxy(target, {
preventExtensions: function(target) {
}
});
- target,目标对象
- this绑定到handler对象
- 返回一个boolean值
- Object.isExtensible(proxy)为假,则Object.preventExtensions(proxy)只能返回true
深度揭秘ES6代理Proxy的更多相关文章
- 详解es6中Proxy代理对象的作用
在es6中新添加了Proxy,那么它有什么作用啊?Proxy本意为代理,而es6中的Proxy也就是代理对象,那么代理对象感觉听起来很模糊,在这里就解释一下Proxy代理对象的作用. Proxy的主要 ...
- 代理(Proxy)和反射(Reflection)
前面的话 ES5和ES6致力于为开发者提供JS已有却不可调用的功能.例如在ES5出现以前,JS环境中的对象包含许多不可枚举和不可写的属性,但开发者不能定义自己的不可枚举或不可写属性,于是ES5引入了O ...
- ES6的Proxy
最近在Javascript的设计编程中,用到的那个单例模式,感觉就类似一种代理的思想[其实就是缓存的一种机制],单例模式就是: function getSingle(fn){ var result; ...
- [每日一题]面试官问:谈谈你对ES6的proxy的理解?
[每日一题]面试官问:谈谈你对ES6的proxy的理解? 关注「松宝写代码」,精选好文,每日一题 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...
- Webpack代理proxy配置,解决本地跨域调试问题,同时允许绑定host域名调试
Webpack代理proxy配置,解决本地跨域调试问题,同时允许绑定host域名调试 会撸码的小马 关注 2018.05.29 17:30* 字数 212 阅读 1488评论 0喜欢 2 接到上一章, ...
- 浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance
浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance java.lang.reflect.Proxy:该类用于动态生成代理类,只需传入目标接口.目标接口的类加载器以及Inv ...
- 初识代理——Proxy
无处不在的模式——Proxy 最近在看<设计模式之禅>,看到代理模式这一章的时候,发现自己在写spring项目的时候其实很多时候都用到了代理,无论是依赖注入.AOP还是其他,可以说是无处不 ...
- JAVA设计模式-动态代理(Proxy)示例及说明
在Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析文章的最后部分,我们提到了动态代理的概念,下面我们就简单了解一下动态代理. 一,概念 代理设计模式的目的就是在不直接操作对象的前 ...
- JAVA设计模式-动态代理(Proxy)源码分析
在文章:JAVA设计模式-动态代理(Proxy)示例及说明中,为动态代理设计模式举了一个小小的例子,那么这篇文章就来分析一下源码的实现. 一,Proxy.newProxyInstance方法 @Cal ...
随机推荐
- 关于memcached的那些事儿
一.前言 目前,memcached + mysql的这种存储组合,被广泛地应用到“读多写少”的应用场景上.那么在使用memcached的时候,我们需要注意哪些问题呢? 下面我们来探讨下使用memcac ...
- 深入理解计算机系统chapter1
---恢复内容开始--- 预处理器+编译器+汇编器+链接器=编译系统 运行hello程序 操作系统: 无论是在单核还是多核系统中,一个CPU看上去都在并发的执行多个进程,这是通过处理器在进程间切换来实 ...
- PyTorch教程之Tensors
Tensors类似于numpy的ndarrays,但是可以在GPU上使用来加速计算. 一.Tensors的构建 from __future__ import print_function import ...
- java编程基础复习-------第二章
一.标识符 java中标识符的命名规则: 以数字.字母.下划线和$符号组成:不能用数字开头:不能是java的关键字. 注意:不要用$命名标识符.习惯上,$只用在机器自动产生的源代码中. 二.关键字 1 ...
- 关于select的一个错误---属性选择器
错误: jquery 获取下拉框 text='1'的 option 的value 属性值 我写的var t= $("#selectID option[text='1']).val() ; ...
- TCP/IP 第二章
1, 以太网的封装格式.其中MTU的最小值为46字节,所以,ARP和RARP需要添加18字节的PAD.CRC是检验和.(循环冗余检验) 2,SLIP:(串行线路ip) 首尾一个end字符加以区分数据. ...
- 原创:TSP问题解决方案-----禁忌搜索算法C实现
本文着重于算法的实现,对于理论部分可自行查看有关资料可以简略参考该博文:http://blog.csdn.net/u013007900/article/details/50379135 本文代码部分基 ...
- 一文为你详细讲解对象映射库【AutoMapper】所支持场景
前言 在AutoMapper未出世前,对象与对象之间的映射,我们只能通过手动为每个属性一一赋值,时间长了不仅是我们而且老外也觉得映射代码很无聊啊.这个时候老外的所写的强大映射库AutoMapper横空 ...
- SQL Server 锁机制 悲观锁 乐观锁 实测解析
先引入一些概念,直接Copy其他Blogs中的,我就不单独写了. 一.为什么会有锁 多个用户同时对数据库的并发操作时会带来以下数据不一致的问题: 1.丢失更新 A,B两个用户读同一数据并进行修改,其中 ...
- C语言程序设计第一作业
C语言程序设计第一作业 实验总结 (一) 1.题目:输入圆的半径,求圆周长和面积 2.流程图: 3.测试数据及运行结果: 4.实验分析: 问题1: 出现了错误 原因:是在赋值那写反了 解决方法:应该是 ...