This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
I have a normal object in javascript, contenting functions and values.
This is my example object:
var MyObject = {
myData: 1,
a: function() {},
b: function() {}
}
Now in the function a there is some logic that fire on it, but it should change even the value of myData property.
But when i try get it from the method b, that value come as an undefined value, instead of the value changed.
I created a JsFiddle with a small example of the behaviour of the my object. I realized that it how Javascript behave, but I didn't understand why.
The issue is because this within the click handlers refers to the element which was clicked, not the object the handler functions are members of. You need to cache this:
a: function () {
var self = this;
$('.setValue').click(function() {
self.myData = 2;
});
},
b: function () {
var self = this;
$('.getValue').click(function() {
alert(self.myData);
});
}
Updated fiddle
In JavaScript, each function has its own this argument. In your case, you want to access the outer function's this variable so you should do something like this:
var that = this;
Here is the updated jsfiddle:
http://jsfiddle.net/xaaLQ/5/
Related
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 1 year ago.
I have some code here.
I am aware that this reference wont be carried in anonymous functions.
But here, even when using a function of an object, the this inside that is window.
var MyClass = function (div) {
this.array = [];
};
MyClass.prototype = {
addToArray: function (elem) {
this.array.push(elem);
},
processAndAdd: function(elemArray){
elemArray.forEach(this.addToArray);
}
}
var myObj = new MyClass();
myObj.processAndAdd([1, 2, 3]);
console.log('test');
Error: Line: this.array.push(elem);
push of undefined.
On inspection, the this here is window Object
I want to know why this is window here, and how to restructure my code to properly handle this.
The reference to this object is no more MyClass constructor after you pass the callback function body as callback to forEach. Bind the function body with the current this context and your code should work.
var MyClass = function (div) {
this.array = [];
};
MyClass.prototype = {
addToArray: function (elem) {
this.array.push(elem);
},
processAndAdd: function(elemArray){
elemArray.forEach(this.addToArray.bind(this));
}
}
var myObj = new MyClass();
myObj.processAndAdd([1, 2, 3]);
console.log('test');
This question already has answers here:
Javascript - How change object properties without reassign them
(4 answers)
Closed 3 years ago.
I am using angularJS, and have the following controller variables:
cont.flag = 0;
cont.obj = {objFlag: cont.flag, objFunction: cont.func};
cont.func = function() {
// do stuff
}
The cont.flag variable is bound to user input in the HTML. So when that value changes I want the objFlag to update which it is not currently doing. In addition the objFunction value seems to always be undefined. Is this because cont.obj is declared above cont.func?
EDIT: If it wasn't clear, the cont.flag variable is correctly being updated by the user input, it's just the pointer to cont.flag in my obj which is not updating. Also, objFunction is not getting populated with the function I pass it.
Here is a bit more information that I provided in a comment about why I have these variables in an object instead of manipulating them directly: So I have a series of functions that I want to chain together, but I want to control which functions get run. So I have an obj for each function: the objFlag which says whether the function should be added to the chain, and objFunction which is the actual function to be run. I wanted a way of associating the objFlag with the objFunction it goes with
The reason why objFlag is not change along with cont.flag has nothing to do with Angular. This is a native Javascript behavior.
This statement:
cont.obj = {objFlag: cont.flag, objFunction: cont.func};
only assigns an initial cont.flag value to objFlag and there is no ongoing link between objFlag and cont.flag
This is already explained
Javascript - How change object properties without reassign them
object property to dynamically change with the value of assigned variable
Let us think your code in other way
cont.flag = 0;
cont.obj = {objFlag: cont.flag, objFunction: cont.func};
cont.func = function() {}
which is equivalent to
var cont = {
flag: 0,
obj: {objFlag: cont.flag, objFunction: cont.func},
func: function() {}
}
console.log(cont.obj);
You can see the result, undefined cont here (Cannot read property 'flag' of undefined"). we can not access variable into another variable within same object.
So, you will think to use this here
var cont = {
flag: 0,
obj: {objFlag: this.flag, objFunction: this.func},
func: function() {}
}
console.log(cont.obj);
Again you will get undefined values because we can not access object elements with another variable. But we can use function to access them. So last option is to use a getter function for obj to return json with data of other variable into a variable. (in self-referencing json object)
var cont = {
flag: 0,
get obj() {return {objFlag: cont.flag, objFunction: cont.func}},
/*or*/
/* get obj() {return {objFlag: this.flag, objFunction: this.func}},*/
func: function() {}
}
console.log("Before change", cont.obj);
//change
cont.flag = 10;
console.log("After change", cont.obj);
UPDATE
Now, combining your case with above explanation where cont is controller's reference, how you can add a getter property in angular controller.
Object.defineProperty method is what you need. So your final code will be:
cont.flag = 0;
Object.defineProperty(cont, 'obj', {
get: function() {
return {objFlag: cont.flag, objFunction: cont.func}
}
});
cont.func = function() {}
// you can access obj property to see the values
console.log(cont.obj)
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
I am using Typescript for an Angular 2 project. I notice that when we use the keyword this inside a labmda expression vs a function, this refers to different things.
For example, let's say I have an Angular component like the following.
export class MyComponet {
isActive = true;
names = [ "john", "jeff", "jared" ];
doSomethingWithLambda() {
names.forEach( (value, index) => {
if(this.isActive) { //this.isActive refers to MyComponent.isActive
//do something...
}
});
}
doSomethingWithFunction() {
names.forEach( function(value, index) {
if(this.isActive) { //this.isActive is undefined, since this refers to the function
//do something
}
});
}
doSomethingWithFunction2() {
let isActive = this.isActive;
names.forEach( function(value, index) {
if(isActive) { //if we change isActive will this also change MyComponent.isActive?
//do something
}
});
}
}
What is really happening here (behind the scene, so to speak)? What's the magic behind this inside a lambda that makes it able to "correctly" refer to the outer class' fields? I understand this inside a function will refer to the function itself.
Also, I have a doSomethingWithFunction2 method that will reference MyComponent.isActive into a local variable. If I change that local variable, that should be like changing the one it references, right? (regardless of it being a "primitive" like integer/number or an "object" like JSON { })
The fat-arrow function syntax is shorthand for:
function () { }.bind(this);
bind is a Javascript ES5 method equivalent to this:
Function.prototype.bind = function bind(context) {
var func = this;
return function () {
return func.apply(context, arguments);
};
}
In regards to
Also, I have a doSomethingWithFunction2 method that will reference MyComponent.isActive into a local variable. If I change that local variable, that should be like changing the one it references, right? (regardless of it being a "primitive" like integer/number or an "object" like JSON { })
In Javascript, variables are like pointers and except for some limited cases (primitives and copy-on-write objects) will change the referenced value when mutated. Reassigning will not change the original value, e.g. isActive = false; but this.isActive = false would in fact re-assign the variable isActive on this which is now hopefully correctly assigned.
This has to do with how lambda function are implement in TS. this in arrow function is lexically inferred so it more in line with below code
function Person() {
var self = this; // Some choose that instead of self.
// Choose one and be consistent.
self.age = 0;
setInterval(function growUp() {
// The callback refers to the self variable of which
// the value is the expected object.
self.age++;
}, 1000);
}
So inside the lambda function it is not actually this but a context closer self. This may not be actual implementation but much closer to give you understanding of what is happening.
Now when you are outside the my impotent this refers to global var which would be window
The lambda function is similar to javascripts bind function.
Protip see your transpiled JS how your lambda function is transforming.
This question already has answers here:
How does "this" keyword work within a function?
(7 answers)
Closed 8 years ago.
I have a function in JavaScript:
function main() {
console.log(this);
}
How come this logs Document? Surely it should log function main?
If not, then how do I declare a variable within main to be accessed by the rest of the code as main.varName?
Thank you!
Hey you can do something like this.
But then this would look something like a class object.
<script>
function main() {
this.testVar = "124";
}
var testMain = new main();
alert(testMain.testVar);
</script>
The alternative is that you just create a normal global variable.
The way i am taking the code is a more class object way.
Hope i could help :)
The this keyword references the context of the function, not the function itself.
When you call a function as a method of an object, then this references the object, otherwise the context is the global context (document).
Example:
var o = {
name: 'myObject',
fn: function(){ alert(this.name); }
};
o.fn(); // alerts "myObject"
As a function is also an object, you can add properties to it:
function main() {
}
main.varName = 42;
alert(main.varName); // shows "42"
However, this is not a regular use of functions and objects. Normally main would be a plain object rather than a function if you want to access main.varName.
Also, check out the module pattern
var person = function(){
return module = {
setName: function(name){
module.name=name;
}
}
};
var bill = person();
bill.setName('bill');
console.log(bill.name);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript: Object Literal reference in own key’s function instead of ‘this’
I have this simple code :
var myObj = {
init: function ()
{
this.Name = "Royi";
this.BindMe();
}
BindMe: function ()
{
$('myButton').on("click", this.Work);
},
Work: function ()
{
var self = this; <--------
}
}
Running :
myObj.init();
This is a simple Object literal.
The problem is on the Work Method. I want to make it know this ( myObj)
there are 2 ways of doing it :
option #1
In BindMe , When clicking , transfer the context via :
$('myButton').on("click",{self:this}, this.Work);
and in Work do :
var self = e.data.self... //need also to add e
option #2
write var self = myObj ;
Question
Is there any other way of doing it ?
which is the better/correct way ?
Don't add it as data to the event object. Instead, use .bind() or the jQuery-ish (crossbrowser) proxy to provide the correct thisArg to the function (see MDN's introduction to the this keyword):
$('myButton').on("click", $.proxy(this, "Work"));
You could pass the context to the handler function as part of a closure:
$('myButton').on("click", (function(context) {
return function() {
context.Work
};
})(this));
Needless to say, this is cross browser, since it relies on one of the core features of JS.