|
楼主 |
发表于 2021-8-24 14:00
|
显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用 · 内置多项VBA编程加强工具 ★ 免费下载 ★ ★ 使用手册★
上面的是通过修改原型的方式,影响对象,其实还有另一种方式,就是使用代理对对象进行打包,返回打包后的对象给用户使用,以此方式对对象的访问进行直接干预,看代码:
- //居中填充
- String.prototype.padCenter =
- function(targetLength, padString = ' ') {
- if (typeof targetLength != 'number')
- throw new TypeError('Parameter "targetLength" ' +
- 'must be a number object.');
- if (typeof padString != 'string') {
- if (padString === null)
- padString = 'null';
- else
- padString = padString.toString();
- }
- let padStrWidth = padString.length;
- if (padStrWidth == 0) return this;
- let restWidth = targetLength - this.length;
- if (restWidth <= 0) return this;
- let leftWidth = Math.trunc(restWidth / 2);
- let rightWidth = leftWidth + restWidth % 2;
- if (padString.length == 1) {
- return padString.repeat(leftWidth) + this +
- padString.repeat(rightWidth);
- } else {
- if (leftWidth == 0)
- return this + padString[0];
- else {
- //leftPart
- let leftRepeat = Math.trunc(leftWidth / padStrWidth);
- let leftRest = leftWidth - leftRepeat * padStrWidth;
- let leftStr = padString.repeat(leftRepeat) +
- padString.substr(0, leftRest);
- //rightPart
- let rightRepeat = Math.trunc(rightWidth / padStrWidth);
- let rightRest = rightWidth - rightRepeat * padStrWidth;
- let rightStr = padString.repeat(rightRepeat) +
- padString.substr(0, rightRest);
- return leftStr + this + rightStr;
- }
- }
- }
- /*Proxy handler 可对应于
- Reflect.apply()
- Reflect.construct()
- Reflect.defineProperty()
- Reflect.deleteProperty()
- Reflect.get()
- Reflect.getOwnPropertyDescriptor()
- Reflect.getPrototypeOf()
- Reflect.has()
- Reflect.isExtensible()
- Reflect.ownKeys()
- Reflect.preventExtensions()
- Reflect.set()
- Reflect.setPrototypeOf()
- 实现想要的代理
- */
- class ES6ProxyTest {
- //既然 Reflect.set(target, key, value[, receiver]) 有
- //要设置的属性的键和值,我们就可以通过 set 代理,在一个
- //对象的定义的外部:
- //1.通过键,拦截对某些属性的写入
- //2.通过值,检验类型,拦截非法写入
- //3.通过键,重定向属性的写入,就像为属性设置一些假名一样
- static SetProxy() {
- let p = new Point(3, 8);
- let pp = new Proxy(p, {
- set:function(target, key, value, receiver){
- //Reflect.set(target, key, value[, receiver])
- //target : 用于接收属性(被代理的对象)的对象
- //key : 要写入的属性的键(字符串或Symbol类型)
- //value : 要写入的属性新值
- //receiver : 如果 target 对象的 key 属性有 setter,
- // receiver 则为 setter 调用时的 this 值。
- //return : 返回一个 Boolean 值,表明操作的成败
- let success = Reflect.set(target, key, value, receiver);
- if (success) {
- //Console 在此不可用
- Debug.Print('property '+ key +' on '+
- target + ' set to '+ value);
- }
- //必须返回操作成败状态,否则报错
- return success;
- }
- });
- pp.xxx = 13;
- Console.log(p.xxx);
- }
-
- //既然 Reflect.get(target, key[, receiver]) 提供了要读取
- //的属性的键,我们就可以通过 get 代理,在对象的定义的外部:
- //1.通过键,拦截对某些属性的读取
- //2.通过键,伪造一些不存在的属性
- //3.通过键,实现类同假名的属性
- static GetProxy() {
- var obj = new Proxy({}, {
- get: function (target, key, receiver) {
- //Console 在此不可用
- Debug.Print(`getting ${key}!`);
- //Reflect.get(target, key[, receiver])
- //target : 被代理的对象
- //key : 要读取的属性的键(字符串或Symbol类型)
- //receiver : 如果 target 对象的 key 属性有 getter,
- // receiver 则为 getter 调用时的 this 值。
- //return : 属性的值。
- return Reflect.get(target, key, receiver);
- }
- });
- obj.count = 1;
- ++obj.count;
- }
-
- /*Reflect.apply(target, thisArg, argsList)
- target : 被代理对象,请确保它是一个 Function 对象
- thisArg : 函数调用时绑定的对象
- argsList : 函数调用时传入的实参列表,该参数应该是一个类数组的对象。
- return : 调用函数返回的结果
- 通过这种代理:
- 1.检验调用时传入的参数
- 2.阻止函数被调用
- */
- static ApplyProxy() {
- function sum (...values){
- return values.reduce((pre, cur) => pre + cur, 0);
- }
- let sumProxy = new Proxy(sum, {
- apply : function(target, thisArg, argsList){
- argsList.forEach(arg => {
- if(typeof arg !== "number")
- throw new TypeError("所有参数必须是数字,亲!");
- });
- return Reflect.apply(target, thisArg, argsList);
- }
- });
-
- try {
- let r = sumProxy(3, 5, 'hello');
- Console.log(r);
- } catch(e) {
- Console.log(e.message);
- }
- Console.log(sumProxy(3, 8, 5));
- }
-
- /*Reflect.construct(target, argsList[, newTarget])
- target : 被运行的目标构造函数
- argsList : 类数组,目标构造函数调用时的参数。
- newTarget : 可选,作为新创建对象的原型对象的 constructor 属性,
- 参考 new.target 操作符,默认值为 target。
- */
- static ConstructProxy() {
- function sum (...values){
- return values.reduce((pre, cur) => pre + cur, 0);
- }
- let sumProxy = new Proxy(sum, {
- construct:function(target, argsList){
- throw new TypeError("亲,该函数不能通过 new 调用。");
- }
- });
-
- try {
- let x = new sumProxy(3, 5, 7);
- } catch(e) {
- Console.log(e.message);
- }
- }
-
- //禁止向指定单元格区域写入数据
- static ForbidSetValue() {
- let rng = new Range('B1:D3');
- rng.Value2 = 32;
-
- let rngProxy = new Proxy(rng, {
- set : function(target, key, value, receiver) {
- if (key === 'Value2') {
- throw new Error('无法设置属性')
- } else
- return Reflect.set(target, key, value, receiver);
- }
- });
-
- try {
- rngProxy.Value2 = 168;
- } catch(e) {
- Console.log(e.message);
- }
- Console.log(rngProxy.Text);
- }
-
- //运行所有测试用例
- static RunAll() {
- let members = Object.getOwnPropertyNames(ES6ProxyTest);
- let notCall = ['length', 'prototype', 'name', 'RunAll'];
- for (let member of members) {
- if (!notCall.includes(member)) {
- Console.log(member.padCenter(56, '-'));
- eval(`ES6ProxyTest.${member}()`);
- }
- }
- }
- }
复制代码
在立即窗口中输入 ES6ProxyTest.RunAll(); ,然后回车,其输出如下:
- ------------------------SetProxy------------------------
- property xxx on (3, 8) set to 13
- 13
- ------------------------GetProxy------------------------
- getting count!
- -----------------------ApplyProxy-----------------------
- 所有参数必须是数字,亲!
- 16
- ---------------------ConstructProxy---------------------
- 亲,该函数不能通过 new 调用。
- ---------------------ForbidSetValue---------------------
- 无法设置属性
- 32
复制代码 |
评分
-
1
查看全部评分
-
|