This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
I am trying to call a function via this reference inside of jquery scope:
var Person = function(){
this.hello = function(){
console.log("hello!");
}
this.jump = function(){
$('.jump').on('click', function(){
this.hello();
});
}
}
Then I do:
var p = new Person();
When I click over the .jump element, the console prints an error describing that hello is not a function. I am not sure what is happening here, I am assumming that this is trying to call a function inside of jquery (not sure about it).
So, googling a little bit I found the Jquery.proxy() function that could be helpfull in my situation, but every time I try to understand it my head want to explote.
Use $.proxy() like so:
var Person = function(){
this.hello = function(){
console.log("hello!");
}
this.jump = function(){
$('.jump').on(
'click',
$.proxy(
function() {
this.hello();
},
this
)
);
}
}
Passing this as the 2nd argument to $.proxy() sends that context as the value of this inside the function defined in the first argument.
Try this,
var self = this;
this.jump = function(){
$('.jump').on('click', function(){
self.hello();
});
}
when you refer to "this" inside onclick, by default this refers to the DOM element found in the value of event.target
$('.jump').on('click', function(event) {
this.hello() /// <<-- this == event.target =~ $('.jump')
}
so, fortunately, you can use a closure
var self = this;
this.jump = function(){
$('.jump').on('click', function(){
self.hello();
});
}
Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
I tried searching for this for about an hour and can't seem to find a solution that works for me. I have a function (Function2) inside an object that is called by an interval. Function2 cannot find Function1, and is saying the method does not exist. Why might this be, or what is wrong with my syntax?
var ClassA = function ()
{
this.attribute = "";
this.function1 = function()
{
alert("Function 1");
};
this.function2 = function()
{
alert("Function 2");
this.function1(); <----- Does not exist?
};
this.function3 = function()
{
setInterval(this.function2, 5000);
};
};
var CLASS_A = new ClassA();
CLASS_A.function3();
The setInterval behaves asynchronously. When you provide this.function2 as parameter to setInterval, you're basically providing a callback method. When setInterval has reached 5000 it calls your callback method.
The "this" keyword changes depending on the context. The callback context is very different from your object's "ClassA" context. It's not the same "this".
The trick is to do this:
var ClassA = function(){
var that = this;
//And then everywhere else use that instead of this.
that.function1 = function() { ...
that.function2 = function() { ...
that.function1
that.function3 = function ....
}
Good luck.
You have to look carefully about what this means in JavaScript and in what context your function is being called. You can ensure that the context is what you intend by using the bind method of Function, as in the following edit:
var ClassA = function ()
{
this.attribute = "";
this.function1 = function()
{
alert("Function 1");
};
this.function2 = function()
{
alert("Function 2");
this.function1(); // Exists but only on the ClassA, not on Window
};
this.function3 = function()
{
setInterval(this.function2.bind(this), 5000);
};
};
var CLASS_A = new ClassA();
CLASS_A.function3();
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
As in, sometimes when I look at code by other people, they will go var self = this; or in jquery for example, go var $self = $(this);
is there a particular reason for doing so?
It preserves the value of this for use in functions defined inside the current function.
// Contrived example
var myObject = {
func: function () {
var self = this;
setTimeout(bar, 1000);
function bar () {
alert(this); // `window`
alert(self); // `myObject`
}
}
};
myObject.func();
By holding a reference to this in some context, you have the ability to access it in other contexts such as within member functions or forEach loops.
Consider the following example:
function ViewModel() {
var self = this;
self.linksArray = ["link1", "link2", "link3"];
self.linksArray.forEach(function(link) {
// this refers to the DOM window
// and self refers to the parent context (ViewModel)
});
};
As others have mentioned, you could set a variable to $(this) if you wish to use it in another function.
On practical example would be when doing an ajax call tied to an event on the page. Using JQuery:
<script>
$(document).on("click", ".mySelector", function () {
// Where we are in the click event, $(this) refers to whatever
// element has a class of mySelector that was clicked
var self = $(this);
theDiv.html('');
$.ajax({
cache: false,
type: "GET",
url: "/SomeAjaxMethod",
data: { },
success: function (data) {
// Trying to access $(this) here will return undefined, as
// we are technically in the callback method
// Where our event is based on a class, there is likely more
// than one element on the page with the class, so it would be
// difficult to get the exact element again without some other code
self.html(data);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("Ajax failed.")
}
}); // end ajax call
}); // end on mySelector class click
</script>
or:
<script>
$(document).ready(function () {
$('.foo').click(function () {
var self = $(this); // Whatever element that was clicked with foo class
$('.bar').each(function () {
var bar = $(this); // Current iteration of bar element in the loop
var baz = self; // self is still the initial value, but $(this) is not
}); // end bar loop
}); // end foo click
}); // end doc ready
</script>
The particular example (not using JQuery) is the function closure. Referencing this in a function closure refers to the function object, not the context in which the closure was defined. Your example is one way to deal with the closure problem:
var that = this;
function(){
that.something = 1;
}();
Another way to deal with this is with the apply method on the function:
function(arg){
this.something = 1;
}.apply(this, argumentArray);
The first argument in apply is the "this argument" that "this" will refer too.
One purpose of that would be to make this accessible to inner functions. for example:
function clickHandler(){
console.log(this); // this is body
var $self = this;
function inner(){
console.log(this); // this is window
console.log($self); // this is body
}
inner();
}
$("body").click(clickHandler);
Run it in console to get a sense.
This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Explanation asked about the value of 'this' in Javascript [duplicate]
(2 answers)
Closed 8 years ago.
Simple question. Why do we have set that = this? If we dont, we are in the global scope...but why?
var myObj = {
specialFunction: function () {
},
anotherSpecialFunction: function () {
},
getAsyncData: function (cb) {
cb();
},
render: function () {
var that = this;
this.getAsyncData(function () {
// this now refers to global scope....why?
that.specialFunction();
that.anotherSpecialFunction();
});
}
};
myObj.render();
Writing that = this doesn't change the scope. The way the anonymous function is called will always end up with this being global object,* because that's exactly what the spec says should happen. Using that = this is just a workaround.
You could make this always point to myObj by using Function.call:
var myObj = {
specialFunction: function () {
},
getAsyncData: function (cb) {
cb.apply(this);
},
render: function () {
this.getAsyncData(function () {
this.specialFunction();
});
}
};
and/or using Function.bind:
var myObj = {
specialFunction: function () {
},
getAsyncData: function (cb) {
cb();
},
render: function () {
function callback() {
this.specialFunction();
}
this.getAsyncData(callback.bind(this));
}
};
* Unless you're in strict mode, in which case this is undefined.
take a look at the this keyword in JavaScript and how it works. I’m sure we’ve all come across this issue:
$("myLink").on("click", function() {
console.log(this); //points to myLink (as expected)
$.ajax({
//ajax set up
success: function() {
console.log(this); //points to the global object. Huh?
}
});
});
this is a variable that is automatically set for you when a function is invoked. The value it’s given depends on how a function is invoked. In JavaScript we have a few main ways of invoking functions. I wont talk about them all today, but just the three ways most people use them; either when a function is called as a method, or on it’s own, or as an event handler. Depending on how a function is invoked, this is set differently:
function foo() {
console.log(this); //global object
};
myapp = {};
myapp.foo = function() {
console.log(this); //points to myapp object
}
var link = document.getElementById("myId");
link.addEventListener("click", function() {
console.log(this); //points to link
}, false);
Doing $("myLink").on("click", function() {}) means that when the element is clicked, the function is fired. But this function is bound as an event handler, so this is set to the reference to the DOM element myLink. The success method you define within the Ajax request is just a regular function, and as such when it’s invoked, this is set to the global object, as it is when any function that’s not an event handler or an object method is.
$("myLink").on("click", function() {
console.log(this); //points to myLink (as expected)
var _this = this; //store reference
$.ajax({
//ajax set up
success: function() {
console.log(this); //points to the global object. Huh?
console.log(_this); //better!
}
});
});
Source: http://tinyurl.com/melbl92
EDIT: in JavaScript the "this" context depends on how your function is called, example:
function helloWorld()
{
console.log(this);
}
And here two ways to call this function:
new helloWorld(); note that if you call your function in this
way, the context of this will be the context of the function +
prototype, so your console will show this: helloWorld {}
helloWorld(); if you call your function without of the "new",
the context of "this" will be global(Window), so your console will show
this: Window about:home
Ok, with this little explanation i will try to explain now why you
have sometimes to use self/that...
Imagine that you want to use this.name inside this.hello function. Like I said before, the context of "this" depends on how your function is called, so if you want to ensure that this.name inside of this.hello function refer to this.name outside is recommended that you use self/that to avoid what happens bellow
function helloWorld(){
var self = this;//or that = this
this.name = "YourName"
this.hello = function(){
console.log(this); //the context of "this" here will be: "hello {}"
return this.name; //undefined, because you don't have name attribute inside hello function
}
new this.hello(); //note how hello is called here...
}
var test = new helloWorld();
And here a good explanation about context x scope:
http://ryanmorr.com/understanding-scope-and-context-in-javascript/
This question already has answers here:
jquery using this to access object context when inside callback
(3 answers)
Closed 8 years ago.
I have a class Playlist :
function Playlist() {
this.episodes = [ /*episode list*/ ];
};
and I want to make a method displaying each episode :
Playlist.prototype.display = function() {
$('.episodeList').each(function(index) {
$(this).children('title').text(this.episodes[index].title);
});
}
The problem is that the 'this' at the end, before '.episodes[index]' represent the dom object selected and not my playlist.
How can I solve this problem ? Thanks.
Bind the function to your context:
$('.episodeList').each($.proxy(function(index, elem) {
$(elem).children('title').text(this.episodes[index].title);
}, this));
More on jQuery.proxy
If you use each on dom element, this inside each have reference to dom elements
For example:
Playlist.prototype.display = function(e)
{
$('.episodeList').each(function(index) {
console.log(this)
});
}
console.log prints dom element and it is correct.
Now put console log outside each like this:
Playlist.prototype.display = function(e)
{
console.log(this)
$('.episodeList').each(function(index) {
});
}
Now console.log should print PlayList function (your class). So "this" in each scope have reference to dom elements but this in Playlist.prototype.display scope have reference to Playlist function.
Solution is:
Playlist.prototype.display = function(e)
{
var self = this;
$('.episodeList').each(function(index) {
console.log(self)
console.log(this)
});
}
You need take "this" from Playlist scope and attribute to self var, so now self have refenrece to Playlist. Now you do each, so current this in each have reference to dom element but self variable still have reference to Playlist.
In your code $(this)=episodes[index] because it's in the each function. I think this is what you want,
Playlist.prototype.display = function() {
var element=$(this);
$('.episodeList').each(function(index,item) {
item.children('title').text(element.episodes[index].title);
});
}
A common practice in Javascript is to make a new variable for storing the current class, since the content of the this variable changes with context. Consider something like
function Playlist()
{
var self = this;
this.episodes = [/*episode list*/];
this.display = function()
{
$('.episodeList').each(function(index) {
$(this).children('title').text(self.episodes[index].title);
});
}
};
for your Playlist class definition, and call myPlaylist.display()
to display the content.
function test() {
this.str = "hello";
this.sayHello = function() {
document.write(this.str);
}
this.init = function() {
document.onkeydown = this.sayHello;
}
}
var testing = new test();
testing.init();
The above code should output "hello" on an onkeydown event.
But I get "undefined". How can I get this to work ?
The problem is with this.sayHello. When you assign the reference to the sayHello function on keydown, the reference to the context (object) is lost. When a key is pressed, this refers to the Document object as the callback is invoked as:
document.onkeydown(); // or for simplicity imagine - document.sayHello();
If you assigned the str variable on the document object, you would see the value logged,
document.str = "hello";
However, that is not what you'd want. You need to wrap the keydown event handler inside another function to preserve the context to that object. Two ways to go about this. You could either wrap the event handler inside another function, and preserve the reference to this.
this.init = function() {
var me = this;
document.onkeydown = function() {
me.sayHello();
};
}
Or, if you're using modern browsers, this has already been incorporated into ECMAScript 5 using the bind function.
this.init = function() {
var me = this;
document.onkeydown = this.sayHello.bind(this);
}