Access current element's 'this' object when an external 'this' was bind - javascript

Don't know if the question's title is too confusing but here I go.
If I got something like:
var Test = function(){
this.foo = a;
}
Test.prototype.init = function() {
$(document).on('change', '.form-control', this.myFunction);
}
Test.prototype.myFunction = function() {
console.log(this.foo);
console.log(this);
}
My understanding is that when printing 'this' in myFunction it would print the execution context of the function that made the call, in this case it'll print the execution context for .on('change' ...). So when printing this.foo since it doesn't exist in that context then undefined will be printed out.
To solve this issue and to access this.foo, I'm doing the following:
Test.prototype.init = function() {
$(document).on('change', '.form-control', (this.myFunction).bind(this));
}
Test.prototype.myFunction = function() {
console.log(this.foo);
console.log(this);
}
I'm binding 'this' to the function call, so this.foo would be printed out which is OK, but my question is, in that case how can I also get access to the execution context for .on('change' ...)??? Meaning, how can I access the 'this' that I had originally access to before the binding?
Thanks

Instead of binding, just use a reference variable. It will maintain the context, and still allow you to use the .on's context with this
Test.prototype.init = function () {
var context = this;
$(document).on('change', '.form-control', function () {
context.myFunction();
console.log(this); // `this` has context to the onchange
});
};

A bound function's this will always be bound to that same value. That means you no longer have access to the "original" value.
If you want to use both thises, you'll have to use one as this and the other as an argument. Or both as arguments.
var Test = function(a) {
this.foo = a;
this.init();
}
Test.prototype.init = function() {
// Set `this` to the calling test object, and window
// (which would be the original context in this case)
// as first parameter of `myFunction`. Swap the arguments
// if you wish to use them the other way around.
window.setTimeout(this.myFunction.bind(this, window), 500);
};
Test.prototype.myFunction = function(that) {
console.log(this.foo);
console.log(that.foo);
};
new Test(5);
Btw, ES6 arrow functions keep the environment they're defined in, meaning that this would point to your test object.
Test.prototype.init = function() {
window.setTimeout(() => this.myFunction(window), 500);
};

Related

How to pass down function with "this" keyword [duplicate]

