1919 age : 26
2020}
2121let handler = {
22+ // get(target, propKey, receiver)
2223 get : function ( target , key ) {
2324 console . log ( 'getting ' + key ) ;
2425 return target [ key ] ; // 不是target.key
2526 } ,
27+ // set(target, propKey, value, receiver)
2628 set : function ( target , key , value ) {
29+ if ( key === 'age' ) {
30+ if ( ! Number . isInteger ( value ) ) {
31+ throw new TypeError ( 'The age is not an integer' ) ;
32+ }
33+ }
2734 console . log ( 'setting ' + key ) ;
2835 target [ key ] = value ;
2936 }
3037}
3138let proxy = new Proxy ( target , handler )
3239proxy . name // getting name 实际执行 handler.get
3340proxy . age = 25 // setting age 实际执行 handler.set
41+ // proxy.age = "25" // "The age is not an integer"
3442
35- // target 可为空对象
43+ // => target 可为空对象
3644let targetEpt = { }
3745let proxyEpt = new Proxy ( targetEpt , handler )
3846// 调用 get 方法,此时目标对象为空,没有 name 属性
4351proxyEpt . name // getting name "csxiaoyao"
4452// 注意:通过构造函数新建实例时其实是对目标对象进行了浅拷贝,因此目标对象与代理对象会互相影响
4553
46- // handler 可为空对象
54+ // => handler 可为空对象
4755// 相当于不设置拦截操作,直接访问目标对象
4856let targetEmpty = { }
4957let proxyEmpty = new Proxy ( targetEmpty , { } )
5058proxyEmpty . name = "csxiaoyao" // Proxy {name: "csxiaoyao"}
5159
60+ /**
61+ * 应用:利用实例方法 get(target, propKey, receiver) 实现私有属性读取保护
62+ * get() 方法可以继承
63+ */
64+ let proxy2 = new Proxy ( { } , {
65+ get ( target , propKey , receiver ) {
66+ // 实现私有属性读取保护
67+ if ( propKey [ 0 ] === '_' ) {
68+ throw new Error ( `Invalid attempt to get private "${ propKey } "` ) ;
69+ }
70+ console . log ( 'Getting ' + propKey ) ;
71+ return target [ propKey ] ;
72+ }
73+ } ) ;
74+ // 更好的创建对象的方式
75+ let obj = Object . create ( proxy2 ) ;
76+ // console.log(obj._test) // Invalid attempt to get private "_test"
77+
78+ /**
79+ * proxy receiver参数
80+ */
81+ const handler2 = {
82+ // 参数 receiver 表示原始操作行为所在对象,一般是 Proxy 实例本身
83+ set : function ( obj , key , value , receiver ) {
84+ console . log ( obj , key , value , receiver )
85+ if ( key === 'instance' ) {
86+ obj [ key ] = receiver ;
87+ } else {
88+ obj [ key ] = value ;
89+ }
90+ return true
91+ // 注意: 严格模式下,set代理如果没有返回true,会报错
92+ }
93+ } ;
94+ const proxy3 = new Proxy ( { } , handler2 ) ;
95+ proxy3 . name = 'csxiaoyao' ;
96+ proxy3 . instance = ''
97+ proxy3 . instance === proxy3 // true
98+ // Object.setPrototypeOf()
99+ const exam = { }
100+ Object . setPrototypeOf ( exam , proxy3 )
101+ exam . instance = ''
102+ exam . instance === exam // true
103+
104+ /**
105+ * proxy apply
106+ */
107+ // apply(target, ctx, args)
108+ // 用于拦截函数的调用、call 和 reply 操作
109+ // target目标对象,ctx目标对象上下文,args目标对象的参数数组
110+ function sub ( a , b ) {
111+ return a - b ;
112+ }
113+ let handler3 = {
114+ apply : function ( target , ctx , args ) {
115+ console . log ( 'handle apply' ) ;
116+ return Reflect . apply ( ...arguments ) ;
117+ }
118+ }
119+ let proxySub = new Proxy ( sub , handler3 )
120+ proxySub ( 2 , 1 ) // 1
121+
122+ /**
123+ * proxy has
124+ */
125+ // has(target, propKey)
126+ // 用于拦截 HasProperty 操作
127+ // 即在判断 target 对象是否存在 propKey 属性时,会被这个方法拦截
128+ // 此方法不判断一个属性是对象自身的属性,还是继承的属性
129+ // 注意:此方法不拦截 for ... in 循环
130+ let handler4 = {
131+ has : function ( target , propKey ) {
132+ console . log ( "handle has" ) ;
133+ return propKey in target ;
134+ }
135+ }
136+ let exam2 = { name : "csxiaoyao" }
137+ let proxyHas = new Proxy ( exam2 , handler4 ) // true
138+
139+ /**
140+ * proxy construct
141+ */
142+ // construct(target, args)
143+ // 用于拦截 new 命令,返回值必须为对象
144+ let handler5 = {
145+ construct : function ( target , args , newTarget ) {
146+ console . log ( "handle construct" ) ;
147+ return Reflect . construct ( target , args , newTarget ) ;
148+ } }
149+ class exam3 {
150+ constructor ( name ) {
151+ this . name = name ;
152+ }
153+ }
154+ let proxy4 = new Proxy ( exam3 , handler5 )
155+ new proxy4 ( "csxiaoyao" ) // exam3 {name: "csxiaoyao"}
156+
157+ /**
158+ * proxy deleteProperty
159+ */
160+ // deleteProperty(target, propKey)
161+ // 用于拦截 delete 操作,如果这个方法抛出错误或者返回 false ,propKey 属性就无法被 delete 命令删除
162+ let handler6 = {
163+ deleteProperty : function ( target , propKey ) {
164+ console . log ( "handle deleteProperty" ) ;
165+ return false ;
166+ }
167+ }
168+ let exam4 = { name : "csxiaoyao" }
169+ let proxyDelete = new Proxy ( exam4 , handler6 ) // true
170+ delete proxyDelete . name
171+
172+ /**
173+ * proxy defineProperty
174+ */
175+ // defineProperty(target, propKey, propDesc)
176+ // 用于拦截 Object.defineProperty
177+ // 若目标对象不可扩展,增加目标对象上不存在的属性会报错;若属性不可写或不可配置,则不能改变这些属性
178+ // defineProperty 返回值为false,添加属性操作无效
179+ let handler7 = {
180+ defineProperty : function ( target , propKey , propDesc ) {
181+ console . log ( "handle defineProperty" ) ;
182+ return true ;
183+ }
184+ }
185+ let proxyDefine = new Proxy ( { } , handler7 )
186+ proxyDefine . name = "csxiaoyao"
187+
188+ /**
189+ * proxy getOwnPropertyDescriptor
190+ */
191+ // getOwnPropertyDescriptor(target, propKey)
192+ // 用于拦截 Object.getOwnPropertyDescriptor() 返回值为属性描述对象或 undefined
193+ let handler8 = {
194+ getOwnPropertyDescriptor : function ( target , propKey ) {
195+ console . log ( 'handle getOwnPropertyDescriptor' )
196+ return Object . getOwnPropertyDescriptor ( target , propKey ) ;
197+ }
198+ }
199+ let proxyGetOwnPropertyDescriptor = new Proxy ( { name : "csxiaoyao" } , handler8 )
200+ const retData = Object . getOwnPropertyDescriptor ( proxyGetOwnPropertyDescriptor , 'name' )
201+ console . log ( retData ) // {value: "csxiaoyao", writable: true, enumerable: true, configurable: true}
52202
203+ /**
204+ * proxy getPrototypeOf
205+ */
206+ // getPrototypeOf(target)
207+ // 主要用于拦截获取对象原型的操作,包括以下操作:
208+ // - Object.prototype._proto_
209+ // - Object.prototype.isPrototypeOf()
210+ // - Object.getPrototypeOf()
211+ // - Reflect.getPrototypeOf()
212+ // - instanceof
213+ // 注意:返回值必须是对象或 null ,否则报错
214+ // 另外,如果目标对象不可扩展(non-extensible),getPrototypeOf 方法必须返回目标对象的原型对象
215+ let exam5 = { }
216+ let proxyProto = new Proxy ( { } , {
217+ getPrototypeOf : function ( target ) {
218+ return exam5 ;
219+ }
220+ } )
221+ console . log ( Object . getPrototypeOf ( proxyProto ) ) // {}
53222
223+ /**
224+ * proxy isExtensible
225+ */
226+ // isExtensible(target)
227+ // 用于拦截 Object.isExtensible 操作
228+ // 该方法只能返回布尔值,否则返回值会被自动转为布尔值
229+ let proxyExtensible = new Proxy ( { } , {
230+ isExtensible :function ( target ) {
231+ return true ;
232+ }
233+ } )
234+ Object . isExtensible ( proxyExtensible ) // true
235+ // 注意:它的返回值必须与目标对象的isExtensible属性保持一致,否则会抛出错误
236+
237+ /**
238+ * proxy ownKeys
239+ */
240+ // ownKeys(target)
241+ // 用于拦截对象自身属性的读取操作
242+ // - Object.getOwnPropertyNames()
243+ // - Object.getOwnPropertySymbols()
244+ // - Object.keys()
245+ // - or...in
246+ // 方法返回的数组成员,只能是字符串或 Symbol 值,否则会报错
247+ // 若目标对象中含有不可配置的属性,则必须将这些属性在结果中返回,否则就会报错
248+ // 若目标对象不可扩展,则必须全部返回且只能返回目标对象包含的所有属性,不能包含不存在的属性,否则也会报错
249+
250+ // [ 'name' ]f返回结果中,三类属性会被过滤:
251+ // - 目标对象上没有的属性
252+ // - 属性名为 Symbol 值的属性
253+ // - 不可遍历的属性
254+ let target1 = {
255+ name : "csxiaoyao" ,
256+ [ Symbol . for ( 'age' ) ] : 26 ,
257+ } ;
258+ // 添加不可遍历属性 'gender'
259+ Object . defineProperty ( target1 , 'gender' , {
260+ enumerable : false ,
261+ configurable : true ,
262+ writable : true ,
263+ value : 'male'
264+ } ) ;
265+ let handlerOwnKeys = {
266+ ownKeys ( target ) {
267+ return [ 'name' , 'parent' , Symbol . for ( 'age' ) , 'gender' ] ;
268+ }
269+ } ;
270+ let proxyOwnKeys = new Proxy ( target1 , handlerOwnKeys ) ;
271+ const retData2 = Object . keys ( proxyOwnKeys )
272+ console . log ( retData2 ) // ['name']
273+
274+ /**
275+ * proxy preventExtensions
276+ */
277+ // preventExtensions(target)
278+ // 拦截 Object.preventExtensions 操作
279+ // 该方法必须返回一个布尔值,否则会自动转为布尔值
280+ // 只有目标对象不可扩展时(即 Object.isExtensible(proxy) 为 false )才能返回 true ,否则会报错
281+
282+ // 由于 proxy.preventExtensions 返回 true,此处也会返回 true,因此会报错
283+ // Object.preventExtensions(proxyPreventExtensions) // error
284+ // 解决方案
285+ var proxyPreventExtensions2 = new Proxy ( { } , {
286+ preventExtensions : function ( target ) {
287+ // 返回前先调用 Object.preventExtensions
288+ Object . preventExtensions ( target ) ;
289+ return true ;
290+ }
291+ } ) ;
292+ Object . preventExtensions ( proxyPreventExtensions2 )
293+
294+ /**
295+ * proxy setPrototypeOf
296+ */
297+ // 主要用来拦截 Object.setPrototypeOf 方法
298+ // 返回值必须为布尔值,否则会被自动转为布尔值
299+ // 若目标对象不可扩展,setPrototypeOf 方法不得改变目标对象的原型
300+ let proto = { }
301+ let proxyProto2 = new Proxy ( function ( ) { } , {
302+ setPrototypeOf : function ( target , proto ) {
303+ console . log ( "setPrototypeOf" ) ;
304+ return true ;
305+ }
306+ } ) ;
307+ Object . setPrototypeOf ( proxyProto2 , proto ) ;
308+
309+ /**
310+ * proxy revocable
311+ */
312+ // Proxy.revocable()
313+ // 用于返回一个可取消的 Proxy 实例
314+ let { proxy5, revoke} = Proxy . revocable ( { } , { } ) ;
315+ proxy5 . name = "csxiaoyao" ;
316+ revoke ( ) ;
317+ proxy5 . name
54318
55319/**
56320 * 【 Reflect 】
57321 * 获取目标对象的行为
58322 * 与 Object 类似,但是更易读
59323 * 为操作对象提供了一种更优雅的方式,方法与 Proxy 是对应的
60324 */
325+
61326</ script >
62327</ body >
63328</ html >
0 commit comments