首页 > 解决方案 > 当我从中获取值时,我的自定义类代理返回未定义

问题描述

我正在尝试制作一个支持类的代理版本。这包括普通代理不支持的 instanceof。这是我到目前为止所得到的:

let ClassProxy = function(TargetClass, args) { // A class which creates a Proxy of a class
	function extend(sup, base) {
		var descriptor = Object.getOwnPropertyDescriptor(
			base.prototype, 'constructor'
		); // Get the constructor
		base.prototype = Object.create(sup.prototype); // Create an object with the super's prototype and apply it to the base's prototype
		var handler = {
			construct: function(target, args) {
				var obj = Object.create(base.prototype);
				return this.apply(target, obj, args); // Call the constructor
			}, // Construct it
			apply: function(target, obj, args) {
				let obj1 = Reflect.construct(sup, args, function() {
					return obj
				}) // Construct
				let obj2 = Reflect.construct(base, args, function() {
					return obj
				})
				let proto = Object.getPrototypeOf(obj)
				let obj1d = Object.getOwnPropertyDescriptors(Object.getPrototypeOf(obj1))
				let obj2d = Object.getOwnPropertyDescriptors(Object.getPrototypeOf(obj2))
				for (let k in obj1d) {
					let prop = obj1d[k]
					Object.defineProperty(proto, k, prop) // Attempt to apply the prototype from the super
				}
				for (let k in obj2d) {
					let prop = obj2d[k]
					Object.defineProperty(proto, k, prop) // Attempt to apply the prototype from the base
				}
				Object.setPrototypeOf(obj, proto)
				obj1d = Object.getOwnPropertyDescriptors(obj1)
				obj2d = Object.getOwnPropertyDescriptors(obj2)
				for (let k in obj1d) {
					let prop = obj1d[k]
					Object.defineProperty(obj, k, prop) // Attempt to set properties from the super
				}
				for (let k in obj2d) {
					let prop = obj2d[k]
					Object.defineProperty(obj, k, prop) // Attempt to set properties from the base
				}
				return obj
			} // The constructor of the ClassProxy
		}
		var proxy = new Proxy(base, handler); // Create a proxy which is a fake class to create fake classes
		descriptor.value = proxy; // Set the value for the constructor to the proxy above
		Object.defineProperty(base.prototype, 'constructor', descriptor); // Define the constructor
		return proxy;
	}
	let _Proxy = function() {
		return new Proxy(this, args) // Basically just lets me create a proxy with the custom arguments
	}
	_Proxy.prototype = Object.getPrototypeOf(Proxy) // Apply the prototype of Proxy to _Proxy to allow the constructor to use .prototype
	return extend(TargetClass, _Proxy) // Combine the classes
}
ClassProxy.prototype.constructor = ClassProxy // Apply the constructor (calling and using new are the same)

let MyClass = class { // Original class
	constructor(myClassName) {
		console.log("Constructed MyClass! myClassName: "+myClassName) // Test (definitely works)
		this.name = myClassName
	}
}

let Haha = new ClassProxy(MyClass, { // A class proxy of the original class
	get(obj, key) { // A proxy argument
		console.log("Intercepted '"+key+"'!") // When I get "name" it should tell me (it doesn't)
		return Reflect.get(obj, key) // Return the real value
	}
})
let hahaInstance = new Haha("test") // The class proxy
console.log(hahaInstance.test) // Will put undefined and no "intercepted" message will happen
console.log(hahaInstance instanceof MyClass) // True
console.log(new Proxy(new MyClass("test2")) instanceof MyClass) // False (I want to get around this behavior)

它工作正常并且 instanceof 工作但索引类返回 undefined 并且不调用代理方法。Object.getOwnPropertyDescriptors 工作,你仍然可以通过这种方式获得价值。这似乎可能与 Proxy 类本身有关......有谁知道这是否可以修复?

基本上我想制作一个自定义版本的代理,它实际上是一个类的实例,但仍然像代理一样。

编辑:这是我的原始代码:

{
	// Creep is a class built into the game which is the entity that does all of the work for you
	let creepAPI = {
		moveTo: function() {
			// Optimized moveTo code (the original code can be slow in some rare cases and doesn't do exactly what I want)
		}
	}
	let _Creep = Creep
	Creep.constructor = function(creepId) { // Override the constructor
		return new Proxy(new _Creep(creepId), { // Make a proxy for the class
			get(real, index) { // Allows me to add custom API functions, etc.
				console.log("Index: "+index) // Output the index for testing
				if (creepAPI[index]) {
					return creepAPI[index]
				}
				return Reflect.get(real, index) // Get the index from the real creep
			}
		})
	}
	console.log(new Creep(otherCreep.id) instanceof _Creep) // otherCreep would be an actual instance of a creep (outputs false on my private server)
	
	// Now to use my api I just make a new creep from the id of the actual creep
}

标签: javascriptclassproxy

解决方案


Bergi 让我意识到 Proxy 确实支持类,但我使用的 API 存在某种奇怪的错误,我假设这是因为 API 的工作方式。它创建了一个完全隔离的虚拟机(我认为它甚至不是一个实际的节点 js 虚拟机),它是从主节点 js 进程产生的,并且全局以某种方式传递给虚拟机。我猜这与全局传递的方式有关,但我看不出它是如何工作的。

对此的真正答案是代理实际上确实支持类和 instanceof,但在 VM 中 instanceof 和类扩展在内置 API 类上的工作方式并不完全相同。我将不得不想出另一种方法来做我想做的事情。

如果有人想知道我在说什么,我正在尝试在名为“Screeps”的编程游戏中为我自己的代码有效地修改类,该游戏售价 15 美元(因此没有游戏的人无法访问) .

我为我的疏忽而道歉。


推荐阅读