《每天十分钟》-红宝书第4版-代理与反射(二)

2024-06-15 22:12

本文主要是介绍《每天十分钟》-红宝书第4版-代理与反射(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

代理另一个代理
代理可以拦截反射 API 的操作,而这意味着完全可以创建一个代理,通过它去代理另一个代理。这样就可以在一个目标对象之上构建多层拦截网:

 foo: 'bar' 
}; 
const firstProxy = new Proxy(target, { get() { console.log('first proxy'); return Reflect.get(...arguments); } 
}); 
const secondProxy = new Proxy(firstProxy, { get() { console.log('second proxy'); return Reflect.get(...arguments); } 
}); 
console.log(secondProxy.foo); 
// second proxy 
// first proxy 
// ba

代理的问题与不足

  1. 代理中的 this
 thisValEqualsProxy() { return this === proxy; } 
} 
const proxy = new Proxy(target, {}); 
console.log(target.thisValEqualsProxy()); // false 
console.log(proxy.thisValEqualsProxy()); // true

以上代码符合预期

const wm = new WeakMap(); 
class User { constructor(userId) { wm.set(this, userId); } set id(userId) { wm.set(this, userId); } get id() { return wm.get(this); } 
}
const user = new User(123); 
console.log(user.id); // 123 
const userInstanceProxy = new Proxy(user, {}); 
console.log(userInstanceProxy.id); // undefined

以上代码 ,User 实例一开始使用目标对象作为 WeakMap 的键,代理对象却尝试从自身取得这个实例。要解决这个问题,就需要重新配置代理,把代理 User 实例改为代理 User 类本身。

const UserClassProxy = new Proxy(User, {}); 
const proxyUser = new UserClassProxy(456); 
console.log(proxyUser.id);

其实一个走的是构造函数,一个是触发的 set ,而不同的this 导致的

  1. 代理与内部槽位
    一个典型的例子就是 Date 类型。根据 ECMAScript 规范,Date 类型方法的执行依赖 this 值上的内部槽位[[NumberDate]]。代理对象上不存在这个内部槽位,而且这个内部槽位的值也不能通过普通的 get()和 set()操作访问到,于是代理拦截后本应转发给目标对象的方法会抛出 TypeError:
const target = new Date(); 
const proxy = new Proxy(target, {}); 
console.log(proxy instanceof Date); // true 
proxy.getDate(); // TypeError: 'this' is not a Date object

简单说,代理就是无法代理内部插槽
Map,Set,Date,Promise 等,都使用了所谓的“内部插槽”。

let map = new Map();let proxy = new Proxy(map, {});proxy.set('test', 1); // Error

解决办法

let map = new Map();let proxy = new Proxy(map, {get(target, prop, receiver) {let value = Reflect.get(...arguments);
return typeof value == 'function' ? value.bind(target) : value;}
});proxy.set('test', 1);
alert(proxy.get('test')); // 1(工作了!)

代理捕获器与反射方法

  1. get()
const myTarget = {}; 
const proxy = new Proxy(myTarget, { get(target, property, receiver) { console.log('get()'); return Reflect.get(...arguments) } 
}); 
proxy.foo; 
// get()
  1. set()
const myTarget = {}; 
const proxy = new Proxy(myTarget, { set(target, property, value, receiver) { console.log('set()'); return Reflect.set(...arguments) } 
}); 
proxy.foo = 'bar'; 
// set()
  1. has()
const myTarget = {}; 
const proxy = new Proxy(myTarget, { has(target, property) { console.log('has()'); return Reflect.has(...arguments) } 
}); 
'foo' in proxy; 
// has()
  1. defineProperty()
  2. getOwnPropertyDescriptor()
  3. deleteProperty()
  4. ownKeys()
  5. getPrototypeOf()
  6. setPrototypeOf()
  7. isExtensible()
  8. preventExtensions()
  9. apply()
  10. construct()

代理模式
举一些有用的编程模式
14. 跟踪属性访问

