Created
March 7, 2018 01:20
-
-
Save freakboy3742/d98c513e92a8badcb632d38581ae54b1 to your computer and use it in GitHub Desktop.
Desperately Seeking JSusan...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PyType { | |
constructor(name, bases, dict) { | |
this.name = name | |
this.bases = bases | |
this.dict = dict | |
} | |
__str__() { | |
return this.name | |
} | |
__call__(...args) { | |
console.log(`Create new <${this.name}> with ${args.length} args...`) | |
return `New <${this.name}> object created with ${args.length} args` | |
} | |
__getattribute__(attr) { | |
return this[attr] | |
} | |
__setattr__(attr, value) { | |
this[attr] = value | |
} | |
} | |
let descriptor = { | |
get: function(obj, attr) { | |
if (attr === Symbol.toPrimitive) { | |
console.log('get as str', obj) | |
console.log('__str__', obj.__str__) | |
return obj.__str__.bind(obj) | |
} else { | |
console.log(`Getting ${attr}`) | |
return obj.__getattribute__(attr); | |
} | |
}, | |
set: function(obj, attr, value) { | |
console.log(`Setting ${attr} to ${value}`) | |
obj.__setattr__(attr, value); | |
return true; | |
}, | |
apply: function(obj, that, args) { | |
console.log(`Calling object with ${args.length} arguments`) | |
return obj.__call__.apply(that, args) | |
}, | |
construct: function(obj, args) { | |
console.log(`Constructing object with ${args.length} arguments`) | |
throw "Python objects are constructed by invocation" | |
} | |
} | |
export function tester() { | |
let mt = new PyType('MyType', ['base1', 'base2'], {'attr1': 1, 'attr2': 2}) | |
let MyType = new Proxy(mt, descriptor) | |
console.log('mt = ', MyType) | |
console.log('mt.name = ', MyType.name) | |
console.log('mt.bases = ', MyType.bases) | |
console.log('mt.dict = ', MyType.dict) | |
console.log('mt.__str__() = ', MyType.__str__()) | |
console.log('mt.__call__() = ', MyType.__call__()) | |
// This line fails: | |
// Uncaught TypeError: MyType is not a function | |
// at Object.tester (test.js:69) | |
let obj = MyType(1, 2, 3, 4) | |
} |
(I got some of this info from https://stackoverflow.com/a/40878674 )
This is the simplest solution with the least amount of functionality, but it's guaranteed to work almost anywhere. Create a new function and clone an object's properties onto it.
class PyType {
constructor(name, bases, dict) {
this.name = name
this.bases = bases
this.dict = dict
}
__str__() {
return this.name
}
__call__(...args) {
console.log(`Create new <${this.name}> with ${args.length} args...`)
return `New <${this.name}> object created with ${args.length} args`
}
__getattribute__(attr) {
return this[attr]
}
__setattr__(attr, value) {
this[attr] = value
}
}
let descriptor = {
get: function(obj, attr) {
if (attr === Symbol.toPrimitive) {
console.log('get as str', obj)
console.log('__str__', obj.__str__)
return obj.__str__.bind(obj)
} else {
console.log(`Getting ${attr}`)
return obj.__getattribute__(attr);
}
},
set: function(obj, attr, value) {
console.log(`Setting ${attr} to ${value}`)
obj.__setattr__(attr, value);
return true;
},
apply: function(obj, that, args) {
console.log(`Calling object with ${args.length} arguments`)
return obj.__call__.apply(that, args)
},
construct: function(obj, args) {
console.log(`Constructing object with ${args.length} arguments`)
throw "Python objects are constructed by invocation"
}
}
const ObjectCallable_handler = {
get: function get(self, key) {
if (self.hasOwnProperty(key)) {
return self[key];
} else { return self.__inherit__[key]; }
},
apply: function apply(self, thisValue, args) {
return (self.__call__ || self.__inherit__.__call__).apply(self, args);
}
};
function ObjectCallable(cls) {
var p = new Proxy(function() { }, ObjectCallable_handler);
p.__inherit__ = cls;
return p;
}
export function tester() {
let mt = new PyType('MyType', ['base1', 'base2'], {'attr1': 1, 'attr2': 2})
let MyType = new Proxy(ObjectCallable(mt), descriptor)
console.log('mt = ', MyType)
console.log('mt.name = ', MyType.name)
console.log('mt.bases = ', MyType.bases)
console.log('mt.dict = ', MyType.dict)
console.log('mt.__str__() = ', MyType.__str__())
console.log('mt.__call__() = ', MyType.__call__())
// This line fails:
// Uncaught TypeError: MyType is not a function
// at Object.tester (test.js:69)
let obj = MyType(1, 2, 3, 4)
}
However, this approach will only answer your first question about callable classes. Probably you will get another error, but now with name reference. So here's a example about valid approach for deal with it:
var proxyAccount = new Proxy (ObjectCallable(new PyType('MyType', ['base1', 'base2'], {'attr1': 1, 'attr2': 2})) , {
get: function (target, name, receiver) {
console.log('get called for field: ', name);
if(!target.hasOwnProperty(name))
{
// do I have to store `name` into global variable, to reference it in `apply trap?
// methodName = name
return new Proxy(target[name],this);
}
return Reflect.get(target, name, receiver);
},
apply: (target,receiver,args) => {
console.log('methodName: ', 'I need methodName here. how do I get -withdraw- here?');
return Reflect.apply(target, receiver, args);
}
});
proxyAccount();
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I made some progress by extending
Function
twice-removed:Now it calls the
__call__
, butthis
is undefined within__call__
becauseFunction
is weird: