this keyword inside an object's function - javascript

I didn't understand the var self = this; in the below code. I know that "The value of this, when used in a function, is the object that "owns" the function.".Then this keyword inside the object's function refer to that object,right?However the comments of below codes says the opposite of that.
I'm confused about why we cannot use this keyword inside an object's function, in the below code? What does this refer to in below codes?
var util = require('util');
var EventEmitter = require('events').EventEmitter;
// #station - an object with `freq` and `name` properties
var Radio = function(station) {
// we need to store the reference of `this` to `self`, so that we can use the current context in the setTimeout (or any callback) functions
// !!!! -> using `this` in the setTimeout functions will refer to those funtions, not the Radio class
var self = this;
// emit 'close' event after 5 secs
setTimeout(function() {
self.emit('close', station);
}, 5000);
// EventEmitters inherit a single event listener, see it in action
this.on('newListener', function(listener) {
console.log('Event Listener: ' + listener);
});
};
// extend the EventEmitter class using our Radio class
util.inherits(Radio, EventEmitter);
// we specify that this module is a refrence to the Radio class
module.exports = Radio;
I read similar posts and understood, however i couldn't understand the comments of below codes. Also, nobody mentioned about the this keyword inside a function's function argument inside a constructor. Especially the second sentence which is written bold makes me confused totaly :
We need to store the reference of this to self, so that we can
use the current context in the setTimeout (or any callback) functions.
using this in the setTimeout functions will refer to those funtions,
not the Radio class
Quoted from : http://www.hacksparrow.com/node-js-eventemitter-tutorial.html

The value og the this keyword will change value based on the current context. The complete description of how this works is somewhat complicated. See MDN for more details.
In your case, this will have a different value when the anonymous function inside the setTimeout call is eventually called. However, the self variable will still be available.

The purpose of 'this' in a function is a reference to the object that called the function. Since you're passing an anonymous function to the window with setTimeout, any 'this' call within that function will be referencing the window object.
You could use the Javascript Bind function to preserve the context of 'this' within the callback function regardless of where it's called.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Your setTimeout function would look like this:
setTimeout(function() {
this.emit('close', station);
}.bind(this), 5000);

Related

How to get "this" to reference parent object? [duplicate]

