This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
I am adapting a controller to the "controller as" syntax.
But while transforming the code, I remarked that I can't access the "scope" variables with this out of a function.
If I understand the concept of this, then this does access the object it is used in.
As example this code:
this.scopeVariable = undefined;
this.fooFunction = function () {
resource.get()
.$promise.then(function (result) {
this.scopeVariable = result.foo;
});
};
So when I try to set the scopeVariable with this, I actually try to access an object from fooFunction, right?
If this is the case, how can I grab an object outside of the function within the function?
Thanks for your answers!
You have this problem because the this keyword changes definition when in a different scope. That means that if you have a simple object e.g.
var a = {
b: function() {
console.log(this); // => will log the value of "a"
setTimeout(function() {
console.log('just some rubbish');
console.log(this); // => will log inner function scope instead of "a"
}, 200)
}
}
a.b(); // to see the results
To prevent this issue from happening you can reassign this to a variable which will stay intact through deeper scopes like this:
this.scopeVariable = undefined;
var self = this;
this.fooFunction = function () {
resource.get()
.$promise.then(function (result) {
// using self. instead of this. makes the difference here
self.scopeVariable = result.foo;
});
};
Capturing the this being the scope in a variable: var that = this:
var that = this;
this.fooFunction = function () {
resource.get()
.$promise.then(function (result) {
that.scopeVariable = result.foo;
});
};
Related
This question already has answers here:
How do JavaScript closures work?
(86 answers)
Closed 3 years ago.
How do I use the variable from the outer scope of the function. I have created this simple example here
var view = {
init(){
const targetOne = document.querySelector(".targetOne");
const targetTwo = document.querySelector(".targetTwo");
var val = "outer scope";
targetOne.addEventListener('click', (e) => {
console.log('target one', val)
});
targetTwo.addEventListener('click', this.handleEvent);
},
handleEvent(e) {
console.log('targetTwo ', val);
}
}
view.init();
JS fiddle link: https://jsfiddle.net/jr7b521x/50/
For the targetOne callback I can use the variable val, but when i define a function for the targetTwo callback, that variable val is not defined in the scope. I feel like I am missing something very simple here, I refreshed on scope chaining and closure but I am not able to get it
the variable val is within the scope of the init () function
for you to get it in the handleEvent function you will need to pass it by parameter or it must be a property of the view object
This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
class Foo {
constructor() {
this.foobar = "foobar";
}
bar() {
let _this = this;
return function() {
try {
alert("Attempt 1: "+foobar);//ReferenceError: foobar is not defined
myMethod();
} catch(err) {console.log(err);}
try {
alert("Attempt 2: "+this.foobar);//TypeError: this is undefined
this.myMethod();
} catch(err) {console.log(err);}
try{
alert("Attempt 3: "+_this.foobar);//Works!
_this.myMethod();
} catch(err) {console.log(err);}
}();
}
myMethod() {
alert("myMethod()");
}
}
new Foo().bar();
The above example is very simplified - the anonymous function inside bar() was a jQuery call originally, but for the sake of the question I didn't include that.
Why don't attempts 1 and 2 work? Do I have to use the _this trick to reference class variables/methods? How do I reference class variables/methods from nested functions?
Are you familiar with how the this keyword works in JavaScript? It's value will depend on how the function is called, not in how it is defined. For example, if you do the following:
var dog = {
greeting:"woof",
talk:function (){
console.log(this.greeting);
}
};
var cat={
greeting:"meow",
talk:dog.talk
};
dog.talk();
cat.talk();
You will see that when the talk function is called as a method of an object, that object will be used as the value of this.
The same happens with ES6 classes, where class methods are still JavaScript functions and the rules for deciding the value of this still apply. If you want to avoid declaring an auxiliar variable, you should look into using bind:
var mammal = {
greeting:"<noise>",
getTalk:function (){
return function(){
console.log(this.greeting);
};
},
getTalkBinded:function (){
return (function(){
console.log(this.greeting)
}).bind(this);
}
};
var dog={
greeting:"woof",
talk:mammal.getTalk(),
talkBinded:mammal.getTalkBinded()
};
var cat={
greeting:"meow",
talk:mammal.getTalk(),
talkBinded:mammal.getTalkBinded()
};
dog.talk();
cat.talk();
dog.talkBinded();
cat.talkBinded();
You are returning self-execution function execution result and during that function execution this it global context(not your class object). to make it work use () => {}() arrow function call syntax, as it captures current context, or function() { }.bind(this)().
See this simple example,
function a(){
this.someProp = 5;
console.log(this);
var _this = this; //so we explicitly store the value of `this` to use in a nested function
return function(){
//value of `this` will change inside this function
this.anotherProp = 6;
console.log(this);
//to use the methods and props of original function use `_this`
console.log(_this)
}
}
var c = a.call({}) //prints {someProp: 5}
c.call({}) //prints {anotherProps: 6} {someProp: 5}
This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 6 years ago.
I have the following code (simplified)
var Page = new UI('page.html');
Page.onLoad = function(html){
this.name = 'Page 1';
Util.test(this.run);
};
Page.run = function(){
console.log(this.name); // undefined
console.log(Page.name); // correct
};
var Util = function(){};
Util.prototype.test = function(callback){
// when finished run the callback
callback();
};
My question is why I can't use the this keyword if the execution leaves the object then comes back? Please explain what should I change to be able to access this again.
You can bind "this" to function run, like this.
Page.onLoad = function(html){
this.name = 'Page 1';
Util.test(this.run.bind(this));
};
You can find more information for function "bind". https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
The top of the article references another post regarding 'this', so, I thought I'd just provide the code. If you read the other post and the articles linked within, you should be able to follow this code.
function UI(html) {
this.name = html;
}
UI.prototype = {
onLoad: function () {
util.test(this);
},
run: function () {
console.log(this.name);
}
}
var util = (function () {
return {
test: function (ui) {
if (ui && ui.run) {
ui.run();
}
}
}
})();
var page = new UI("index.html");
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
When test.testHello(helloWorld.sayHello); runs, it doesn't recognize that I have inserted a new greeting is the greeting is undefined. I can use bind to make sure it runs it in the proper scope, I am not really sure why isn't it running in the proper scope to begin with. Could someone explain why this is happening and show me a better solution?
Solution: test.testHello(helloWorld.sayHello.bind(helloWorld));
http://jsfiddle.net/EzabX/
var HelloWorldClass = function() {
this.greetings = [];
}
HelloWorldClass.prototype.addGreeting = function(greeting) {
this.greetings.push(greeting);
}
HelloWorldClass.prototype.sayHello = function() {
document.getElementById('output').innerHTML += this.greetings;
this.greetings.forEach(function(greeting) {
greeting.execute();
})
}
var TestClass = function() {
this.testHello = function(callback) {
alert("TestHello is working, now callback");
callback();
}
}
var main = function() {
var helloWorld = new HelloWorldClass();
var test = new TestClass();
helloWorld.addGreeting({
execute: function() {
alert("Konichiwa!");
}
});
helloWorld.sayHello();
test.testHello(helloWorld.sayHello);
}
main();
Managing the this variable within the prototype function scope when called as a callback can be complicated for novice users. You don't always need a prototype for all functions on a class. If you really want to use a prototype function look at Javascript .bind(this) implementations. Google and Stackoverflow are your friend on that topic. Example: Preserving a reference to "this" in JavaScript prototype functions
Offending code with this referring to DOM Window object and not a HelloWorld instance:
this.greetings.forEach(function(greeting) {
greeting.execute();
})
A non-prototype version that works just great, easy to use. Fiddle: http://jsfiddle.net/EzabX/2/
var HelloWorldClass = function() {
var greetings = [];
this.greetings = greetings;
this.addGreeting = function(greeting) {
greetings.push(greeting);
};
this.sayHello = function() {
document.getElementById('output').innerHTML += greetings;
greetings.forEach(function(greeting) {
greeting.execute();
})
}; }
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 4 years ago.
I basically have an object, extended with a function through its prototype. Inside that function, another function exists, however when using this in this nested function, it does not seem to refer to the object, but the function.
For example,
var sampleObject = function() {
this.foo = 123;
}
sampleObject.prototype.getFoo = function() {
var nested = function() {
return this.foo;
}
return nested();
}
var test = new sampleObject();
window.alert(test.getFoo()); // undefined
The this.foo does not refer to the 123 value, but is undefined as this refers to the nested function, in which no foo exists. How can I access the 123 value from the nested function?
sampleObject.prototype.getFoo = function() {
var me = this;
var nested = function() {
return me.foo;
}
return nested;
}
By saving the value of this in a local variable, you make it explicitly part of the lexical context for that function and for all nested function scopes. Thus, on the call to "nested", that inner function will have its own scope (it's own this value), but it can still refer to the variable "me" in the enclosing scope.
In your example "this" refers to the window object because you didn't specify another context when you call the nested function and you get undefind because window.foo is undefined.
You can fix this in 3 ways.
1 - Use a variable to store the outside this - most used method
sampleObject.prototype.getFoo = function() {
var _this = this;
var nested = function() {
return _this.foo;
}
return nested();
}
2 - Use the bind method which bind the outer "this" to the inner one
sampleObject.prototype.getFoo = function() {
var nested = function() {
return this.foo;
}.bind(this);
return nested();
}
3 - Use the call method which can pass the context to the function
SampleObject.prototype.getFoo = function() {
var nested = function() {
return this.foo;
};
return nested.call(this);
}
The common work around for that is to use closure
sampleObject.prototype.getFoo = function() {
var _this = this;
var nested = function() {
return _this.foo;
}
return nested();
}
Some libraries add methods to automate this
Prototype adds Function.bind (http://prototypejs.org/doc/latest/language/Function/prototype/bind/)
Ext adds function.createDelegate (http://www.sencha.com/learn/Manual:Utilities:Function#createDelegate)
Javascript 1.8.5 adds function.bind (https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind)
tl;dr
Use arrow functions. They are available since ECMAScript 6:
var sampleObject = function() {
this.foo = 123;
}
sampleObject.prototype.getFoo = function() {
var nested = () => { // Changed this line.
return this.foo;
}
return nested();
}
var test = new sampleObject();
window.alert(test.getFoo());
Explanation
This is one of the main advantages of arrow functions. Your case is described in the section: No binding of this. The refference states:
Until arrow functions, every new function defined its own this value [...]
An arrow function does not create its own this context, so this has the original meaning from the enclosing context.
Apart from declaring it to var _this = this, I also see codes doing var that = this or var self = this.
Knowing your variable's scope is important as it might raises unexpected result.
This is an old question, but I give another solution for the sake of completeness. Another approach involves function binding.
sampleObject.prototype.getFoo = function() {
var nested = function() {
return this.foo;
}
return nested.bind(this)();
}
An ES6 way of doing this would be to use an Arrow Function. Basically, when you use an arrow function, it does not create it's own "this" context. So, using "this" would then refer to the parent function's context. Here's how the code would look:
sampleObject.prototype.getFoo = function() {
const nested = () => {
return this.foo; //"this" refers to parent function's context
}
return nested;
}
This is a known wart on JavaScript. The usual pattern is to assign this to another variable (often self) in the outer function, then access self from the inner funtction. This works.