I am having a bit of trouble intercepting constructor calls to a library (so I can replay them later) while still maintaining the prototype chain. More concretely, I am working with a library (ThreeJS, but could be any library), and some code that uses this library. What I want to do is write a piece of code that modifies the library objects, so I can run a block of code every time a constructor is called.
Example: when a new scene is created, I want to print "new Scene created" to the console.
var scene = new THREE.Scene();
When the constructor takes arguments, I also want to log these arguments.
I am having a bit of trouble intercepting constructor calls to a library (so I can replay them later) while still maintaining the prototype chain. More concretely, I am working with a library (ThreeJS, but could be any library), and some code that uses this library. What I want to do is write a piece of code that modifies the library objects, so I can run a block of code every time a constructor is called.
Example: when a new scene is created, I want to print "new Scene created" to the console.
var scene = new THREE.Scene();
When the constructor takes arguments, I also want to log these arguments.
Share Improve this question edited Apr 8, 2015 at 15:39 Mathias Bak asked Apr 8, 2015 at 15:34 Mathias BakMathias Bak 5,1556 gold badges33 silver badges42 bronze badges 2-
1
Might be missing the point, but if you are the one calling
new ...
could you not just log the information yourself? – Joey Ciechanowicz Commented Apr 8, 2015 at 15:36 - My goal is to edit neither the library code or the code calling new, but only a third file that intercepts the constructor calls. – Mathias Bak Commented Apr 8, 2015 at 15:38
4 Answers
Reset to default 6I'm not sure about this, but... you could try something like...
// Backup the original constructor somewhere
THREE._Scene = THREE.Scene;
// Override with your own, then call the original
THREE.Scene = function() {
// Do whatever you want to do here..
THREE._Scene.apply(this, arguments);
}
// Extend the original class
THREE.Scene.prototype = Object.create(THREE._Scene.prototype);
Using proxy:
THREE.Scene = new Proxy(THREE.Scene, {
construct(target, args) {
console.log(`creating a ${target.name} with ${args}`);
return new target(...args);
}
});
Starting from @bvaughn code, this worked for me:
THREE._Scene = THREE.Scene;
THREE.Scene = function() {
const Scene = Function.prototype.bind.apply(THREE._Scene, arguments);
const scene = new Scene()
console.log("Intercepted scene:", scene)
return scene;
}
THREE.Scene.prototype = Object.create(THREE._Scene.prototype);
// Test
const scene = new THREE.Scene()
// Prints "Intercepted scene:", ....
The "Using proxy" answer by Yoz is correct for modern times (thanks!), however it doesn't quite work for a class implementation since you can't redefine the class's name as a variable.
Here's my example using a class. Here this is used to implement a typical "singleton" pattern (where only one instance of a class should ever exist).
It's in TypeScript, but just remove the type annotations and it will work in JS.
// Only one instance can exist per application so the actual implementation class
// is hidden behind a Proxy (below). Thus we implement the singleton pattern.
class MySingletonImpl {
constructor() { /* ... */ }
}
var instance: MySingletonImpl | null = null;
// Proxy the implementation's constructor to ensure only one instance ever exists.
export const MySingleton = new Proxy(MySingletonImpl, {
construct(target, args) {
if (!instance)
instance = new target(...args);
return instance;
}
});
VSCode, at least, is smart enough to see the proxy and still provides full hinting/checking support for the members of the actual implementation class. Don't know about other editors though.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744769652a4592681.html
评论列表(0条)