I attempting to overwrite/proxy a function from a library class. I've done this by extending the class and defining a Proxy
object over the method.
Alas, like in this question, the this
object in the derived class is undefined. I can't seem to get those solutions working in my case. Perhaps due to use of Proxy
.
See example below:
class Structure {
constructor (name){
this.noDoors = 0
this.name = name
}
async addDoors(noDoorsToAdd){
this.noDoors += noDoorsToAdd
console.log(`${noDoorsToAdd} doors added to ${this.name}`)
return new Promise(r=>r())
}
}
const Building = class Building extends Structure {
constructor(conditionfunc,args){
super(args)
this.addDoors = new Proxy(this.addDoors, {
apply(target, thisArg, argumentsList){
//console.log("apply:",target, thisArg, argumentsList,conditionfunc(argumentsList[0]))
if (conditionfunc(argumentsList[0])){
console.log(`Correct password: About to add doors to ${thisArg.name}`)
target(argumentsList[1]);
}
else {
console.log(`Incorrect password: Doors not added to ${thisArg.name}`)
}
}
})
}
}
/******** Main Script *********/
let conditionfunc = (password) => {
if (password == '123456') { return true } else {return false }
}
myStructure = new Structure('Ty Bach')
myBuilding = new Building(conditionfunc,'Ty Mawr')
;(async()=>{
await myStructure.addDoors(1)
await myBuilding.addDoors('wrongpassword',7)
await myBuilding.addDoors('123456',4)
console.log(`${myStructure.name} has ${myStructure.noDoors} doors!`)
console.log(`${myBuilding.name} has ${myBuilding.noDoors} doors!`)
})();
Here I expect the myBuilding
object to end up with 4 doors.
The error messages on my console are:
1 doors added to Ty Bach
Doors not added to Ty Mawr
About to add doors to Ty Mawr
Ty Bach has 1 doors!
Ty Mawr has 0 doors!
(node:3732) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'noDoors' of undefined
at addDoors (MYPATH\proxytoy\test.js:11:3)
at Object.apply (MYPATH\proxytoy\test.js:26:6)
at MYPATH\proxytoy\test.js:51:23
at processTicksAndRejections (internal/process/task_queues.js:95:5)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:3732) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:3732) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Why is the this
undefined in the derived class' object?
How might I fix this, or achieve the same through some other way?
You are calling the original function without assigning this
.
Use target.call(thisArg, argumentsList[1])
instead
class Structure {
constructor(name) {
this.noDoors = 0
this.name = name
}
async addDoors(noDoorsToAdd) {
this.noDoors += noDoorsToAdd
console.log(`${noDoorsToAdd} doors added to ${this.name}`)
return new Promise(r => r())
}
}
const Building = class Building extends Structure {
constructor(conditionfunc, args) {
super(args)
this.addDoors = new Proxy(this.addDoors, {
apply(target, thisArg, argumentsList) {
//console.log("apply:",target, thisArg, argumentsList,conditionfunc(argumentsList[0]))
if (conditionfunc(argumentsList[0])) {
console.log(`Correct password: About to add doors to ${thisArg.name}`)
target.call(thisArg, argumentsList[1]);
} else {
console.log(`Incorrect password: Doors not added to ${thisArg.name}`)
}
}
})
}
}
/******** Main Script *********/
let conditionfunc = (password) => {
if (password == '123456') {
return true
} else {
return false
}
}
myStructure = new Structure('Ty Bach')
myBuilding = new Building(conditionfunc, 'Ty Mawr')
;
(async() => {
await myStructure.addDoors(1)
await myBuilding.addDoors('wrongpassword', 7)
await myBuilding.addDoors('123456', 4)
console.log(`${myStructure.name} has ${myStructure.noDoors} doors!`)
console.log(`${myBuilding.name} has ${myBuilding.noDoors} doors!`)
})();