I have a question concerning how the "this" pointer is treated in a nested function scenario.
Say I insert this following sample code into a web page. I get an error when I call the nested function "doSomeEffects()". I checked in Firebug and it indicates that when I am in that nested function, the "this" pointer is actually pointing to the global "window" object - which I did not expect. I must not be understanding something correctly because I thought since I declared the nested function within a function of the object, it should have "local" scope in relation to the function (i.e. the "this" pointer would be referring to the object itself like how it is in my first "if" statement).
Any pointers (no pun intended) would be appreciated.
var std_obj = {
options : { rows: 0, cols: 0 },
activeEffect : "none",
displayMe : function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect=="fade") { }
var doSomeEffects = function() {
// the 'this' pointer is referring to the window obj, why?
if (this.activeEffect=="fade") { }
}
doSomeEffects();
}
};
std_obj.displayMe();
In JavaScript the this object is really based on how you make your function calls.
In general there are three ways to setup the this object:
someThing.someFunction(arg1, arg2, argN)
someFunction.call(someThing, arg1, arg2, argN)
someFunction.apply(someThing, [arg1, arg2, argN])
In all of the above examples the this object will be someThing.
Calling a function without a leading parent object will generally get you the global object which in most browsers means the window object.
Since this appears to be among the most upvoted questions of its kind, let me add, after all these years, the ES6 solution using arrow functions:
var std_obj = {
...
displayMe() {
...
var doSomeEffects = () => {
^^^^^^^ ARROW FUNCTION
// In an arrow function, the 'this' pointer is interpreted lexically,
// so it will refer to the object as desired.
if (this.activeEffect=="fade") { }
};
...
}
};
this is not part of the closure scope, it can be thought of as an additional parameter to the function that is bound at the call site. If the method is not called as a method then the global object is passed as this. In the browser, the global object is identical to window. For example, consider the following funciton,
function someFunction() {
}
and the following object,
var obj = { someFunction: someFunction };
If you call the function using method syntax such as,
obj.someFunciton();
then this is bound to obj.
If you call someFunction() directly, such as,
someFunction();
then this is bound to the global object, that is window.
The most common work around is to capture this into the closure such as,
displayMe : function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect=="fade") { }
var that = this;
var doSomeEffects = function() {
// the 'this' pointer is referring to global
// that, however, refers to the outscope this
if (that.activeEffect=="fade") { }
}
doSomeEffects();
}
To understand this question , try to get the output for the following snippet
var myObject = {
foo: "bar",
func: function() {
var self = this;
console.log("outer func: this.foo = " + this.foo);
console.log("outer func: self.foo = " + self.foo);
(function() {
console.log("inner func: this.foo = " + this.foo);
console.log("inner func: self.foo = " + self.foo);
}());
}
};
myObject.func();
The above code will output the following to the console:
outer func: this.foo = bar
outer func: self.foo = bar
inner func: this.foo = undefined
inner func: self.foo = bar
In the outer function, both this and self refer to myObject and therefore both can properly reference and access foo.
In the inner function, though, this no longer refers to myObject. As a result, this.foo is undefined in the inner function, whereas the reference to the local variable self remains in scope and is accessible there. (Prior to ECMA 5, this in the inner function would refer to the global window object; whereas, as of ECMA 5, this in the inner function would be undefined.)
There's a difference between enclosure variables and "this". "this" is actually defined by the invoker of the function, while explicit variables remain intact inside the function declaration block known as the enclosure. See the example below:
function myFirstObject(){
var _this = this;
this.name = "myFirstObject";
this.getName = function(){
console.log("_this.name = " + _this.name + " this.name = " + this.name);
}
}
function mySecondObject(){
var _this = this;
this.name = "mySecondObject";
var firstObject = new myFirstObject();
this.getName = firstObject.getName
}
var secondObject = new mySecondObject();
secondObject.getName();
you can try it out here:
http://jsfiddle.net/kSTBy/
What's happening in your function is "doSomeEffects()", is being called explicitly, this means context or the "this" of the function is the window. if "doSomeEffects" was a prototype method e.g. this.doSomeEffects on say "myObject", then myObject.doSomeEffects() would cause "this" to be "myObject".
As explained by Kyle, you could use call or apply to specify this within the function:
Here is that concept applied to your code:
var std_obj = {
options: {
rows: 0,
cols: 0
},
activeEffect: "none",
displayMe: function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect == "fade") {}
var doSomeEffects = function() {
// the 'this' pointer is referring to the window obj, why?
if (this.activeEffect == "fade") {}
}
doSomeEffects.apply(this,[]);
}
};
std_obj.displayMe();
JsFiddle
Since it wasn't mentioned I will mention that using .bind() is a solution -
doSomeEffects=doSomeEffect.bind(this);
doSomeEffects();
}
};
std_obj.displayMe();
Here is a more simple example -
bad = {
name:'NAME',
z : function() {
function x() { console.log(this.name); };
x()
}
};
bad.z() // prints 'undefined'
good = {
name:'NAME',
z : function() {
function x() { console.log(this.name); };
x=x.bind(this);
x();
}
};
good.z() // prints 'NAME'
It is true that using an arrow function => looks slicker and is easy for the programmer. However, it should be kept in mind that a lexical scope is likely to require more work in terms of processing and memory to setup and maintain that lexical scope, compared to simply associating a function's this with a pointer via .bind().
Part of the benefit of developing classes in JS was to provide a method to make this more reliably present and available, to pivot away from functional programming and lexical scopes, and thus reduce overhead.
From MDN
Performance considerations
It is unwise to unnecessarily create functions within other functions if closures are not needed for a particular task, as it will negatively affect script performance both in terms of processing speed and memory consumption.
It's because "this" refers to the self object / local function.
var std_obj = {
options : { rows: 0, cols: 0 },
activeEffect : "none",
displayMe : function() {
if (this.activeEffect=="fade") { }
let This = this; // 'this' here is for the std_obj scope. Create a reference to 'this' if you want to use it elsewhere.
var doSomeEffects = function() {
// 'this' here refers to the doSomeEffects scope. If you don't want "this," you can still use "this" of the std_obj scope.
if (This.activeEffect=="fade") { }
}
doSomeEffects();
}
};
std_obj.displayMe();
I also got a warning "Potentially invalid reference access to a class field via this"
class MyListItem {
constructor(labelPrm) {
this._flagActive = false;
this._myLabel = labelPrm;
labelPrm.addEventListener('click', ()=>{ this.onDropdownListsElementClick();}, false);
}
get myLabel() {
return this._myLabel
}
get flagActive(){
return this._flagActive;
}
onDropdownListsElementClick(){console.log("Now'this'refers to the MyListItem itself")}}//end of the class

