Proxy学习

Proxy使用

Proxy是一个类,要new来实例化

let o = new Proxy(target,handler)
  • target指要代理的对象
  • handler一个对象,对target操作进行拦截的对象
    举例:
let obj = {name: 'brook'};
let p = new Proxy(obj, {
    get(target, property) {
        console.log(target, property);//{ name: 'brook' } 'name'
        return target[property];
    }
});

console.log(p.name); // 'brook

pobj的代理,里面写了get函数进行拦截,访问属性时的操作

  • get(target,property)
    • targetobj对象
    • property是访问的属性名这里是name

Proxy可拦截的操作

get

get(target, propKey, receiver)

  • taget是目标对象
  • propKey被拦截到的属性名
  • receivernew出的Proxy对象

拦截 以下操作

  • 访问属性: proxy[key]proxy.key
  • 访问原型链上的属性: Object.create(proxy)[key]
  • Reflect.get()

通过Proxy来让数组支持索引位负的情况


let arr = ["b", "r", "o", "o", "k"]
let p = new Proxy(arr, {
    get(target, property) {
        console.log(property)
        let index = Math.abs(Number(property))  // 取负数的绝对值
        return arr[index]
    }
})
console.log(p[-2])  //输出o

set

set(target, propKey, value, receiver)

  • value拦截到的赋值
  • receiver一般为proxy对象, 若proxy对象在原型链上(此时就不是proxy对象)
  • 必须返回布尔值,true表示成功,false失败

拦截 以下操作

  • 赋值属性: proxy[key]=valproxy.key=val
  • 访问原型链上的属性: Object.create(proxy)[key] = val
  • Reflect.set()

数组赋值时不是number类型就赋值0

let arr: any[] = [];
let p = new Proxy(arr, {
    set(target, property, value, receiver) {
        if (typeof value != 'number') {  // 不是number就设为0
            value = 0;
        }
        target[property] = value
        return false;
    }
});

p[0] = 11;
p[1] = 'brook';

console.log(p[0]); // 11
console.log(p[1]); // 

receiver对象不是proxy时

let o: { name: any } = {name: ""}
let p = new Proxy(o, {
    set: function (target, property, value, receiver) {
        console.log(receiver)
        target[property] = value
        return true
    }
});
p.name = 1 
let o2 = Object.create(p)
o2.name = 2
//第一次log { name: '' } p对象 
//第二次log {} o2对象

apply

apply(target, thisArg, arguments)

  • target目标对象(函数)
  • thisArg被调用时的上下文对象
  • arguments被调用时的参数列表
  • 可以返回任意值

拦截 以下操作

  • proxy(...args)
  • Function.prototype.apply()Function.prototype.call()
  • Reflect.apply()
let o = {
    sum: function (a, b) {
        return a + b;
    }
}
const handler = {
    apply: function (target, thisArg, argumentsList) {
        console.log(thisArg === newO) // true
        return target(argumentsList[0], argumentsList[1]) * 10;
    }
};

let newO = {sum: new Proxy(o.sum, handler)}
console.log(newO.sum(1, 2));

construct

construct(target, argumentsList, proxy)

  • target 目标对象
  • argumentsList constructor参数列表
  • proxy proxy对象

拦截 以下操作

  • 拦截new操作符new proxy(...args)
  • Reflect.construct()
function monster1(disposition) {
    this.disposition = disposition
}

const handler1 = {
    construct(target, args, proxy) {
        return new target(...args)
    }
}

const proxy1 = new Proxy(monster1, handler1)
new proxy1('fierce')

has

has(target, prop)

  • target 目标对象
  • prop 进行检查是否纯在的属性
  • return需要返回一个boolean属性值

拦截 以下操作

  • 主要针对in操作的钩子
  • 属性查询:key in proxy
  • 继承属性查询: key in Object.create(proxy)
  • with检查:with(proxy){(key)}
  • Reflect.has()
let p = new Proxy({}, {
    has: function (target, prop) {
        return true
    }
});
console.log(p) // {}
console.log('a' in p) // true
console.log('a' in Object.create(p)) //true

