Best way to send "this" object to callback function [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
Lately a lot of my code has been looking like this...
function MyObjectClass (selector) {
this.color = "red";
this.$elt = $(selector);
// ... any other object vars here ...
// Example method for the object
this.showThenUpdateColor = function () {
// Keep a copy of "this" to use for callbacks
var o = this;
// Example of jQuery function that accepts a callback
o.$elt.fadeIn(function(){
// Inside of this callback function we need to access the main object
o.$elt.css({
"background-color" : o.color // This is where we need the "o"
});
});
}
}
var myObject = new MyObjectClass('#myObject');
myObject.showThenUpdateColor();
...where I have a callback inside of an object method. Typically I assign the object itself ("this") to a local variable (usually "o" because it's short and easy) which can be used in the callback.
Is this an optimal use of memory? Is there any danger of memory leaks? Is there a better way?

I would recommend having a look at jQuery.proxy(). It lets you create a function that, when executed, executes another function in the scope you specify. You could then write:
this.showThenUpdateColor = function () {
// Example of jQuery function that accepts a callback
this.$elt.fadeIn($.proxy(this._onFadeInComplete, this));
}
function _onFadeInComplete() {
this.$elt.css({
"background-color" : this.color
});
}

Related

Referencing the Correct 'this' Without Re-declaring 'this' Inside Nested Functions [duplicate]

This question already has answers here:
Pass correct "this" context to setTimeout callback?
(6 answers)
Closed 6 years ago.
I have a class with multiple methods and properties. One of those methods has a setTimeout() function embedded in it as such:
function myClass() {
this.some_property = "test";
this.PrintOnTimeout = function() {
// I can do var.self = this;
// but I can't help but feel like that would be inefficient
setTimeout(function timeoutPrint() {
// I want to reference this.some_property here.
// Currently this.some_property returns an error as
// this refers to PrintOnTimeout() rather than myClass().
});
}
}
Apologies in advance if there's an answer up on StackOverflow. I've looked around but pretty much everything I find talks about extended classes and super(). Perhaps super() is the answer here and I'm not understanding it? I'd use global, but I'd prefer to treat each instance of this class as potentially unidentified. So if there's a this.GetMainParent or something... otherwise, I appreciate the uprgrade.
edit 1: The goal isn't to pass 'this' in, which is obvious, but instead to reference the main block (or any particular block, if you set it up so) from anywhere inside a set of nested functions.
edit 2: The arrow function was the solution I needed, as shown by ASDFGerte.
You can use an arrow function to bind this, use bind(this) or close over a local variable that stores the property.
Note that unless you bind this to every function involved, you need to make sure all related functions are always called in the correct context, otherwise you are binding the nested functions to the wrong this:
function a(){
this.x = "hi";
this.y = function() {
setTimeout(() => { console.log(this.x); }, 100);
};
}
let obj = new a();
let outside = obj.y;
obj.y(); //y is being called with this === obj
outside(); //y is being called with this depending on strict mode, window or undefined.

"This" within es6 class method [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
For some reason I'm getting weird values for "this" in my es6 class...
'use strict';
class Clicker {
constructor(element) {
this.count = 0;
this.elem = element;
this.elem.addEventListener('click', this.click);
// logs Clicker { count:0, elem: button#thing} as expected
console.log(this);
}
click() {
// logs <button id="thing">...</button> as unexpected...
console.log(this);
this.count++;
}
}
var thing = document.getElementById('thing');
var instance = new Clicker(thing);
<button id="thing">Click me</button>
Question:
Why is the "this" inside of of the Clickers' click method referring to the dom node rather than ... itself?
More importantly, how do I refer to Clickers' count property from within its' click method if I can't use "this" to do it?
Why is the "this" inside of of the Clickers' click method referring to
the dom node rather than ... itself?
Because the specification for .addEventListener() is to set the this pointer to the DOM element that caught the event. That's how it is designed to work.
When passing a method as a callback where you want to override the value of this, you can use .bind() to force the desired value of this with it:
this.elem.addEventListener('click', this.click.bind(this));
Explanation:
All function calls in Javascript set a new value of this according to how the function is called. See this explanation for further info on that basic set of rules.
On top of that, when you do this:
this.elem.addEventListener('click', this.click);
You are just getting the this.click method and passing that method alone to addEventListener(). The value of this will be completely lost. It's as if you are doing this:
var m = this.click; // m here is just a reference to Clicker.prototype.click
this.elem.addEventListener('click', m);
On top of this, .addEventListener() is specifically built to set it's own value of this when it calls the callback (to point this at the element creating the event).
So, you can use .bind() as shown above to force the proper value of this to be in place when your method is called.
For reference, you may find this description of the six ways that this is set for a function call in Javascript to be useful.
Other Options
I find .bind() to be the clearest way of defining this, but you could also use either a local anonymous function:
var self = this;
this.elem.addEventListener('click', function() {
self.click();
});
or in ES6, an arrow function:
this.elem.addEventListener('click', () => this.click());
The arrow function will preserve the value of this for you automatically to avoid needing the self reference used in the prior example.

JS: this reference does not work [duplicate]

This question already has answers here:
Using this in event handler in strict javascript?
(3 answers)
Closed 7 years ago.
I want to encapsulate my Javascript code for certain objects in structures as indicated below. However, I ran into trouble with the semantics of this.
While this during tiles.init() refers to the tiles object, in the event handlers it refers to the event, i.e. I cannot use this to call other methods from my object.
Is there any way to pass the object to the event handlers, such that I do not have to use the global variable to call my own sub-routines and still retain this from the callback context?
I put up a JSFiddle here. This is the working JS part:
myData = {
'color': "red",
'makeRed': function(){
// don't want reference to global here!
$(this).css("color",myData.color);
},
'reset': function(){
$(this).css("color","");
},
'init': function(){
$("#click").hover(this.makeRed,this.reset);
}
};
myData.init();
I found several solutions like this and this idea to pass additional arguments. The question has been marked a duplicate of this, but using .bind() wastes the this required for the jQuery inside the callback.
Any idea how to get both tiles and this of the event context to the handler function without using globals?
You can use a closure variable in the init method
'init': function () {
var self = this;
$("#tiles div.tile").hover(function () {
self.hoverIn(this);
}, function () {
self.hoverOut(this);
});
}
Your construct is not working because this inside the hover callbacks does not refer to the tiles object

javascript Object - unreachable method [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
I have a javascript object with a handful of methods, and some of the methods reference each other. The methods become undefined in some situations, regardless of using the key word "this" with them. I'm not sure how to go about it. Here is a snippet of my object below. Method getContent() when accessed in onClickMngLinksBtn method becomes undefined when a button with onClickMngLinksBtn event binding is clicked. This same method works fine when accessed with:
InLineLinksObj.getContent()
I'm hoping the solution is something very basic to Objects in javascript. Any help is much appreciated.
function InLineLinks(formController, fieldController)
{
....
this.getContent = function(){
var field = this.getFieldController().getCustomFieldByName(this.content_field);
if(field){
return field.getValue();
}
return null;
};
this.onClickMngLinksBtn = function(){
var links = [];
var txt = this.getContent();
}
....
}
See here, here or here, or many other places for an explanation of scope and the this keyword in javascript. Essentially,
this always refers to the “owner” of the function we're executing
and when your method is triggered by a DOM event, then the owner is either the window or the HTML element that was clicked (or moused over, etc.), instead of the containing object.
A simple way around it in your case is to define a second variable self which will retain a reference to the containing object.
function InLineLinks(formController, fieldController) {
var self = this;
....
self.getContent = function(){
var field = self.getFieldController().getCustomFieldByName(self.content_field);
if(field){
return field.getValue();
}
return null;
};
self.onClickMngLinksBtn = function(){
var links = [];
var txt = self.getContent();
}
....
}
The way you have it, InLineLinks is a constructor and getContent is a method of it's instances.
Then, you must instantiate InLineLinks to reach getContent:
new InLineLinks().getContent()

How to use JQuery callback functions with Javascript objects

I have a Javascript object the following:
function extraFields(id) {
this.numActiveFields = 0;
...
this.addRow = function(quoteClass, rowClass) {
var remButton = $("<span></span>")
.addClass(rowClass)
.addClass(quoteClass)
.click(function() {
//here I want to refer to the object's variable, but instead refer
//to the JQuery object
this.numActiveFields++;
});
}
...
}
I want to change the object's variable from inside the callback function. How would I do that? Should I change the way I declare the object?
When you are in the callback function "this" is the "remButton" you created. Just save "this" in a variable before the callback and then use that instead.
For a better explanation please look at the link that mplungjan suggested:
Reference to an object from a callback function in jQuery

Categories

Resources