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.
Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 3 years ago.
I've created a class and I'm trying to call a method from inside that class from another method inside that same class. I've seen online that some people say use 'this' keyword, but as you can see from the example, that doesn't work. Can someone please explain in simple terms how to call a class method from inside another method in that same class? Thanks!
class Form {
constructor() {
}
fn1 () {
console.log('fn1 calling fn2 now:')
this.fn2();
}
fn2 () {
console.log('fn1 called me')
}
}
let myForm = new Form();
myForm.fn1();
Example can be found here
The error I keep getting is this: Uncaught TypeError: this.fn2 is not a function
There's nothing wrong with the code you show embedded into your question - that should work just fine. The issue arises when you pass a method to .addEventListener() as a callback (which shows in the code you have a link to).
Change this:
document.getElementById('call-func').addEventListener('click', this.fn1);
to this:
document.getElementById('call-func').addEventListener('click', this.fn1.bind(this));
The problem is that passing this.fn1 loses the value of this so when the listener calls the callback later, the object that it belongs to is lost and then this inside of fn1() is wrong. In addition, .addEventListener() explicitly sets the this value to the DOM element that triggered the event (which is not your object).
The same thing would happen if you did this:
let f = this.fn1;
f();
Using .bind(this) rebinds the value of this when the listener calls it.
FYI, you could also do it this way with a fat-arrow function:
document.getElementById('call-func').addEventListener('click', () => this.fn1());
Or, an older way of doing it:
var self = this;
document.getElementById('call-func').addEventListener('click', function() {
self.fn1();
});
My preference is to use .bind(this).
More explanation on event listeners and this here: "This" within es6 class method
More explanation on the general concept of how this gets set when a function is called here: When you pass 'this' as an argument
Using ES6/ES2015 and webpack, I am trying to wrap my head around the little monster that is the keyword this.
I have a class Edit containing a static method change(event) and within that method I am trying to make a recursive call to the method itself (depending on a given variable).
In most cases I could just call this.change(event) but here the keyword this is already occupied by the jquery object that was calling the function instead of the containing class.
The easiest solution would be to just call Edit.change(event) instead, but there must be a cleaner solution. Every programming language I have encountered so far has had some reference to its containing class built in.
I promise I have checked the docs and other threads on stackoverflow, but no one I found seems to address this particular problem.
// main.js
'use strict';
const $ = require('jquery');
const Edit = require('./Edit');
$(document).ready(() => {
let thingsToAddToData = {
whatToDo: // defined here depending on context
someVariable: //defined here depending on context
};
$('table :input').change(thingsToAddToData, Edit.change);
}
and here the Edit class is defined
// Edit.js
class Edit {
static change(event) {
if(event.data.whatToDo === 'do_nothing'){
return false;
}
if(event.data.whatToDo === 'do_this_important_thing'){
// here some important stuff is done
return true;
}
if(event.data.someVariable === 'special_case'){
event.data.whatToDo = 'do_this_important_thing'
// THIS IS THE LINE THAT GIVES ME HEADACHES
return this.change(event);
}
// here some default stuff is done
}
}
module.exports = Edit;
The easiest solution would be to just call Edit.change(event) instead, but there must be a cleaner solution
No, this is indeed what you need to use to always refer to the Edit class. There's nothing messy with it, just use it.
You could also use this.change(event) if you weren't using the method as an event handler. Make sure to call it as a method:
$('table :input').change(thingsToAddToData, Edit.change.bind(Edit));
// or
$('table :input').change(thingsToAddToData, e => Edit.change(e));
Either of the answers by #Bergi, should work (using Function.prototype.bind or () => {}). However I think your problem is more structural. Since Edit.change is an event handler it doesn't make sense to call it directly, since it is supposed to be fired through events.
I would suggest firing the event again with some parameter changes (http://api.jquery.com/trigger/):
replace Edit.change(event); with this.trigger(event);
That way there is no need for calling the handler directly, and you don't need to change the this context, thus keeping the code more transparent.
Static methods operate on the class instead of instances of the class, they are called on the class. There are two ways to call static methods:
<ClassName>.methodName()
or
<class-instance>.constructor.methodName()
In static methods, the this keyword references the class. You can call a static method from another static method within the same class with this.
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()
I think the title is pretty self-descriptive.
I've building react components using the class notation, and I noticed that while handleSomething has to be manually bound to this, render and componentWillMount do not. Are method bound to this already? Is it ok to bind manually for notationally consistency's sake?
Understanding of 'this' in JavaScript
The 'this' keyword in a function is determined by the executing scope of the function. For example, the this in someFunction when calling with obj.someFunction() will be obj.
A more concrete example:
function handleClick() {
console.log(this.state.value);
}
var state = { value: 1 }; // declare a var in window
console.log("handleClick()");
handleClick(); // Logged 1. The 'this' in the method will be window, because the method is called in window
var obj = {
state: { value: 2 },
handleClick: function() {
console.log(this.state.value);
},
};
console.log("obj.handleClick();");
obj.handleClick(); // Logged 2. The 'this' is referred to obj because the method is called in obj.
// let's reassign the function to a temp var in window
var temp = obj.handleClick;
console.log("temp()");
temp(); // Logged 1. The 'this' in the function is referred to window because the method is called in window.
console.log("window.temp()");
window.temp(); // this is equal to the one above.
console.log("temp.bind(obj)");
temp.bind(obj)(); // Logged 2. Bind the method and call the method, so the 'this' in the function is referred to obj.
console.log("temp.bind(this)");
temp.bind(this)(); // Logged 1. Since this in the executing scope is window. This effectively is the same calling in this.
console.log("temp.bind(window)");
temp.bind(window)(); // Logged 1. This is equal to the one above.
Try it here: https://codepen.io/anon/pen/OvOpEa?editors=0012
A blog post about this: https://hackernoon.com/understanding-javascript-the-this-keyword-4de325d77f68
Back to your question
If you look at render, componentWillMount, and handleSomething you defined in your class, it will become apparent why you need to bind your handler to this.
render
// Rerender
ReactCurrentOwner.current = workInProgress;
var nextChildren = void 0;
{
ReactDebugCurrentFiber.setCurrentPhase('render');
nextChildren = instance.render();
if (debugRenderPhaseSideEffects) {
instance.render();
}
ReactDebugCurrentFiber.setCurrentPhase(null);
}
This is how react call redner(), where the instance is the object instance that has state, props, etc. You can try it very easily by putting a breakpoint in your render method and go back a call stack.
handleSomething
For example, if you define your class like this, with handleSomething as the onClick callback method of the button.
class Button extends Component {
handleSomething() {
// 'this' will be undefined.
}
render() {
return (<button onClick={this.handleSomething}>Test</button>);
}
}
If you click the button, this is how react calls the onClick handler method.
function callCallback() {
fakeNode.removeEventListener(evtType, callCallback, false);
// This is where react calls your method.
func.apply(context, funcArgs);
didError = false;
}
where func is handleSomething, and context is usually undefined in my debugging experience, and funcArgs is the arguments that being passed in the function.
apply is similar to bind. The first argument is used to specify the this of the function, and the second argument is an array of parameters to pass into the function.
See MDN for more information about apply: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
In this case, the method handleSomething is being called with undefined as this; Therefore, if you didn't bind the method, your this will be undefined.
I noticed that while handleSomething has to be manually bound to this,
render and componentWillMount do not. Are method bound to this
already?
They are called with the instance of your class, so they already have this as your instance without using bind. I guess you can kind of say it's already bound to this.
Is it ok to bind manually for notationally consistency's sake?
You don't need to bind this with react's lifecycle methods. If you really want to, I guess you can bind those methods to this as well (there might be some side effects that I don't know, since I didn't really look that deeply into their source), but this is like doing obj.handleClick.bind(obj)(); instead of obj.handleClick();. It is unnecessary and will spend some clock cycles doing something that's not needed.
I am trying to create a basic javascript framework that you can pass different things into, including functions for it to execute later. Right now, I'm in a more simple testing phase, but I can't quite get the function calling to work. A piece of my code is here:
[My JS Fiddle][1]http://jsfiddle.net/mp243wm6/
My code has an object that holds different data, and I want to call the method later, but with data that is available at the time of creation. Here is a code snippet of the function that uses the function that is passed to the object:
clickMe : function() {
this.obj.click(function() {
this.func();
});
}
Any suggestions or things I should read are welcome.
The problem is that there're two different contexts:
clickMe : function() {
// here is one
this.obj.click(function() {
// here is another
this.func();
});
}
You can simple pass the function as parameter, like the following:
clickMe : function() {
this.obj.click($.proxy(this.func, this));
}
http://jsfiddle.net/mp243wm6/2/
The problem:
Considering your code in the JSFiddle, you have:
onClick : function() {
this.obj.click(function() {
this.func();
});
},
As noted, you have different contexts going on here.
Consider the snippet this.obj.click(function() { this.func(); }). The first this here is a reference to the framework.events object. The second this here is a reference to whatever will be this when this function get called. In the case of your JSFiddle, when this.func gets called, this is actually the DOM object that represents the <div id="test">TEST</div> node. Since it doesn't have a func function, calling func() on it causes:
Uncaught TypeError: undefined is not a function
You have to understand the following: you have to pass the correct this in which you want the function func to be called.
The solution:
A couple of ways to make it work as you would like:
1. with bind
this.obj.click(this.func.bind(this));
This way, you are telling: "call my this.func function, but make sure that it will be called using the this that I am passing as a parameter". Vanilla JS, no $.proxy stuff.
JSFiddle
2. with a copy of the reference to the actual function
onClick : function() {
var theFunctionReference = this.func;
this.obj.click(function() {
theFunctionReference();
});
},
This way, you will not rely on the value of this outside of the context of the framework.events object.
JSFiddle
The issue is that this is not bound to the correct object. I would suggest you look into Function.bind() because that creates a function with this pointing to the right thing.