Proxy代理

代理
  • ES5 代理方式
//es5 代理方式
let obj={}
let newVal=''
Object.defineProperty(obj,'name',{      
    get(){
        console.log('get');
        return newVal
    },
    set(val){
        console.log('set');
        newVal=val
    }
})
obj.name='es' //set
console.log(obj.name);  //get es
  • ES6 Proxy
let obj={}
let p=new Proxy(obj,{})
p.name='hi'
console.log(obj.name); //hi
for(let key in obj){console.log(key);} //name
  • ES6 Reflect
//es6中使用Reflect.defineProperty 将Object属于语言内部的方法放到Reflect上  更加规范
let obj={}
Object.defineProperty(obj,'name',{})
Reflect.defineProperty(obj,'name',{})

//返回boolean  修改某些Object方法的返回结果,让其变得更合理
// if(Reflect.defineProperty()){}else{}

//让Object操作变成函数行为
console.log('assign' in Object)  //true
console.log(Reflect.has(Object,'assign')) //true

//Reflect对象的方法于Proxy对象的方法一一对应
常用拦截方法
  • get
    拦截对象属性的读取,比如proxy.foo和proxy['foo']
// 判断数组的下标是否有值,有值返回值,没值返回下标
let arr=[7,8,9]
arr=new Proxy(arr,{
    get(target,prop){  
        // console.log(target,prop);  //arr[1]->target [7,8,9],prop '1'
        return prop in target ? target[prop] : 'error'
    }
})
console.log(arr[1]); //8
console.log(arr[3]); //error

//字典翻译,输入hello返回你好,输入字典没有的返回原值
let dict={
    'hello':'你好',
    'world':'世界'
}
dict=new Proxy(dict,{
    get(target,prop){  
        return prop in target ? target[prop] : prop
    }
})
console.log(dict['world']); //世界
console.log(dict['good']); //good
  • set
    拦截对象属性的设置,返回一个布尔值,比如proxy.foo=v或proxy['foo']=v
//限制arr内限制只能设置number值,其他值返回错误
let arr=[]
arr=new Proxy(arr,{
    set(target,prop,val){
        if(typeof val==='number'){
            target[prop]=val
            return true
        }else{
            return false
        }
    }
})
arr.push(1) 
console.log(arr[0]); //1
arr.push(2) 
console.log(arr[1],arr.length); //2 2
  • has
    拦截propKey in proxy的操作,返回一个布尔值
//判断是否在范围内,返回布尔型值
let range={
    start:1,
    end:5
}
range=new Proxy(range,{
    has(target,prop){
        return prop>=target.start && prop<=target.end
    }
})
console.log(2 in range); //true
console.log(9 in range); //false
  • ownKeys
    拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组
//使用Symbol例子
let obj={
    name:'daji',
    [Symbol('es')]:'es'
}
console.log(Object.getOwnPropertyNames(obj)) //['name']
console.log(Object.getOwnPropertySymbols(obj))  //[Symbol(es)]
console.log(Object.keys(obj)) //['name']
for(let key in obj){
    console.log(key); //name
}

//不想被遍历出私有属性以下划线开头的 _parssword 使用ownKeys
let userinfo={
    name:'daji',
    age:18,
    _password:'***'
}
userinfo=new Proxy(userinfo,{
    ownKeys(target){
        return Object.keys(target).filter(key=>!key.startsWith('_'))
    }
})
for(let key in userinfo){
    console.log(key); //name age
}
console.log(Object.keys(userinfo)); //['name','age']
  • deleteProperty
    拦截delete proxy[proKey] 返回一个布尔值
//阻止对私有属性的任何访问 _password
let user={
    name:'daji',
    age:18,
    _password:'***'
}
user=new Proxy(user,{
    get(target,prop){           //不允许获取
        if(prop.startsWith('_')){
            throw new Error('不可访问')
        }else{
            return target[prop]
            //return Reflect.get(target,prop)
        }
    },
    set(target,prop,val){          //不允许设置 返回布尔型值
        if(prop.startsWith('_')){
            throw new Error('不可访问')
        }else{
            target[prop]=val    //Reflect.set(target,prop,val)
            return true
        }
    },    
    deleteProperty(target,prop){           //不允许删除 返回布尔型值
        if(prop.startsWith('_')){
            throw new Error('不可删除')
        }else{
            delete target[prop]   //Reflect.delete(target,prop)
            return true
        }
    },
    ownKeys(target){           //不允许遍历
        return Object.keys(target).filter(key=>!key.startsWith('_'))   
       //return Reflect.ownKeys(target).filter(key=>!key.startsWith('_'))  
    }
})

//get 测试
// console.log(user.age); //18
// console.log(user._password); //报错Error: 不可访问

//set 测试
user.age=100
console.log(user.age); //100
//捕获异常写法
try{
    user._password='xxx'
}catch(e){
    console.log(e.message);  //不可访问
}

//删除 测试
try{
   delete user._password
}catch(e){
    console.log(e.message);  //不可删除
}

//遍历 测试
for(let key in user){
    console.log(key);  //name age
}
  • apply
    拦截函数调用,apply和call操作
let sum=(...args)=>{
    let num=0
    args.forEach(item=>{
        num+=item
    })
    return num
}
sum=new Proxy(sum,{
    apply(target,ctx,args){   //ctx上下文
        return target(...args)*2    //return Reflect.apply(target,target,[...args])*2
    }
})
console.log(sum(1,2));  //6
console.log(sum.call(null,1,2,3));  //null不改变指向 12
console.log(sum.apply(null,[1,2,3]));  //12
  • construct
    construct 拦截new 返回一个对象
let User=class{
    constructor(name){
        this.name=name
    }
}
User=new Proxy(User,{
    construct(target,args,newTarget){  //args构造函数的参数
        return new target(...args)
    }
})
console.log(new User('hi'));  // User {name: "hi"}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容

  • 什么是Proxy代理 ES6 让开发者能进一步接近 JS 引擎的能力,这些能力原先只存在于内置对象上。语言通过代理...
    27亿光年中的小小尘埃阅读 486评论 0 1
  • 一、概述 Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta pr...
    了凡和纤风阅读 265评论 0 1
  • 来自深入理解ES6第十二章,由于最近业务中经常用到,记录一下 这里内容都太学术了,有一篇简单介绍Proxy作用的文...
    NowhereToRun阅读 1,010评论 0 1
  • 前面的话   ES5和ES6致力于为开发者提供JS已有却不可调用的功能。例如在ES5出现以前,JS环境中的对象包含...
    CodeMT阅读 1,451评论 0 2
  • ES:给开发者提供了一个新特性:Proxy,就是代理的意思。也就是我们这一节要介绍的知识点。以前,ATM还没有那么...
    幸宇阅读 463评论 0 0