Skip to content

Commit 5c0da89

Browse files
update
1 parent a5cfc4c commit 5c0da89

File tree

3 files changed

+267
-2
lines changed

3 files changed

+267
-2
lines changed

02-ES新特性/ES6/05-Reflect&Proxy.html

Lines changed: 267 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,28 @@
1919
age: 26
2020
}
2121
let 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
}
3138
let proxy = new Proxy(target, handler)
3239
proxy.name // getting name 实际执行 handler.get
3340
proxy.age = 25 // setting age 实际执行 handler.set
41+
// proxy.age = "25" // "The age is not an integer"
3442

35-
// target 可为空对象
43+
// => target 可为空对象
3644
let targetEpt = {}
3745
let proxyEpt = new Proxy(targetEpt, handler)
3846
// 调用 get 方法,此时目标对象为空,没有 name 属性
@@ -43,21 +51,278 @@
4351
proxyEpt.name // getting name "csxiaoyao"
4452
// 注意:通过构造函数新建实例时其实是对目标对象进行了浅拷贝,因此目标对象与代理对象会互相影响
4553

46-
// handler 可为空对象
54+
// => handler 可为空对象
4755
// 相当于不设置拦截操作,直接访问目标对象
4856
let targetEmpty = {}
4957
let proxyEmpty = new Proxy(targetEmpty,{})
5058
proxyEmpty.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>

git速查表.JPG

149 KB
Loading

git速查表.png

-736 KB
Binary file not shown.

0 commit comments

Comments
 (0)