This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 4 years ago.
I don´t get why "this" in this case returns "NaN" :
function Counter() {
this.num = 0;
this.timer = setInterval(function add() {
this.num++;
console.log(this.num);
}, 1000);
}
And in this one it refers to "this.value":
function foo() {
this.value = 'Hello, world';
this.bar = function() {
alert(this.value);
}
}
var inst = new foo();
inst.bar();
I get that in the first case "this" is pointing to the Window object, I just don´t get why that´s the case.
Inside setInterval this will be completely new and it will have no idea about Counter. You can use bind to pass the context this to setInterval
function Counter() {
this.num = 0;
this.timer = setInterval(function add() {
this.num++;
console.log(this.num);
}.bind(this), 5000);
}
Counter()
Alternatively you can also use arrow function
function Counter() {
this.num = 0;
this.timer = setInterval(() => {
this.num++;
console.log(this.num);
}, 5000);
}
Counter()
The setInterval function barely looks like this:
function setInterval(callback, time, ...args) {
// native complicated code
callback(...args);
}
What matters here is the call (callback(...)), as JS determines the context by how you are calling the function. In your second example the context of bar is inst as you call it as inst.bar(), so you directly tell js what this is. If you call a function direclty, e.g.
const bar = inst.bar;
bar(); // call without context
you don't specify a context, and therefore this defaults to window
Related
This question already has answers here:
What does "this" refer to in arrow functions in ES6?
(10 answers)
Closed 6 years ago.
Why isn't this inside of the setTimeout equal to the object that invoked the render function when using arrow functions?
class X {
constructor(config) {
this.data = config.data;
this.render_ = config.render;
}
render() {
this.render_(this.data);
}
}
var x = new X({
data: [1, 2, 3],
render: (data) => {
setTimeout(() => {
console.log(this);
}, 200);
}
});
x.render();
Read the part of the arrow function documentation that says "Arrow functions used as methods"
in summary: arrow functions just simply do not bind this or their own version of this, but rather references the global Window object.
Because arrow functions are lexically bound. That means they take on the value of "this" at the time of declaration. They are not affected by other means of modifying the this value, including being called as a method or functions like bind, apply and call.
function F() {
this.type = 'F';
this.logTypeExpression = function() {
console.log(this.type);
};
this.logTypeArrow = () => {
console.log(this.type);
};
}
function G() {
this.type = 'G';
}
var f = new F();
var g = new G();
f.logTypeExpression(); // F
f.logTypeArrow(); // F
// Now lets give these functions to G
g.logTypeExpression = f.logTypeExpression;
g.logTypeArrow = f.logTypeArrow;
g.logTypeExpression(); // G
g.logTypeArrow(); // F(!) (That's because `this` was assigned by the arrow function)
At the time that the arrow function is created, this isn't bound to any object, so it still refers to window. Maybe you want to try console.log(x); if you want to refer to that specific instance?
The code below only holds a reference to the function you created using an object literal syntax.
this.render_ = config.render;
Using bind(this) will tell the function to use the parameter object as the this reference when calling the function in the instance of your X object.
class X {
constructor(config) {
this.data = config.data;
this.render_ = config.render.bind(this);
}
render() {
this.render_(this.data);
}
}
Also, it does not matter if it's an arrow function or a regular function expression in your code snippet.
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 does the "this" keyword work, and when should it be used?
(22 answers)
Closed 8 years ago.
I am learning javascript. Have two blocks of code in below.
As you can see that first one works just fine but second one does not. Different between them is that I use this.count to access the count variable defined in the counter2,
function counter1(start){
var count = start;
var increase = function(){
count++;
};
var getValue = function(){
return count;
};
return {
inc : increase,
get :getValue }
}
var c1 = new counter1(5);
c1.inc(); //is able to increase 1
console.log(c1.ge());//can return 6
function counter2(start){
var count = start;
var increase = function(){
this.count++;
};
var getValue = function(){
return this.count;
};
return {
inc : increase ,
get :getValue }
}
var c2 = new counter2(5);
c2.inc(); //can NOT access this.count
console.log(c2.ge());//return NaN
I am a little confused with the "this" in counter2 as you can see, when I debug the code, "this" is counter2, but just has no access the the count variable
So could you help me to understand why 'this' in counter2 is not have the access to the count variable?
and why I can access count variable in the increase function in counter1 even if I did not use "this". Does this makes the code "worse" (less accessible)?
Thanks
When you call a constructor function with the "new" keyword, the context variable "this" points to itself and is implicitly returned from the end of the constructor function. When you are explicitly returning your new object inc and get functions, you are no longer returning "this" that is created with the constructor anymore. To be able to use with "this", you need to expose inc and get functions on "this" within the constructor function:
function counter2(start) {
//ensure counter2 function was called with "new" keyword
if (!(this instanceof counter2)) {
return new counter2(start);
}
this.count = start;
this.inc = function(){
this.count++;
};
this.get = function() {
return this.count;
};
//When called with "new" this is implicitly returned, your constructed object.
//return this;
}
var c2 = new counter2(5);
c2.inc();
As others have pointed out, exposing "count" inside your explicitly returned object would also allow you to access count through "this.count" since count is now a part of the object that you are returning. In this case, "this" will point to the object itself (which will need a count defined).
function counter2(start) {
var count = start;
var increase = function(){
this.count++;
};
var getValue = function() {
return this.count;
};
return {
count: count,
inc: increase,
get: getValue
}
}
var c2 = new counter2(5);
c2.inc();
So to start off I think you should learn a little about the Constructor pattern and 'Inheritance' in javascript.
Constructor Pattern
When you call new counter2(5) the counter2 function attempts to create a new object which would be called this inside the function, so you can add functions to it, which will allow you to access the state of the variables, such as count.
If you are just learning javascript then it would probably be easier for you if you try not to use var inside your counter2 and use the this keyword and have your function looking like the following:
function Counter(start) {
this.count = start;
this.increase = function () {
this.count++;
}
this.get = function () {
return this.count;
}
}
This is the basics of the Constructor pattern in Javascript.
As I have said this inside the function refers to the object being created, which only happens because you used the new keyword. This can be a complicated subject, but what this is set to inside a function can be changed, which is why im linking Function#bind as some reading.
It can be alot to take in at first, but heres some basic reading to get you started:
Reading
(Constructor Pattern)[http://www.samselikoff.com/blog/2013/11/14/some-Javascript-constructor-patterns/]
(Inheritance and the prototype chain)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain]
(Function.prototype.bind)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind]
Good luck!!
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:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
Normally I'd assign an alternative "self" reference when referring to "this" within setInterval. Is it possible to accomplish something similar within the context of a prototype method? The following code errors.
function Foo() {}
Foo.prototype = {
bar: function () {
this.baz();
},
baz: function () {
this.draw();
requestAnimFrame(this.baz);
}
};
Unlike in a language like Python, a Javascript method forgets it is a method after you extract it and pass it somewhere else. You can either
Wrap the method call inside an anonymous function
This way, accessing the baz property and calling it happen at the same time, which is necessary for the this to be set correctly inside the method call.
You will need to save the this from the outer function in a helper variable, since the inner function will refer to a different this object.
var that = this;
setInterval(function(){
return that.baz();
}, 1000);
Wrap the method call inside a fat arrow function
In Javascript implementations that implement the arrow functions feature, it is possible to write the above solution in a more concise manner by using the fat arrow syntax:
setInterval( () => this.baz(), 1000 );
Fat arrow anonymous functions preserve the this from the surrounding function so there is no need to use the var that = this trick. To see if you can use this feature, consult a compatibility table like this one.
Use a binding function
A final alternative is to use a function such as Function.prototype.bind or an equivalent from your favorite Javascript library.
setInterval( this.baz.bind(this), 1000 );
//dojo toolkit example:
setInterval( dojo.hitch(this, 'baz'), 100);
i made a proxy class :)
function callback_proxy(obj, obj_method_name)
{
instance_id = callback_proxy.instance_id++;
callback_proxy.instances[instance_id] = obj;
return eval('fn = function() { callback_proxy.instances['+instance_id+'].'+obj_method_name+'(); }');
}
callback_proxy.instance_id = 0;
callback_proxy.instances = new Array();
function Timer(left_time)
{
this.left_time = left_time; //second
this.timer_id;
this.update = function()
{
this.left_time -= 1;
if( this.left_time<=0 )
{
alert('fin!');
clearInterval(this.timer_id);
return;
}
}
this.timer_id = setInterval(callback_proxy(this, 'update'), 1000);
}
new Timer(10);