当前位置:   article > 正文

ES6系列之Proxy_proxy 数组

proxy 数组

ES6之Proxy

它是什么

proxy使用格式

proxy入门示例

理解代理的作用

代理对象与原对象的关系

代理列表 

get() 代理的应用

允许数组下标是负值

链式运算 

this指向问题 

ES6之Proxy
proxy的中文有代理的意思。在其他的程序设计语言中这个单词也具有类似的含义。

它是什么
Proxy是一个构造器。Proxy在目标对象的外层搭建了一层拦截,外界对目标对象的某些操作,必须通过这层拦截。在 js 中构造器的典型特点就是首字母大写,我们通过new Proxy(原对象,{代理列表})格式去创建对象,创建的这个对象我们称之为代理对象。 即:

代理对象 = new Proxy(原对象,{代理列表})

之所以要额外产生这么一个代理对象,好处在于可以保持原对象不变,在代理对象中添加新的功能,或者是改造某些功能。而这个原对象则可以在适当的时机回滚回去。可以与设计模式中的代理模式对比理解。

proxy使用格式
var obj;
var proxyObj = new Proxy(obj, {
    对obj的操作1: 函数1,
    对obj的操作2: 函数2,
    ...
    
})

obj 参数表示所要拦截的目标对象,{} 参数是一个对象,用来定制拦截行为

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)

proxyObj.name    // no
proxyObj.abc    // no

解释如下:

proxxy对象是在obj对象的基础之上创建的一个新对象。
proxyObj.name是要去获取proxy对象的name属性。.操作符会自动去调用get()方法。这一点非常重要当然。我们平时使用.操作时,是没有感知到这一点的。
在new Proxy的第二个参数中,明确设置了get的方法:当访问proxyObj的任意属性时,输出target,key,receiver的值,并统一返回no。所以proxyObj.name和proxyObj.abc都会得到no。
get函数中的三个参数:target,key,receiver。 target就是原对象obj, key是当前的属性名;receiver是代理对象。你可以在get方法中做任意的自定义的处理。
写到这里你会觉得原对象与代理对象之间有什么关系呢?为什么叫代理呢?

理解代理的作用
对于代理模式 Proxy 的作用主要体现在三个方面

拦截和监视外部对对象的访问
降低函数或类的复杂度
在复杂操作前对操作进行校验或对所需资源进行管理
 注意: 代理对象可以理解为明星的经纪人。

代理对象与原对象的关系
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();     // 1,2,3
console.info(proxyArr[0])     // 1

以上代码中,这个代理对象并没有做任何的特殊操作。理解为明星的经理人消极怠工:原封不动地转告外界的信息给明星本身。所以在proxyArr上做到操作会直接影响到arr上。

同理,在arr上的操作,也会影响proxyArr。
但是要注意:proxyArr与arr是两个不同的对象:arr !== proxyArr 

为什么proxyArr能够直接使用push这个方法呢?原因是:

proxyArr.__proto__ === arr.__proto__ === Array.prototype

代理列表 
实际上 第二个参数 本身就是ES6所新设计的一个对象.它的作用就是用来 自定义代理对象的各种可代理操作 。它本身一共有13中方法,每种方法都可以代理一种操作.其13种方法如下

var proxyObj = new Proxy(obj, {
    // 在读取代理对象的原型时触发该操作
    getPrototypeOf: function(tagert){},
    // 在设置代理对象的原型时触发该操作
    setPrototypeof: function(tagert,proto){},
    // 在判断一个代理对象是否是可扩展时触发该操作
    isExtensible: function(tagert){},
    // 在让一个代理对象不可扩展时触发该操作
    preventExtensions: function(tagert){},
    // 在获取代理对象某个属性的属性描述时触发该操作
    getOwnPropertyDescriptor: function(tagert,key){},
    // 在定义代理对象某个属性时的属性描述时触发该操作
    defineProperty: function(tagert,key,desc){},
    // 在判断代理对象是否拥有某个属性时触发该操作
    has: function(tagert,key){},
    // 在读取代理对象的某个属性时触发该操作
    get: function(tagert,key,receiver){},
    // 在给代理对象的某个属性赋值时触发该操作
    set: function(tagert,key,receiver){},
    // 在删除代理对象的某个属性时触发该操作
    deleteProperty: function(tagert,key){},
    // 在获取代理对象的所有属性键时触发该操作
    getOwnPropertyDescriptor: function(tagert,key){},
    // 在调用一个目标对象为函数的代理对象时触发该操作
    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
链式运算 
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);    // 64
console.info( pipe(4).pow.double.pow2.add1.end);   // 1025

this指向问题 
被代理对象内部的this指向proxy实例

const target = {
  m: function () {
    console.log(this === proxy);
  }
};
const handler = {};

const proxy = new Proxy(target, handler);

target.m() // false
proxy.m()  // true

 Proxy 拦截函数内部的this,指向的是handler对象
 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/140219
推荐阅读
相关标签
  

闽ICP备14008679号