Мой собственный прокси для классов возвращает неопределенное значение, когда я получаю значения из него - PullRequest
0 голосов
/ 15 мая 2018

Я пытаюсь сделать версию Proxy, которая поддерживает классы. Это включает экземпляр, который обычный прокси не поддерживает. Вот что у меня так далеко:

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 работает, но индексирование класса возвращает неопределенное значение, а прокси-методы не вызываются. Object.getOwnPropertyDescriptors работает, и вы все равно можете получить значение таким образом. Возможно, что-то связано с самим классом Proxy ... Кто-нибудь знает, можно ли это исправить?

По сути, я хочу создать собственную версию Proxy, которая на самом деле является экземпляром класса, но при этом действует как Proxy.

EDIT: Вот мой оригинальный код:

{
	// 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
}

1 Ответ

0 голосов
/ 16 мая 2018

Берги заставил меня осознать, что Прокси поддерживает классы, но в используемом мной API есть какая-то странная ошибка, которую я предполагаю из-за того, как работает API. Он создает полностью изолированный vm (я думаю, что это даже не фактический узел js VM), который порождается из процесса js основного узла, и глобал каким-то образом передается в VM. Я предполагаю, что это связано с тем, как проходит глобальное, но я не могу понять, как это работает.

Реальный ответ на этот вопрос заключается в том, что прокси действительно поддерживают классы и instanceof, но в экземпляре VM и расширениях классов не работают точно так же на встроенных классах API. Я должен найти другой способ сделать то, что я пытаюсь сделать, я предполагаю.

Если кому-то интересно, о чем я говорю, я пытаюсь эффективно изменить классы для своего собственного кода в программной игре «Screeps», которая стоит 15 долларов в паре (поэтому недоступна для людей, у которых нет игра).

Я прошу прощения за мой плохой контроль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...