const user = { name: 'Jake' 
}; 
const proxy = new Proxy(user, { get(target, property, receiver) { console.log(`Getting ${property}`); return Reflect.get(...arguments); }, set(target, property, value, receiver) { console.log(`Setting ${property}=${value}`); return Reflect.set(...arguments); } 
}); 
proxy.name; // Getting name 
proxy.age = 27; // Setting age=27
  1. 隐藏属性
const hiddenProperties = ['foo', 'bar']; 
const targetObject = { foo: 1, bar: 2, baz: 3 
}; 
const proxy = new Proxy(targetObject, { get(target, property) { if (hiddenProperties.includes(property)) { return undefined; } else { return Reflect.get(...arguments); } }, has(target, property) {if (hiddenProperties.includes(property)) { return false; } else { return Reflect.has(...arguments); } } 
}); 
// get() 
console.log(proxy.foo); // undefined 
console.log(proxy.bar); // undefined 
console.log(proxy.baz); // 3 
// has() 
console.log('foo' in proxy); // false 
console.log('bar' in proxy); // false 
console.log('baz' in proxy); // true
  1. 属性验证
const target = { onlyNumbersGoHere: 0 
}; 
const proxy = new Proxy(target, { set(target, property, value) { if (typeof value !== 'number') { return false; } else { return Reflect.set(...arguments); } } 
}); 
proxy.onlyNumbersGoHere = 1; 
console.log(proxy.onlyNumbersGoHere); // 1 
proxy.onlyNumbersGoHere = '2'; 
console.log(proxy.onlyNumbersGoHere); // 1
  1. 函数与构造函数参数验证
function median(...nums) { return nums.sort()[Math.floor(nums.length / 2)]; 
} 
const proxy = new Proxy(median, { apply(target, thisArg, argumentsList) { for (const arg of argumentsList) { if (typeof arg !== 'number') { throw 'Non-number argument provided'; } } return Reflect.apply(...arguments); } 
}); 
console.log(proxy(4, 7, 1)); // 4 
console.log(proxy(4, '7', 1)); 
// Error: Non-number argument provided
class User { constructor(id) { this.id_ = id; } 
} 
const proxy = new Proxy(User, { construct(target, argumentsList, newTarget) { if (argumentsList[0] === undefined) { throw 'User cannot be instantiated without id'; } else { return Reflect.construct(...arguments); } } 
}); 
new proxy(1); 
new proxy(); 
// Error: User cannot be instantiated without id
  1. 数据绑定与可观察对象
const userList = []; 
class User { constructor(name) { this.name_ = name; } 
} 
const proxy = new Proxy(User, { construct() { const newUser = Reflect.construct(...arguments); userList.push(newUser); return newUser; } 
}); 
new proxy('John'); 
new proxy('Jacob'); 
new proxy('Jingleheimerschmidt'); 
console.log(userList); // [User {}, User {}, User{}]

代理是 ECMAScript 6 新增的令人兴奋和动态十足的新特性。尽管不支持向后兼容,但它开辟出了一片前所未有的 JavaScript 元编程及抽象的新天地。
从宏观上看,代理是真实 JavaScript 对象的透明抽象层。代理可以定义包含捕获器的处理程序对象,而这些捕获器可以拦截绝大部分 JavaScript 的基本操作和方法。在这个捕获器处理程序中,可以修改任何基本操作的行为,当然前提是遵从捕获器不变式。与代理如影随形的反射 API,则封装了一整套与捕获器拦截的操作相对应的方法。可以把反射 API看作一套基本操作,这些操作是绝大部分 JavaScript 对象 API 的基础。
代理的应用场景是不可限量的。开发者使用它可以创建出各种编码模式,比如(但远远不限于)跟踪属性访问、隐藏属性、阻止修改或删除属性、函数参数验证、构造函数参数验证、数据绑定,以及可观察对象。

咏牡丹
宋·王溥
枣花至小能成实,桑叶虽柔解吐丝。
堪笑牡丹如斗大,不成一事又空枝。