getPrototypeOf

getPrototypeOf(target)

  • target 目标对象
  • return需要返回一个object或null

拦截 以下操作

  • instanceof
  • __proto__
  • Object.getPrototypeOf()
  • Object.prototype.isPrototypeOf()
  • Reflect.getPrototypeOf()
let obj = {}
let p = new Proxy(obj, {
    getPrototypeOf(target) {
        return Array.prototype
    }
})
console.log(
    Object.getPrototypeOf(p) === Array.prototype,  // true
    Reflect.getPrototypeOf(p) === Array.prototype, // true
    p.__proto__ === Array.prototype,               // true
    Array.prototype.isPrototypeOf(p),              // true
    p instanceof Array                             // true
)

setPrototypeOf

getPrototypeOf(target,prototype)

  • target 目标对象
  • prototype 对象新原型或为null
  • return若成功修改你要返回true,否则返回false

拦截 以下操作

  • Object.setPrototypeOf()
  • Reflect.setPrototypeOf()
let handlerReturnsFalse = {
    setPrototypeOf(target, newProto) {
        Object.setPrototypeOf(target, newProto)
        return true
    }
}
let o = {a: 1}
let p1 = new Proxy({}, handlerReturnsFalse)
console.log(Object.getPrototypeOf(p1)) //{}
Object.setPrototypeOf(p1, o)
console.log(Object.getPrototypeOf(p1)) //{a:1}

deleteProperty

deleteProperty(target,property)

  • target 目标对象
  • property 待删除的属性名
  • return若删除成功,你要返回true,否则返回false

拦截 以下操作

  • 删除属性: delete proxy[foo]delete proxy.foo
  • Reflect.deleteProperty()
let p = new Proxy({a: 1}, {
    deleteProperty: function (target, prop) {
        delete target[prop]
        return true
    }
})
console.log(p) // { a: 1 }
delete p.a 
console.log(p) // {}

ownKeys

ownKeys(target)

  • target 目标对象
  • return 必须返回一个可枚举对象,且元素类型必须是StringSymbol

拦截

  • Object.keys()
  • Object.getOwnPropertyNames()
  • Object.getOwnPropertySymbols()
  • Reflect.ownKeys()
  • 具体效果看代码
let p = new Proxy({z: 1, x: 1}, {
    ownKeys: function (...arg) {
        return [Symbol(), 'k', 'z']
    }
})

console.log(Object.keys(p)) //[ 'z' ]
console.log(Object.getOwnPropertyNames(p))//[ 'k', 'z' ]
console.log(Object.getOwnPropertySymbols(p))//[ Symbol() ]

还有一些不常用的方法

  • defineProperty()
    • 用于拦截对对象的Object.defineProperty() 操作。
  • getOwnPropertyDescriptor()
    • 用于拦截对对象的Object.getOwnPropertyDescriptor() 操作。
  • isExtensible
    • 用于拦截对对象的Object.isExtensible() 操作。
  • preventExtensions()
    • 用于拦截对对象的Object.preventExtensions() 操作。
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • 来自深入理解ES6第十二章,由于最近业务中经常用到,记录一下 这里内容都太学术了,有一篇简单介绍Proxy作用的文...
    NowhereToRun阅读 1,009评论 0 1
  • defineProperty() 学习书籍《ECMAScript 6 入门 》 Proxy Proxy 用于修改某...
    Bui_vlee阅读 650评论 0 1
  • 此文出处 简介 proxyproxy可以拦截目标(target)上的非内置的对象进行操作,使用trap拦截这些操作...
    xiaohesong阅读 368评论 0 1
  • 在大自然中,有许许多多奇异的昆虫,让我们大开眼界。 它,在人类眼里不堪一击,可是却如此残忍,看似柔弱但很凶残;...
    魏良煜阅读 519评论 0 0
  • 一大早儿子打来电话:“妈妈,悄咪咪的告诉你一件事,我比赛用的四百块钱没了?!蔽以诘缁袄锾芯跛っ磐Υ蟮?,...
    ganweif阅读 94评论 0 0