`this` inside inner functions [duplicate]

I have a question concerning how the "this" pointer is treated in a nested function scenario.
Say I insert this following sample code into a web page. I get an error when I call the nested function "doSomeEffects()". I checked in Firebug and it indicates that when I am in that nested function, the "this" pointer is actually pointing to the global "window" object - which I did not expect. I must not be understanding something correctly because I thought since I declared the nested function within a function of the object, it should have "local" scope in relation to the function (i.e. the "this" pointer would be referring to the object itself like how it is in my first "if" statement).
Any pointers (no pun intended) would be appreciated.
var std_obj = {
options : { rows: 0, cols: 0 },
activeEffect : "none",
displayMe : function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect=="fade") { }
var doSomeEffects = function() {
// the 'this' pointer is referring to the window obj, why?
if (this.activeEffect=="fade") { }
}
doSomeEffects();
}
};
std_obj.displayMe();
In JavaScript the this object is really based on how you make your function calls.
In general there are three ways to setup the this object:
someThing.someFunction(arg1, arg2, argN)
someFunction.call(someThing, arg1, arg2, argN)
someFunction.apply(someThing, [arg1, arg2, argN])
In all of the above examples the this object will be someThing.
Calling a function without a leading parent object will generally get you the global object which in most browsers means the window object.
Since this appears to be among the most upvoted questions of its kind, let me add, after all these years, the ES6 solution using arrow functions:
var std_obj = {
...
displayMe() {
...
var doSomeEffects = () => {
^^^^^^^ ARROW FUNCTION
// In an arrow function, the 'this' pointer is interpreted lexically,
// so it will refer to the object as desired.
if (this.activeEffect=="fade") { }
};
...
}
};
this is not part of the closure scope, it can be thought of as an additional parameter to the function that is bound at the call site. If the method is not called as a method then the global object is passed as this. In the browser, the global object is identical to window. For example, consider the following funciton,
function someFunction() {
}
and the following object,
var obj = { someFunction: someFunction };
If you call the function using method syntax such as,
obj.someFunciton();
then this is bound to obj.
If you call someFunction() directly, such as,
someFunction();
then this is bound to the global object, that is window.
The most common work around is to capture this into the closure such as,
displayMe : function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect=="fade") { }
var that = this;
var doSomeEffects = function() {
// the 'this' pointer is referring to global
// that, however, refers to the outscope this
if (that.activeEffect=="fade") { }
}
doSomeEffects();
}
To understand this question , try to get the output for the following snippet
var myObject = {
foo: "bar",
func: function() {
var self = this;
console.log("outer func: this.foo = " + this.foo);
console.log("outer func: self.foo = " + self.foo);
(function() {
console.log("inner func: this.foo = " + this.foo);
console.log("inner func: self.foo = " + self.foo);
}());
}
};
myObject.func();
The above code will output the following to the console:
outer func: this.foo = bar
outer func: self.foo = bar
inner func: this.foo = undefined
inner func: self.foo = bar
In the outer function, both this and self refer to myObject and therefore both can properly reference and access foo.
In the inner function, though, this no longer refers to myObject. As a result, this.foo is undefined in the inner function, whereas the reference to the local variable self remains in scope and is accessible there. (Prior to ECMA 5, this in the inner function would refer to the global window object; whereas, as of ECMA 5, this in the inner function would be undefined.)
There's a difference between enclosure variables and "this". "this" is actually defined by the invoker of the function, while explicit variables remain intact inside the function declaration block known as the enclosure. See the example below:
function myFirstObject(){
var _this = this;
this.name = "myFirstObject";
this.getName = function(){
console.log("_this.name = " + _this.name + " this.name = " + this.name);
}
}
function mySecondObject(){
var _this = this;
this.name = "mySecondObject";
var firstObject = new myFirstObject();
this.getName = firstObject.getName
}
var secondObject = new mySecondObject();
secondObject.getName();
you can try it out here:
http://jsfiddle.net/kSTBy/
What's happening in your function is "doSomeEffects()", is being called explicitly, this means context or the "this" of the function is the window. if "doSomeEffects" was a prototype method e.g. this.doSomeEffects on say "myObject", then myObject.doSomeEffects() would cause "this" to be "myObject".
As explained by Kyle, you could use call or apply to specify this within the function:
Here is that concept applied to your code:
var std_obj = {
options: {
rows: 0,
cols: 0
},
activeEffect: "none",
displayMe: function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect == "fade") {}
var doSomeEffects = function() {
// the 'this' pointer is referring to the window obj, why?
if (this.activeEffect == "fade") {}
}
doSomeEffects.apply(this,[]);
}
};
std_obj.displayMe();
JsFiddle
Since it wasn't mentioned I will mention that using .bind() is a solution -
doSomeEffects=doSomeEffect.bind(this);
doSomeEffects();
}
};
std_obj.displayMe();
Here is a more simple example -
bad = {
name:'NAME',
z : function() {
function x() { console.log(this.name); };
x()
}
};
bad.z() // prints 'undefined'
good = {
name:'NAME',
z : function() {
function x() { console.log(this.name); };
x=x.bind(this);
x();
}
};
good.z() // prints 'NAME'
It is true that using an arrow function => looks slicker and is easy for the programmer. However, it should be kept in mind that a lexical scope is likely to require more work in terms of processing and memory to setup and maintain that lexical scope, compared to simply associating a function's this with a pointer via .bind().
Part of the benefit of developing classes in JS was to provide a method to make this more reliably present and available, to pivot away from functional programming and lexical scopes, and thus reduce overhead.
From MDN
Performance considerations
It is unwise to unnecessarily create functions within other functions if closures are not needed for a particular task, as it will negatively affect script performance both in terms of processing speed and memory consumption.
It's because "this" refers to the self object / local function.
var std_obj = {
options : { rows: 0, cols: 0 },
activeEffect : "none",
displayMe : function() {
if (this.activeEffect=="fade") { }
let This = this; // 'this' here is for the std_obj scope. Create a reference to 'this' if you want to use it elsewhere.
var doSomeEffects = function() {
// 'this' here refers to the doSomeEffects scope. If you don't want "this," you can still use "this" of the std_obj scope.
if (This.activeEffect=="fade") { }
}
doSomeEffects();
}
};
std_obj.displayMe();
I also got a warning "Potentially invalid reference access to a class field via this"
class MyListItem {
constructor(labelPrm) {
this._flagActive = false;
this._myLabel = labelPrm;
labelPrm.addEventListener('click', ()=>{ this.onDropdownListsElementClick();}, false);
}
get myLabel() {
return this._myLabel
}
get flagActive(){
return this._flagActive;
}
onDropdownListsElementClick(){console.log("Now'this'refers to the MyListItem itself")}}//end of the class