这篇关于《每天十分钟》-红宝书第4版-代理与反射(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1064718

相关文章

每天认识几个maven依赖(ActiveMQ+activemq-jaxb+activesoap+activespace+adarwin)

八、ActiveMQ 1、是什么? ActiveMQ 是一个开源的消息中间件(Message Broker),由 Apache 软件基金会开发和维护。它实现了 Java 消息服务(Java Message Service, JMS)规范,并支持多种消息传递协议,包括 AMQP、MQTT 和 OpenWire 等。 2、有什么用? 可靠性:ActiveMQ 提供了消息持久性和事务支持,确保消

高效+灵活,万博智云全球发布AWS无代理跨云容灾方案!

摘要 近日,万博智云推出了基于AWS的无代理跨云容灾解决方案,并与拉丁美洲,中东,亚洲的合作伙伴面向全球开展了联合发布。这一方案以AWS应用环境为基础,将HyperBDR平台的高效、灵活和成本效益优势与无代理功能相结合,为全球企业带来实现了更便捷、经济的数据保护。 一、全球联合发布 9月2日,万博智云CEO Michael Wong在线上平台发布AWS无代理跨云容灾解决方案的阐述视频,介绍了

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

proxy代理解决vue中跨域问题

vue.config.js module.exports = {...// webpack-dev-server 相关配置devServer: {host: '0.0.0.0',port: port,open: true,proxy: {'/api': {target: `https://vfadmin.insistence.tech/prod-api`,changeOrigin: true,p

【反射知识点详解】

Java中的反射(Reflection)是一个非常强大的机制,它允许程序在运行时检查或修改类的行为。这种能力主要通过java.lang.reflect包中的类和接口来实现。 通过反射,Java程序可以动态地创建对象、调用方法、访问字段,以及获取类的各种信息(如构造器、方法、字段等)。 反射的用途 反射主要用于以下几种情况: 动态创建对象:通过类的Class对象动态地创建其实例。访问类的字段

Go 在orm中使用反射

作为静态语言,golang 稍显笨拙,还好 go 的标准包reflect(反射)包弥补了这点不足,它提供了一系列强大的 API,能够根据执行过程中对象的类型来改变程序控制流。本文将通过设计并实现一个简易的 mysql orm 来学习它,要求读者了解mysql基本知识,并且跟我一样至少已经接触 golang 两到三个月。 orm 这个概念相信同学们都非常熟悉,尤其是写过rails的同学,对acti

类型信息:反射-Class

在说反射前提一个概念:RTTI(在运行时,识别一个对象的类型) public class Shapes {public static void main(String[] args) {List<Shape> shapes = Arrays.asList(new Circle(), new Square(), new Triangle());for (Shape shape : shapes

单例模式以及反射对单例模式的破坏及防御

单例模式(Singleton Pattern)是一种确保类在应用程序生命周期内只存在一个实例的设计模式。它不仅提供了全局访问点,还能节省内存、控制实例的生命周期。但常见的单例模式实现方式如饿汉式、懒汉式、双重校验锁、静态内部类等,虽然设计良好,但都容易被 Java 的反射机制所破坏。本文将介绍这些单例实现方式的优缺点、反射如何破坏它们的唯一性,以及如何防御这种破坏。 1. 单例模式的常见实现

Linux如何做ssh反向代理

SSH反向代理是一种通过SSH协议实现的安全远程访问方式,它允许客户端通过SSH连接到一台具有公网IP的代理服务器,然后这台代理服务器再将请求转发给内部网络中的目标主机。以下是实现SSH反向代理的步骤: 一、准备工作 确保服务器配置: 内网服务器(目标主机)和外网服务器(代理服务器)都安装了SSH服务,并且能够通过SSH进行互相访问。内网服务器上的服务(如Web服务、数据库服务等)需要在本地

servlet用反射代替if..else

String methodName = request.getParameter("method"); Method method = this.getClass().getDeclaredMethod(methodName,HttpServletRequest.class, HttpServletResponse.class); method.invoke(this, request, re