摘要:在中构造器的典型特点就是首字母大写,我们通过原对象代理列表格式去创建对象创建的这个对象我们称之为代理对象。就是原对象是当前的属性名是代理对象。理解为明星的经理人消极怠工原封不动地转告外界的信息给明星本身。但是要注意与是两个不同的对象。
ES6之Proxy
proxy的中文有代理的意思。在其他的程序设计语言中这个单词也具有类似的含义。
它是什么Proxy是一个构造器。在js中构造器的典型特点就是首字母大写,我们通过new Proxy(原对象,{代理列表})格式去创建对象,创建的这个对象我们称之为代理对象。
即:
代理对象 = new Proxy(原对象,{代理列表})
之所以要额外产生这么一个代理对象,好处在于可以保持原对象不变,在代理对象中添加新的功能,或者是改造某些功能。而这个原对象则可以在适当的时机回滚回去。可以与设计模式中的代理模式对比理解。
使用格式var obj; var proxyObj = new Proxy(obj, { 对obj的操作1: 函数1, 对obj的操作2: 函数2, ... })入门示例 Proxy的基本示范
var obj = {name:"fan",age:34} console.info(obj.name) var proxyObj = new Proxy(obj,{ get:function(target,key,receiver){console.info(target,key,receiver); return "no"} }) console.info(proxyObj.name) console.info(proxyObj.abc)
解释如下:
proxxy对象是在obj对象的基础之上创建的一个新对象。
proxyObj.name是要去获取proxy对象的name属性。.操作符会自动去调用get()方法。这一点非常重要,在js中,对象是属性的无序集合。对象只有属性,其他什么都没有. 而我们经常说的调用对象的某个方法:例如数组对象arr的sort方法:arr.sort(),这里的sort也是arr对象的属性(更严谨一点,sort是arr.__proto__这个对象的属性),与length属性相比,sort属性的属性值是一个函数,所以在它的后面加()来执行这个函数,而length属性的值是一个数值,所以不需要加()就可以直接使用。再次强调一下:对象的.操作,会自动去调用get。当然,我们平时使用.操作时,是没有感知到这一点的。
在new Proxy的第二个参数中,明确设置了get的方法:当访问proxyObj的任意属性时,输出target,key,receiver的值,并统一返回no。所以proxyObj.name和proxyObj.abc都会得到no。
写到这里你会觉得原对象与代理对象之间有什么关系呢?为什么叫代理呢?
理解代理的作用代理对象可以理解为明星的经纪人。
外界 <----> 原对象; 外界 <----> 代理对象 <------> 原对象;
还以上面的代码为例,改进一下需求:如果有人问obj的名字,就直接告诉对方; 如果有人问obj的年龄,就返回小5岁的年龄。
var obj = {name:"fan",age:34} console.info(obj.age) // 34 var proxyObj = new Proxy(obj,{ get:function(target,key,receiver){ console.info(target === obj); //true console.info(receiver === proxyObj); //true if("age" === key){ return target[key] - 5; } else{ return target[key] } } }) console.info(proxyObj.age) // 34- 5 = 29
解释如下:
get函数中的三个参数:target,key,receiver。 target就是原对象j,keys是当前的属性名;receiver是代理对象。你可以在get方法中做任意的自定义的处理。
代理对象与原对象的关系var arr = [2,1] var proxyArr = new Proxy(arr,{} ) proxyArr.push(3); console.info(arr) // [2,1,3] console.info(arr === proxyArr) // false arr.sort(); console.info(proxyArr[0]) // 1
以上代码中,这个代理对象并没有做任何的特殊操作。理解为明星的经理人消极怠工:原封不动地转告外界的信息给明星本身。所以在proxyArr上做到操作会直接影响到arr上。
同理,在arr上的操作,也会影响proxyArr。
但是要注意:proxyArr与arr是两个不同的对象:arr !== proxyArr。
你可能会想一想:为什么proxyArr能够直接使用push这个方法呢?原因是:
proxyArr.__proto__ === arr.__proto__ === Array.prototype
前一个等式成立的原因是由new Proxy的基因决定的:原对象被代理了嘛。
代理列表在new Proxy的第二个参数中,可以设置的代理属性如下:
var proxyObj = new Proxy(obj, { get: function(tagert,key,receiver){}, set: function(tagert,key,receiver){}, has: function(tagert,key){}, deleteProperty: function(tagert,key){}, ownKeys: function(tagert){}, getOwnPropertyDescriptor: function(tagert,key){}, defineProperty: function(tagert,key,desc){}, preventExtensions: function(tagert){}, getPrototypeOf: function(tagert){}, isExtensible: function(tagert){}, setPrototypeof: function(tagert,proto){}, apply: function(tagert,obj,args){}, construct: function(tagert,args){}, })get() 代理的应用 允许数组下标是负值
在js中,数组的有效下表是从0开始的。
var arr = [1,2,3]; console.info(arr[0]) // 1 console.info(arr[-1]) // undefined console.info(arr[100]) // undefined
值得注意的是,下表越界或者是负值的情况下,得到的结果是undefined,而不是报错。
下面我们希望数组可以取负值下表,规则如下:
-n表示倒数第n个元素。例如:-1表示倒数第一个元素。
使用Proxy解决如下:
var arr = [1,2,3]; var proxyArr = new Proxy(arr,{ get: (target,prop)=>{ let index = Number(prop); if(index < 0){ prop = target.length + index; } return target[prop]; } }) console.info(arr[-1]); // undefined console.info(proxyArr[-1]); // 3
注意:
Number()可以把传入的值转成数值型。非数值 --> NaN;
如果是proxyArr.push(3),由于此时的prop是"push",所以不会进入if分支。
如果是proxyArr[-1],此时的prop是"-1",所以会进入到if分支:把prop从-1改成 2 ,从而实现了被代理的效果。
此时,完全可以把proxyArr当作一个数组来使用,sort,push等方法均可以调用。Array.isArray(proxyArr) === true
当然,你也可以进一步封装成工厂函数。
function myArr(...args){ var arr = new Array(...args); var proxyArr = new Proxy(arr,{ get: (target,key)=>{ let index = Number(key); if(index < 0){ key = target.length + index; } return target[key]; } }) return proxyArr; } var obj = myArr([1,2,3]); console.info(obj[0],obj[-1])链式运算
var double = n => n*2; var pow2 = n => n*n; var half = n => n/ 2; var add1 = n => n+1; function pipe (num){ let funs = [] let obj = new Proxy({},{ get:function(target,prop){ if(prop === "end"){ return funs.reduce((val,currentfn)=>currentfn(val),num); }else{ funs.push(window[prop]) } return obj; } }) return obj; }; console.info( pipe(4).double.pow2.end); console.info( pipe(4).pow.double.pow2.add1.end);
说明:
reduce
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/98000.html
摘要:存取描述符同时具有以下可选键值一个给属性提供的方法,如果没有则为。该方法返回值被用作属性值。值得注意的是属性描述符必须是数据描述符或者存取描述符两种形式之一,不能同时是两者。可以忽略方法的返回值。 前言 我们或多或少都听过数据绑定这个词,数据绑定的关键在于监听数据的变化,可是对于这样一个对象:var obj = {value: 1},我们该怎么知道 obj 发生了改变呢? define...
摘要:查找并返回对象的属性例例属性部署了读取函数返回的是的参数对象注意如果的第一个参数不是对象,则会报错。它返回一个布尔值,表示是否操作成功用于返回对象的所有属性使用和实现观察者模式请参考观察者模式 1、什么是Reflect?为操作对象而提供的新API 2、为什么要设计Reflect?(1)将Object对象的属于语言内部的方法放到Reflect对象上,即从Reflect对象上拿Object...
摘要:的出现,使用内建对象的继承得以实现。属性不存在抛出异常是取值操作,而就是赋值操作,可以对属性值进行验证。属性必须为数字抛出异常接受两个参数被读取属性的原对象,即代理的目标。这个可以拦截内部方法,通过返回数组的值可以覆写其行为。 Proxy & Reflect extends的出现,使用内建对象的继承得以实现。Proxy可以拦截JS引擎内部目标的底层对象操作,这些底层操作被拦截后会触发响...
阅读 411·2019-08-29 12:44
阅读 2986·2019-08-26 17:49
阅读 2348·2019-08-26 13:40
阅读 1165·2019-08-26 13:39
阅读 3633·2019-08-26 11:59
阅读 1802·2019-08-26 10:59
阅读 2435·2019-08-23 18:33
阅读 2669·2019-08-23 18:30