I read some other answer about this topic but I'm not sure I understand how this keyword works inside addEventListener.
const button = document.querySelector('button');
function foo() { console.log(this) }
button.addEventListener('click', foo);
foo is a regular function inside addEventListener, it's not a method on button object. When foo is called should be executed in the context of the global object, therefore this should be equal to window and not to button.
Looks like a situation similar to this example:
const obj = {
method: function (cb) {
console.log('method', this); // `this` === `obj`
return cb();
}
};
obj.method(function() {
console.log('cb', this); // `this` === `window`
});
Where obj could be considered as button, method could be addEventListener and cb the callback inside addEventListener.
I know I can use bind to change the context of this but I want to understand more in depth why it works like that.
Why this inside addEventListener callback is invoked on the context of the current element instead of the global object?
If we are using functions which have been defined using function keyword as an event handler, then that event handler function executes in the context of the element on which event was binded
button.addEventListener('click', foo);
so, in this case, this value inside foo will be button element.
If we use arrow functions instead of them then this value will be the window object
The reason is this in an arrow function has the same value as the context in which the arrow function was created
button.addEventListener('click', () => { console.log(this) // window } );
More about lexical this
What is lexical 'this'?
While we know that event listeners are executed with 'this' set to the event target, the below lines of code inside the EventTarget.prototype.dispatchEvent method in the EventTarget link that you found will answer your question as to how it is implemented.
for (var i = 0, l = stack.length; i < l; i++) {
stack[i].call(this, event);
}
The 'stack' array has the callback functions and they are invoked using .call by passing in the event target instance (this) and event as arguments.
As event handler is a type of callback, they are passed as a parameter to the function. Let's create a simple function and passed one callback as a parameter to it and see how it actually works.
function testCallBack(fn){
console.log('inside testCallBack');
fn('Hello I am a callBack')
}
testCallBack(foo);
function foo(param){
console.log(param);
}
// Outputs:
inside testCallBack
Hello I am a callBack
Every scope in JavaScript has a this object that represents the calling object for the function.
That's the reason why this inside addEventListener callback is invoked on the context of the current element instead of the global object.
Refer below code for more clear understanding:
function sayNameForAll() {
console.log(this.name);
}
var person1 = {
name: "Rajat",
sayName: sayNameForAll
};
var person2 = {
name: "pldg",
sayName: sayNameForAll
};
var name = "Sidd";
person1.sayName(); // outputs "Rajat" here calling object is person1, so this represents person 1
person2.sayName(); // outputs "pldg"
sayNameForAll(); // outputs "Sidd"
So when you call button.addEventListner('click',foo), your calling object is button.
Event listeners are executed with this set to the object that triggered the event, as one listener can listen to events of many objects.
A regular function invocation however does not set this if the invocation expression does not contain a member access via .. In those cases, without "use strict" active, this will become the global context, which is window in the browser.
If you want this for cb to be obj, you could replace cb() with cb.apply(this), which would set cb's this to that of the enclosing function.
A final warning: these this mechanics only work for functions defined with the function keyword (and similar mechanics). The this inside of an arrow function becomes locked to that of the enclosing scope at the time of definition.
Just like you can use bind or call to set this to whatever you want, the browser APIs can also call your functions with any value set to this. It’s used in a bunch of weird ways and isn’t very consistent. Outside of classes and methods, this is more like a secret extra argument to a function. In this case you could avoid needing it by getting the button element from event.target.

Javascript event listener works with arrow function, not with normal function [duplicate]

Below I am creating an object in JavaScript. Within the constructor I am setting up an event listener. The problem is that when the event gets fired, this.prop cannot be found, and undefined prints out. How do I solve this?
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
When the event handler gets called, "this" no longer references the "someObj" object. You need to capture "this" into a local variable that the mouseMoving function will capture.
var someObj = function someObj(){
this.prop = 33;
var self = this;
this.mouseMoving = function() { console.log(self.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
I'm assuming "someObj is a constructor, i.e. intended to be called with as new someObj(), otherwise "this" will be the global scope.
The "this" keyword can be confusing in JavaScript, because it doesn't work the same way as in other languages. The key thing to remember is that it is bound to the calling object when the function is called, not when the function is created.
The javascript built-in Function.prototype.bind() is intended for this purpose.
For example:
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving.bind(this),true);
}
More on the bind method here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Other wise you have to pass a reference of the object someObj to the element and use that reference in the line:
console.log(this.referenceToObject.prop); //this references the DOM element in an event.
From Section 4.3 of JavaScript: The Good Parts by Douglas Crockford:
Invoking a function suspends the
execution of the current function,
passing control and parameters to the
new function. In addition to the
declared parameters, every function
receives two additional parameters:
this and arguments. The this parameter
is very important in object oriented
programming, and its value is
determined by the invocation pattern.
There are four patterns of invocation
in JavaScript: the method invocation
pattern, the function invocation
pattern, the constructor invocation
pattern, and the apply invocation
pattern. The patterns differ in how
the bonus parameter this is
initialized.
Crockford continues to explains the binding of 'this' in each of these patterns, as follows:
The Method Invocation Pattern:
When a function is stored as a property of an object, we call it a method. When a method is invoked, this is bound to that object.
The Function Invocation Pattern:
When a function is invoked with this pattern, this is bound to the global object. This was a mistake in the design of the language.
The Constructor Invocation Pattern:
If a function is invoked with the new prefix, then a new object will be created with a hidden link to the value of the function's prototype member, and this will be bound to that new object.
The Apply Invocation Pattern:
The apply method lets us construct an array of arguments to use to invoke a function. It also lets us choose the value of this. The apply method takes two parameters. The first is the value that should be bound to this. The second is an array of parameters.
You could use a variable named 'me', to avoid conflict with the global JavaScript variable 'self':
function someObj() {
var me = this;
this.prop = 33;
this.mouseMoving = function() {
alert(me.prop);
}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
First, you need to understand how 'this' works in JavaScript. 'this' keyword doesn't behave how it behaves in other languages like C# or Java. Read following post to understand more,
What is the rationale for the behavior of the 'this' keyword in JavaScript?
Once you understand that, as Matthew outlined in his code, you can save reference to 'this' and use that reference inside the mouseMoving function.
Though overall, I will advise that you use a JavaScript framework (e.g. jQuery, YUI, MooTools) which will take care of these issues for you. E.g. In Internet Explorer, you use addEvent to attach event and not addEventListenr.
You have some typos on your function declaration.
Your prop variable is also defined as a "public" or "visible" member (by using this.prop), doing so forces you to store the reference of this from the outer function (that is actually a reference to the object instance), as a "private" member of the function (using var) to get access the instance of the created object and read the "public" prop member.
You have some alternatives to rewrite this code:
function someObj (){
var self = this;
this.prop = 33;
this.mouseMoving = function() { alert(self.prop);} // You access the current
// instance, stored in *self*
// since *this*, inside the
// function, is in another
// context.
//...
}
var mySomeObj = new someObj(); // Object instantiation
Or you could:
function someObj (){
var prop = 33;
this.mouseMoving = function() { alert(prop);}
//...
}
var mySomeObj = new someObj(); // Object instantiation
The variables declared with var, are accesible to the functions declared inside of the major constructor function, this feature is known as Closures.

Cannot "reach" class properties from inside method [duplicate]

Below I am creating an object in JavaScript. Within the constructor I am setting up an event listener. The problem is that when the event gets fired, this.prop cannot be found, and undefined prints out. How do I solve this?
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
When the event handler gets called, "this" no longer references the "someObj" object. You need to capture "this" into a local variable that the mouseMoving function will capture.
var someObj = function someObj(){
this.prop = 33;
var self = this;
this.mouseMoving = function() { console.log(self.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
I'm assuming "someObj is a constructor, i.e. intended to be called with as new someObj(), otherwise "this" will be the global scope.
The "this" keyword can be confusing in JavaScript, because it doesn't work the same way as in other languages. The key thing to remember is that it is bound to the calling object when the function is called, not when the function is created.
The javascript built-in Function.prototype.bind() is intended for this purpose.
For example:
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving.bind(this),true);
}
More on the bind method here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Other wise you have to pass a reference of the object someObj to the element and use that reference in the line:
console.log(this.referenceToObject.prop); //this references the DOM element in an event.
From Section 4.3 of JavaScript: The Good Parts by Douglas Crockford:
Invoking a function suspends the
execution of the current function,
passing control and parameters to the
new function. In addition to the
declared parameters, every function
receives two additional parameters:
this and arguments. The this parameter
is very important in object oriented
programming, and its value is
determined by the invocation pattern.
There are four patterns of invocation
in JavaScript: the method invocation
pattern, the function invocation
pattern, the constructor invocation
pattern, and the apply invocation
pattern. The patterns differ in how
the bonus parameter this is
initialized.
Crockford continues to explains the binding of 'this' in each of these patterns, as follows:
The Method Invocation Pattern:
When a function is stored as a property of an object, we call it a method. When a method is invoked, this is bound to that object.
The Function Invocation Pattern:
When a function is invoked with this pattern, this is bound to the global object. This was a mistake in the design of the language.
The Constructor Invocation Pattern:
If a function is invoked with the new prefix, then a new object will be created with a hidden link to the value of the function's prototype member, and this will be bound to that new object.
The Apply Invocation Pattern:
The apply method lets us construct an array of arguments to use to invoke a function. It also lets us choose the value of this. The apply method takes two parameters. The first is the value that should be bound to this. The second is an array of parameters.
You could use a variable named 'me', to avoid conflict with the global JavaScript variable 'self':
function someObj() {
var me = this;
this.prop = 33;
this.mouseMoving = function() {
alert(me.prop);
}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
First, you need to understand how 'this' works in JavaScript. 'this' keyword doesn't behave how it behaves in other languages like C# or Java. Read following post to understand more,
What is the rationale for the behavior of the 'this' keyword in JavaScript?
Once you understand that, as Matthew outlined in his code, you can save reference to 'this' and use that reference inside the mouseMoving function.
Though overall, I will advise that you use a JavaScript framework (e.g. jQuery, YUI, MooTools) which will take care of these issues for you. E.g. In Internet Explorer, you use addEvent to attach event and not addEventListenr.
You have some typos on your function declaration.
Your prop variable is also defined as a "public" or "visible" member (by using this.prop), doing so forces you to store the reference of this from the outer function (that is actually a reference to the object instance), as a "private" member of the function (using var) to get access the instance of the created object and read the "public" prop member.
You have some alternatives to rewrite this code:
function someObj (){
var self = this;
this.prop = 33;
this.mouseMoving = function() { alert(self.prop);} // You access the current
// instance, stored in *self*
// since *this*, inside the
// function, is in another
// context.
//...
}
var mySomeObj = new someObj(); // Object instantiation
Or you could:
function someObj (){
var prop = 33;
this.mouseMoving = function() { alert(prop);}
//...
}
var mySomeObj = new someObj(); // Object instantiation
The variables declared with var, are accesible to the functions declared inside of the major constructor function, this feature is known as Closures.

Correct use of the this pointer in javascript for callbacks in knockout.js

I am a relatively experienced c# (and before that c++ Win32) developer, I am new to javascript and have a question regarding the this pointer.
I am using knockout.js, and one function called subscribe accepts a this variable, that will be set inside the callback function.
From my way of thinking from the Win32 days and C#, on any callback function i want a scope object which contains my state.
In this case I have use the this javascript thing to set my callback scope.
My questions are:
Now everything works (full fiddle here if you are
interested), but have I done something terrible?
Is there any reason this is used instead of passing in an explicit
scope variable as a parameter (that would make things easier to understand as
for me, this makes the workings kind of hidden).
What is the intended use for this?
From http://knockoutjs.com/documentation/observables.html it says:
The subscribe function accepts three parameters: callback is the function that is called whenever the notification happens, target (optional) defines the value of this in the callback function, and event (optional; default is "change") is the name of the event to receive notification for. Example below
myViewModel.personName.subscribe(function(oldValue) {
alert("The person's previous name is " + oldValue);
}, null, "beforeChange");
My code snippet below:
var computedOptions = createComputedDepdency(viewModel[option.requires.target],option.data);
viewModel[option.optionsName] = computedOptions;
console.log("making callback scope object for: " + option.optionsName );
var callbackScope = {
callbackName: option.optionsName,
options: computedOptions,
selectedValue: viewModel[option.selectedName]
};
// when the list of available options changes, set the selected property to the first option
computedOptions.subscribe(function () {
var scope = this;
console.log("my object: %o", scope);
scope.selectedValue(scope.options()[0].sku);
console.log("in subscribe function for..." + scope.callbackName);
},callbackScope);
First a semantic note:
The scope of a function is not related to this word. The context is related to this. The scope is related to the accessibility of variables and functions inside another function.
When you try to read a variable outside the function where it's declared, then you trying to access to a var outside its scope. So you cannot do it because the var is inside a scope not accessible from current position.
Now everything works (full fiddle here if you are interested), but have I done something terrible?
If it works, it's not so terrible :-)
Is there any reason this is used instead of passing in an explicit scope variable as a parameter (that would make things easier to understand as for me, this makes the workings kind of hidden).
a fast read: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
In javascript the value of this is determined by how a function is called.
In one way this approach could save annoying passage of context as argument: in a well documented library, the this use is very intituitive.
In other cases, I agree when you change continually context in your app without a rigorous logic, it could be confused.
What is the intended use for this?
We should always remember how and when the javascript is born. It was born for browser in order to interact with the DOM.
For this purpose, the context has sense that change based of which element call the function.
For example:
var divs = document.getElementsByTagName('DIV');
for(var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click',_clickHandler);
}
function _clickHandler() {
this.innerHTML = "clicked";
}
DEMO http://jsfiddle.net/AYBsL/1/
This is an example to how is useful the implicit change of context in javascript.
You could do this also for user-defined function: when you call a function you could change the context:
_clickHandler.call(divs[0]); // simulate click of first div
In javascript 'this' refers to the object that called your function. Only in a situation when you use 'new' keyword you can expect it to point to the current object (function).
var MyObject = function () {
this.hello = function () { console.log(this); }
}
var instance = new MyObject();
There is a way to make sure that this is always what you expect and that is creating a variable to store the correct reference for you and use that instead of this... in your example it would be similar to this...
computedOptions = function () {
var that = this;
}
computedOptions.subscribe(function () {
console.log("my object: %o", scope);
scope.selectedValue(that.options()[0].sku);
console.log("in subscribe function for..." + that.callbackName);
},callbackScope);
MDN JavaScript reference would inevitably explaing it more better then myself, have a look at it.
You shouldn't mix scope and this. this is supposed to mimic classical-oop languages like java or++, that is to keep the reference to an instance object. But it can be used just to execute arbitrary function on a given context using .apply() or .call.
What about scope, you don't have to do anything to pass the scope to a function, since the outer scope becomes automatically accessible inside function. You should read about closures - it's the best part of javascript.

var self = this?

Using instance methods as callbacks for event handlers changes the scope of this from "My instance" to "Whatever just called the callback". So my code looks like this
function MyObject() {
this.doSomething = function() {
...
}
var self = this
$('#foobar').bind('click', function(){
self.doSomethng()
// this.doSomething() would not work here
})
}
It works, but is that the best way to do it? It looks strange to me.
This question is not specific to jQuery, but specific to JavaScript in general. The core problem is how to "channel" a variable in embedded functions. This is the example:
var abc = 1; // we want to use this variable in embedded functions
function xyz(){
console.log(abc); // it is available here!
function qwe(){
console.log(abc); // it is available here too!
}
...
};
This technique relies on using a closure. But it doesn't work with this because this is a pseudo variable that may change from scope to scope dynamically:
// we want to use "this" variable in embedded functions
function xyz(){
// "this" is different here!
console.log(this); // not what we wanted!
function qwe(){
// "this" is different here too!
console.log(this); // not what we wanted!
}
...
};
What can we do? Assign it to some variable and use it through the alias:
var abc = this; // we want to use this variable in embedded functions
function xyz(){
// "this" is different here! --- but we don't care!
console.log(abc); // now it is the right object!
function qwe(){
// "this" is different here too! --- but we don't care!
console.log(abc); // it is the right object here too!
}
...
};
this is not unique in this respect: arguments is the other pseudo variable that should be treated the same way — by aliasing.
Yeah, this appears to be a common standard. Some coders use self, others use me. It's used as a reference back to the "real" object as opposed to the event.
It's something that took me a little while to really get, it does look odd at first.
I usually do this right at the top of my object (excuse my demo code - it's more conceptual than anything else and isn't a lesson on excellent coding technique):
function MyObject(){
var me = this;
//Events
Click = onClick; //Allows user to override onClick event with their own
//Event Handlers
onClick = function(args){
me.MyProperty = args; //Reference me, referencing this refers to onClick
...
//Do other stuff
}
}
If you are doing ES2015 or doing type script and ES5 then you can use arrow functions in your code and you don't face that error and this refers to your desired scope in your instance.
this.name = 'test'
myObject.doSomething(data => {
console.log(this.name) // this should print out 'test'
});
As an explanation: In ES2015 arrow functions capture this from their defining scope. Normal function definitions don't do that.
var functionX = function() {
var self = this;
var functionY = function(y) {
// If we call "this" in here, we get a reference to functionY,
// but if we call "self" (defined earlier), we get a reference to function X.
}
}
edit: in spite of, nested functions within an object takes on the global window object rather than the surrounding object.
One solution to this is to bind all your callback to your object with javascript's bind method.
You can do this with a named method,
function MyNamedMethod() {
// You can now call methods on "this" here
}
doCallBack(MyNamedMethod.bind(this));
Or with an anonymous callback
doCallBack(function () {
// You can now call methods on "this" here
}.bind(this));
Doing these instead of resorting to var self = this shows you understand how the binding of this behaves in javascript and doesn't rely on a closure reference.
Also, the fat arrow operator in ES6 basically is the same a calling .bind(this) on an anonymous function:
doCallback( () => {
// You can reference "this" here now
});
I haven't used jQuery, but in a library like Prototype you can bind functions to a specific scope. So with that in mind your code would look like this:
$('#foobar').ready('click', this.doSomething.bind(this));
The bind method returns a new function that calls the original method with the scope you have specified.
Just adding to this that in ES6 because of arrow functions you shouldn't need to do this because they capture the this value.
I think it actually depends on what are you going to do inside your doSomething function. If you are going to access MyObject properties using this keyword then you have to use that. But I think that the following code fragment will also work if you are not doing any special things using object(MyObject) properties.
function doSomething(){
.........
}
$("#foobar").ready('click', function(){
});

Categories