How to read value from javascript function?

If I do this in javascript
var A = function() {
alert(this.foo);
};
A["foo"] = "bar";
A();
I expect to alert bar but I get undefined, does anyone know how I can make this work?
Thanks
The value of this is the object upon which the method was called (unless you make use of the new operator or something like call or bind). Since you didn't call the function as a method then it is the default object (window in a browser) unless you are in strict mode.
The only reference you have to the function in scope is A, so you can only access it via alert(A.foo).
If you had used a named function expression:
var A = function myFunction () {
then you would have had the variable myFunction locally scoped to that function which you could use instead of A.
this refers to the "parent" object of the function, not the function itself. There's no parent in the expression A(). To "make that work", you'd have to explicitly pass A as the this value:
A.call(A);
The way it's usually meant to work is this:
var A = {
alert: function () {
alert(this.foo);
}
};
A.foo = 'bar';
A.alert();
The A from A.alert() is used as this value inside alert().
var A = function() {
alert(this.foo);
};
A["foo"] = "bar";
A.call(A);
or
var A = function() {
};
A.prototype.alert = function () {
alert(this.foo);
}
var a = new A();
a["foo"] = "bar";
a.alert();

Why the property of this cannot be accessed directlly within a private function in a closure?

In my own answer for A JavaScript VM that interprets code written in JSON I stated that the "public" properties of a JavaScript closure cannot be accessed in a "private" function.
The example given in that post is
function anobject(){
var privatefunction = function(){
//publicfunction(); //wrong; you have no access to it
console.log(this); //refer to the global object, not the object creating
};
this.publicfunction = function(){
console.log(this); //refer to the object creating
}
}
I think the reason is for some backward compatibility issues privatefunction must belong to the global object. So the public function is only an anonymous function that assigned to a property of this. This explains why calling publicfunction will fail because it need to have a reference to this first.
However, the following fix is still not work:
function anobject(){
var privatefunction = function(){
//publicfunction(); //wrong; you have no access to it
console.log(this); //refer to the object creating
}.bind(this);
this.publicfunction = function(){
console.log(this); //refer to the object creating
}
}
As I explicitly specify that privatefunction should be bound with the object creating, calling publicfunction should work but it does not. I have to do the following:
function anobject(){
var privatefunction = function(){
this.publicfunction();
console.log(this); //refer to the object creating
}.bind(this);
this.publicfunction = function(){
console.log(this); //refer to the object creating
}
}
Another workaround (the way that I am using) is the following:
function anobject(){
var privatefunction = function(){
publicfunction();
console.log(this); //refer to the object creating
};
var publicfunction = function(){
console.log(this); //refer to the object creating
}
this.publicfunction = publicfunction;
}
Now is the question part. What is the reason behind this behavior? What is it trying to avoid by disabling access this's properties without explicit specification?
UPDATE: the main part of the question is : When the interpreter cannot find a name in the scope chains, why should'nt it have a look at the this properties?
The problem here is that the reference this is determined by the caller of the function/method, for example:
function anobject(){
// here "this" is the object
var privatefunction = function(){
// here "this" is the object **that called privatefunction()**
};
this.publicfunction = function(){
// this method will always be called by the object, so "this" is the object
}
}
To achieve what you want you could also try this:
function anobject(){
var that = this;
var privatefunction = function(){
[do what you like using "that"]
};
this.publicfunction = function(){
[here you can use "this" directly, or "that"]
}
}
See also how javascript scope works, here What is the scope of variables in JavaScript? and on the web.
In the second example, publicfunction() is delcared as a property of the object this:
this.publicfunction = function(){
console.log(this);
}
Therefore, this function is not directly accessible by its name publicfunction(), and that is independent of the context. The function does not actually belong to any context, but rather to the object of which it is a property.
In your example, when privatefunction() calls publicfunction(), this raises an error because there is no function declared as a variable with the name publicfunction(), and not because this's properties are not accessible:
function anobject(){
var privatefunction = function(){
//publicfunction(); // You cannot call publicfunction() because there is
// no function defined with this name
}.bind(this);
this.publicfunction = function(){
console.log(this);
}
}
Look at this example, publicfunction() is not accessible even within anobject():
function anobject(){
this.publicfunction = function() {
console.log(this);
}
// publicfunction(); // Wrong because publicfunction()
// was not defined as a variable
}
However, if publicfunction() was defined as a variable within the context of anobject(), then this function would be accessible by its name. For example you can simply declare function publicfunction() within the closure of anobject():
function anobject(){
function publicfunction() {
console.log(this);
}
publicfunction(); // You can access publicfunction() here
}
But in this case, publicfunction() is not accessible outside the execution context of anobject(), therefore it can be regarded as a 'private' function:
var a = new anobject();
if(typeof a.publicfunction === 'undefined')
console.log('Public function is undefined outside of anobject()');
As a result, that's why we use the this keyword to declare publicfunction(): it makes it accessible outside the context of anobject(), but doing so define this function only as a property of anobject().
Therefore the only way to access this function is by calling this.publicfunction():
function anobject(){
var privatefunction = function(){
this.publicfunction();
console.log(this);
}.bind(this);
this.publicfunction = function(){
console.log(this);
}
}
More details regarding the this keyword: How does "this" keyword work within a function?
Variable vs. Properties in JavaScript: http://javascriptweblog.wordpress.com/2010/08/09/variables-vs-properties-in-javascript/

This pointer from internal function

i have JavaScript components, that has following architecture:
var MyComponent = function(params)
{
setup(params);
this.doSomething()
{
// doing something
};
function setup(params)
{
// Setup
// Interaction logic
var _this = this; // "this" points to DOMWindow, not to created object
$(".some-element").click(function(){
_this.doSomething(); // it craches here, because of above
});
}
};
When something, being controlled by interaction logic, happens, sometimes i must forward execution to "public" methods of component.
In this situation, i have a problem with "this" pointer.
Sample code demonstrates it:
var Item = function()
{
this.say = function()
{
alert("hello");
};
this.sayInternal = function()
{
_sayInternal();
};
function _sayInternal()
{
this.say();
};
};
To test it,
Create an object:
var o = new Item();
This works fine:
o.say(); // alerts "hello"
This crashes:
o.sayInternal();
I get an error:
TypeError: Result of expression 'this.say' [undefined] is not a function.
I think, such a behaviour takes place, because _sayInternal() function is declared (and not assigned to object, like "this.say = function()"). This way, it is shared across all created objects and acts like a static function in C++.
Is this true ?
No, sayInternal is not shared between created objects. But you are right, the created objects don't have access to sayInternal as it is not assigned to them. This function is only local to the constructor function.
this always refers to the context a function is invoked in. If you call it like func(), then this refers to the global object (which is window in browser). If you set the function as property of an object and call it with obj.func(), then this will refer to obj.
If you assign a "bound" function to a variable and call it:
var method = obj.func;
method();
then this will again refer to the global object. In JavaScript, functions are like any other value, they don't have a special relationship to the object they are assigned to.
You can explicitly set the context with call or apply:
var MyComponent = function(params)
{
setup.call(this, params); // <- using `call`
this.doSomething()
{
// doing something
};
function setup(params)
{
// Setup
// Interaction logic
var _this = this; // "this" to new created object
$(".some-element").click(function(){
_this.doSomething();
});
}
};
or in you other example:
var Item = function()
{
this.say = function()
{
alert("hello");
};
this.sayInternal = function()
{
_sayInternal.call(this);
};
function _sayInternal()
{
this.say();
};
};
That said, this approach to assign functions to objects is not good, because every instance will have its own this.sayInternal function. So for the Item code above, every creation of an instance involves creating three functions too, which is a waste of memory.
Making use of prototype inheritance would be a better way:
var Item = function() {
};
Item.prototype = (function() {
function _sayInternal() {
this.say();
};
return {
say: function() {
alert("hello");
},
sayInternal: function(){
_sayInternal.call(this);
}
}
}());
This way, _sayInternal is only created once and all instances inherit (refer to) the prototype, so say and sayInternal also exist only once. The "trick" with the immediate function makes _sayInternal only accessible by say and sayInternal.

Categories