Hard to explain JavaScript issue about the scope of "this" [duplicate] - javascript

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 7 years ago.
Sorry for the title, but it's really hard to put a title on this issue (feel free to suggest a better one).
My issue is best explained via this JsFiddle: http://jsfiddle.net/ryLhcn4q/2/
CS = {};
CS.OverviewController = {
foo: "bar",
render: function() {
console.log("Rendering. foo = " + this.foo);
}
};
CS.handleClick = function(callback) {
console.log("handleClick");
if (callback) {
callback();
}
};
$("button").click(function(e) {
CS.handleClick(CS.OverviewController.render);
});
If you click on the button, the console indicates that the value of foo is undefined. How can I have the correct scope of this, so that the console indicates bar as the value for foo?

You should use
CS.handleClick(CS.OverviewController.render.bind(CS.OverviewController));
.bind defines the context of the function. Or in other words it sets its this object to something.
Your example doesn't work because you refer a function out of its context. The this points to the global scope (i.e. the window object). So:
window.foo = 'global';
$("button").click(function(e) {
CS.handleClick(CS.OverviewController.render);
});
will output global -> jsfiddle

PFB the code, this will work
CS = {};
CS.OverviewController = {
foo: "foo",
render: function() {
console.log("rendering. foo = " + this.foo);
}
};
CS.handleClick = function(e, context, callback) {
console.log("handleClick");
if (callback) {
context[callback]();
}
};
$("button").click(function(e) {
CS.handleClick(e, CS.OverviewController, 'render');
});
JsFiddleUpdated
You can also use "apply" or "call"

Related

What is an efficient workaround for using this inside anonymous function? [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
Main concern is efficiency.
I am working on javascript scopes and one thing that I am confused about is this inside a function.
I have read many answers and I understand them. But what I am concerned about is efficiency. Have a look at my code.
class Fancy {
constructor () {
}
checkScope (callback) {
console.log('Inside checkScope');
callback ();
}
}
class Prog {
constructor () {
this.name = 'myProg';
this.fancy = new Fancy ();
}
run () {
var that = this;
this.fancy.checkScope(function () {
console.log('Name ', that.name);
});
}
}
var prog = new Prog ();
prog.run();
Now in run() I am storing reference of this in a local variable that. This is working for me. But is it safe? Is it efficient? If no, please suggest me a good strategy/trick.
Thanks :)
Yes it is safe, but you can use the new arrow syntax.It preserve the this.
class Fancy {
constructor () {
}
checkScope (callback) {
console.log('Inside checkScope');
callback ();
}
}
class Prog {
constructor () {
this.name = 'myProg';
this.fancy = new Fancy ();
}
run () {
// Here your don't need var that = this,
// because the arrow function gets the same this
this.fancy.checkScope( () => {
console.log('Name ', this.name);
});
}
}
var prog = new Prog ();
prog.run();
Every simple function has it's this, in your case your
function () {
console.log('Name ', this.name); // this is undefined in 'strict mode'
}
has its own this.So you need to keep the this outside the function and use with alias in the function.In ES6 there is a new arrow syntax function.Arrow functions don't override the this. In your case
run () {
this.fancy.checkScope( () => {
console.log('Name ', this.name);
});
}
the this in the run function and in the parameter function are the same. It means that in the arrow function scope the this refers to that this in which the arrow function was defined.
In the case of efficient, you don't need an extra variable.You don't pollute the local scope with an extra variable. In the performance there is no affect.

Javascript: Promises + this [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 6 years ago.
Consider the following code:
foo: function() {
var self = this;
var p1 = p2 = someFunctionThatReturnsAPromise();
Promise.all([p1, p2])
.then(self.bar);
}
bar: function(promises) {
var self = this;
console.log(self);
}
Output:
undefined
But if I do the following instead:
foo: function() {
var self = this;
var p1 = p2 = someFunctionThatReturnsAPromise();
Promise.all([p1, p2])
.then(function(result) {
self.bar(result);
});
}
bar: function(promises) {
var self = this;
console.log(self);
}
Output:
{ foo: [Function],
bar: [Function] }
I don't understand why the first call changes where this points in the bar function. Can someone enlighten me?
When you pass self.bar to the then method, you pass a function reference. Although it looks like you also specify it should be called on the self object, that is actually not what is happening. The self object is not included in that function reference. The this object's value is determined when a function is called, not when it is defined or passed as argument.
In your second example, self is the this object within the function context, because that is where you call the function from.
Another way to get it working is to force the function's this object to always be self, overriding the above described behaviour. You can achieve that with .bind():
Promise.all([p1, p2])
.then(self.bar.bind(self));

Why does a function value of an object not have its own scope? [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 6 years ago.
The following code outputs dafunc: this.foo = bar
var myObject = {
foo: "bar",
dafunc: function() {
console.log("dafunc: this.foo = " + this.foo);
}
};
myObject.dafunc();
Why?
Why doesn't the function dafunc have its own scope where this.foo is undefined? Don't functions have their own this in Javascript?
Functions don't have their own this, it is decided by the caller.
If you do myObject.daFunc() that will be myObject.
If you do var x = myObject.daFunc; x(); it will not be something useful.
If you do myObject.daFunc.apply(somethingElse) it will be somethingElse.
I think where the confusion comes from is that the this inside of the function is unrelated to the this in the scope that defined the function. So in that way, the function does have its own this.
var myObject = {
foo: "bar",
dafunc: function() {
setTimeout(function(){
// now we lost "this", this doesn't work
console.log("dafunc: this.foo = " + this.foo);
}, 0);
}
};
This is where the "fat-array" syntax that some versions of Javascript have comes in. Here this carries over from the defining scope:
setTimeout( () => {
// fat array "preserves" this
console.log("dafunc: this.foo = " + this.foo);
}, 0);
When you call it like this: myObject.dafunc(); the this value is myObject
in your code, if you try foo what happens? (its undefined)
In javascript, this refers to the object the function is being called from. The scope is considered using the object. Since function is called using the myobject object, it consists of myobject's scope which has foo defined. I think if said just foo instead of this.foo, it would consider the new foo variable, not the one from myobject's scope.

Scope clarification in javascript [duplicate]

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 keyword vs obj name in javascript [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 9 years ago.
Wondering what the difference between the two code below. In the first case I used this to refer to the object and in the second case I used the object name. Although both works I was wondering whether there is any real difference between the two.
(function() {
var app = {
init: function () {
app.addLun('Hello');
},
addLun: function(a) {
console.log(a);
}
};
});
})();
and
var app = {
init: function () {
this.addLun('Hello');
},
addLun: function(a) {
console.log(a);
}
};
});
})();
this refers to the context/scope of the function, so depending on how you call it, it could refer to app, window, or many other scopes...
app refers to the actual app object if it exists in that scope.
Using this and app are absolutely not the same. Take this (slightly contrived) example:
var app = {
init: {
foo: function () {
// Think 'this' is app?
this.addLun('Hello');
}
},
addLun: function(a) {
console.log(a);
}
};
var app2 = {
init: {
foo: function () {
app2.addLun('Hello');
}
},
addLun: function(a) {
console.log(a);
}
};
app2.init.foo(); // prints Hello
app.init.foo(); // error - no method called addLun
this is the current context, app is the object you have just created.
Yes, there is difference. If you want to have more, that one instance of app object (for example, you can clone it with jQuery.extend()), you need to use second variant for correct work.

Categories

Resources