javascript / Node.js
how can I retrieve a reference to this/object inside a promise.then ?
var controller = new MyController(params);
controller.action_send();
/////////////////////////////////
class MyController{
constructor(params)
{
this.params = params;
}
action_send()
{
var promise = ext_lib.send();
promise.then(
function(details) {
this.action_save(details);
//(node:27014) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'action_save' of undefined
});
}
action_save(details)
{
save (this.params, details);
}
}
a PHPStorm warning says
Warns against a common mistake of trying to reference a member of an ECMAScript class via this.
qualifier in a nested function that is not a lambda.
this in a nested function that is not a lambda is the function's own 'this' and doesn't relate to the outer class.
tks from now
Use an arrow function.
Unlike a regular function, an arrow function does not bind this. Instead, this is bound lexically (i.e. this keeps its meaning from its original context).
Here are more details about it Arrow Functions
You want to use an arrow function: (details) => {...}. This will make the scope the same as outside of the function, and so this should be your class.
I would also recommend looking up the difference between the function syntax and the => syntax, someone can probably explain it better than I.
Just to add to the above answers, this is how your code should look like
promise()
.then(function (results) {
}.bind(this)
).catch(...);
Make sure your bind is just before closing then()
Related
(I looked through similar questions and could not find an answer for my problem, so asking here.)
Why is the code below giving me the error "ReferenceError: myText is not defined"?
async myFunction(myText: string)
{
await this.asyncThing.evaluate(() => {
console.log(myText); // error is thrown here
});
}
Not sure why the closure should not still be active when the log function is called. Is there a workaround for this behavior?
It looks like you're using Puppeteer. Although the function you pass to evaluate looks like a regular closure, it is actually serialized and sent across the wire to the browser. This means that it doesn't actually close over/have access to the variables in the parent scope. Instead you must explicitly pass those variables as arguments to the evaluate function:
async myFunction(myText: string)
{
await this.asyncThing.evaluate((myTextInBrowser) => {
console.log(myTextInBrowser);
}, myText); // <- pass the variable in here
}
This is not called out very well in the documentation, but it is under "Passing arguments to pageFunction:" https://pptr.dev/#?product=Puppeteer&version=v2.1.1&show=api-pageevaluatepagefunction-args
The variable isn't visible inside the closure because the closure has no argument.
Consider
await this.asyncThing.evaluate((myText) => {
console.log(myText);
});
I am not understanding why certain functions need the "= () =>" and other functions like 'onFirstDateRendered' don't have "= () =>" what's the difference between these 2 functions within a class based construct? thanks
onGridReady = (params) => {
this.gridApi = params.api
this.columnApi = params.columnApi
this.gridApi.sizeColumnsToFit()
}
onFirstDataRendered(params) {
params.api.sizeColumnsToFit()
}
I'm guessing these are both within a class construct. The first is a property declaration using an arrow function. The second is a method definition.
Sometimes people use the property-with-arrow-function form so that regardless of how the function is called, this during the call will be the instance of the class that the property was created on; often these are event handlers. In constrast, with method definitions, the value of this during the method call depends on the way the method is called.
I have a collection with a custom fetch function and a onFetchSuccess function.
The onFetchSuccess function needs to trigger some other events, so it is calling this.trigger and here is where it gets tricky.
It seems as if the context to this is lost as trigger is not found.
fetch(options = {}) {
console.log("fetching");
this.trigger(this.FETCH_START);
options.success = this.onFetchSuccess;
options.url = this.url;
Backbone.Collection.prototype.fetch.call(this, options);
console.log("fetched");
}
onFetchSuccess(model, response, options) {
console.log("success!")
this.trigger("change");
}
it just results in Uncaught TypeError: this.trigger is not a function
Am I missing something? From other answers(to different questions) it seems like this is the proper way to extend the fetch function
You need to change onFetchSuccess into an arrow function.
Arrow functions don't have their own context, unlike regular functions. That means the this of an arrow function is the this of the context in which the function was defined, while regular functions have their own this.
In you case you are using a regular function definition, the this of this.trigger is actually the this of the function, which doesn't have a trigger method.
If you are using the arrow function, the this will be the one containing a trigger method as you expected.
I have a method in my vue js element:
_deleteDesign : function(dsn)
{
//_deleteDesign
var url = '{{ url('/fapi/designsTmp/') }}/'+dsn.design_id;
axios.delete(url)
.then(function(){
this.$delete(this.creations, this.creations.indexOf(function(el){
return el.design_id = dsn.design_id;
}));
})
.catch(function(e){
alert('error deleting design');
})
debugger;
}
In this method I am using the indexOf function of Javascript, but vuejs reports me this error in the Chrome debugger:
this.creations.indexOf is not a function
What's the problem?
The this context has changed in the promise then handler because of new function declaration. One way to fix, would be to use ES6 arrow function which keeps the existing this binding for code within the function:
.then(() => {
this.$delete(this.creations, this.creations.indexOf(function(el){
return el.design_id = dsn.design_id;
}));
})
"indexOf" method can only be executed on variables that are type "string" or "array" (which is actually type "object").
So in your particular case "this.creations" must be either array or string. The issue is that you somehow ended up with the case when "this.creations" is not one of those types.
One possible solution is to add
console.log(typeof this.creations)
and monitor the type of this variable.
Also as previous answer mentioned the issue is that "this" changed context. One solution for this is to make copy of this object:
const self = this;
in the beggining of _deleteDesign function and to use "self" object instead of "this". Generally avoid using "this" object as much as possible.
When creating a Function.prototype how do you extract the function that is calling the prototype method without having the specify the function names? I have been researching and found that Javascript doesn't have super functionality, however all of the replacement methods that I have found seem to require using specific method names. Super with Known Prototype However, I want to be able to call the super of the Function.prototype without the prototype being on a specific constructor function.
Function.prototype.wrap = (func) => {
return (...args)=>{
return func(/*Function Caller*/, ...args);
}
}
function testFunc(arg){
console.log(arg);
}
testFunc = testFunc.wrap((originalFunction, args){
console.log("Testing Wrap ---");
originalFunction(args);
};
How can a pull the function that is calling the Function.prototype.wrap method and inject it into the secondary function without specifying the function names.
Arrow functions are lexical scoped, meaning that when writing an arrow function as a prototype method the this is inherited from the current scope, making it bind to the window object. This prevented the this keyword from binding to the function that called .wrap, and meant the code didn't work as expected.
Solution
Function.prototype.wrap = function (func) {
return (...args)=>{
return func(this, ...args);
}
}