I have been doing some JavaScript development and I encountered this problem. Consider the following code
var obj = {};
obj.bind = function () {
console.info(this);
};
obj.bind();
I'm running the code on the FireBug JavaScript console. The expected result is that this displays a reference to the object in the console.
It actually displays undefined.
But, when I make this change to my code
var obj = {};
obj.bind = function () {
this.x = 'x';
console.info(this);
};
obj.bind();
Now the console displays the expected value of this, which is a reference to the obj object.
Why does this happen?
undefined is the return value of the function, which you'll get because you're not returning a value explicitly.
In both Chrome and Firebug, it correctly displays the Object in the console before the return value undefined.
So if you do:
var obj = {};
obj.bind = function () {
console.info(this);
return "foo";
};
obj.bind();
...you should see something like:
Object { }
"foo"
If Firebug is not displaying the Object when it is empty, you may need to check to make sure you're using the most current version.
In your example, "this" should be obj, just as some commenters pointed out. Here are the details that explain why --
In Javascript, the value of "this" changes depending on how you call the function:
When a function is stored as a property on an object, and you invoke that function by calling obj.foo(), "this" will be obj.
EX:
var obj = {
x: 1,
increment: function() {
this.x = this.x + 1;
};
obj.increment(); // Makes "this" be obj
When you invoke a function using syntax that does not refer to any owning object, "this" will be the global environment.
EX:
function someFunc(a, b) {
return a + b; // If you were to refer to "this" here, it would be the global env.
}
someFunc(5, 6);
When you invoke a function as if it were a constructor by using the new operator, a new object will be instantiated for you, and "this" will point to that new object.
EX:
function SomeConstructor() {
this.x = 42; // under the hood, a new object was instantiated for you, and "this" was set to it.
}
var result = new SomeConstructor(); // note the "new" keyword
// result will be { x:42 }
When you use call() or apply(), you can control what "this" is.
(No example here since it's fairly far from your question. Look up docs for apply() or call() for an example.)
Related
I'm trying to figure out the behaviour of "this" keyword in JavaScript. In general I understand how it behaves in different contexts of function calling, but I'm having some trouble when it's part of an arrow function.
I'm using MDN as a source of information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#Arrow_functions.
I have grasped the general concept that in the case of arrow functions "this" retains the value corresponding to the context of the function definition, but I started having trouble when playing with the last example in that section.
The example goes like this:
var obj = {
bar: function() {
var x = (() => this);
return x;
}
};
var fn = obj.bar();
console.log(fn() === obj); //true
As expected, the console returns true. However, and this is my first doubt, i don't understand why it returns false when I compare obj directly with obj.bar(), since I asume that obj.bar() and fn() invoke the same function:
var obj = {
bar: function() {
var x = (() => this);
return x;
}
};
console.log(obj.bar() === obj); //false
I started playing with the code trying to find further unexpected behaviours, and there are some more doubts. The second one: when I change the type of definition of bar, "this" in the function apparently starts referring to the global object, although I thought the function was being called as a method of obj. ¿Shouldn't the result be the opposite? ¿Is it because now "this" refers to the context of fn?
var obj = {
bar: function() {
var x = function() {
return this;
};
return x;
}
};
var fn = obj.bar();
console.log(fn() === obj); //false
console.log(fn() === this); //true
Third doubt: if I omit fn again and use directly obj.bar() in the comparison, again I find unexpected results. In this case "this" in the function refers neither to the global object nor to obj (I expected the second, since bar() is called as a method of obj).
var obj = {
bar: function() {
var x = function() {
return this;
};
return x;
}
};
console.log(obj.bar() === obj); //false
console.log(obj.bar() === this); //false
When I try to see directly the value returned by obj.bar() I can't get much help from the console:
console.log(obj.bar());
//With arrow definition: () => { length:0
// name:x }
//With the second definition: f() => { length:0
// name:"bar"
// prototype: bar}
I hope someone here can help me understand what's going on, or at least recommend me a more complete resource. Thank you in advance!
I asume that obj.bar() and fn() invoke the same function
No, obj.bar() returns the function x. It's creating a closure.
"this" in the function apparently starts referring to the global object, although I thought the function was being called as a method of obj
No, fn was not called as a method on obj, only bar was. fn() is called as a plain function.
if I omit fn again and use directly obj.bar() in the comparison, "this" in the function refers neither to the global object nor to obj
No. The this in the function is never even evaluated, the function is never called. You only called bar, and then compared the returned function against obj.
When I try to see directly the value returned by obj.bar()
…then the console shows you a function object!
What you are looking at is obj.bar() reutrns a function that is assigned to a variable fn and then fn is invoked fn()
so
var obj = {
bar: function() {
var x = (() => this);
return x;
}
};
console.log(obj.bar()() === obj); //should give you true
I am trying to grasp the concepts of Javascript through online video courses, where I came upon this example below.
https://www.youtube.com/watch?v=9oi0NY8Pen8
The instructor used this example first
var carlike = function(obj, loc) {
obj.loc = loc;
obj.move = function() {
this.loc++;
};
return obj;
};
var amy = carlike({}, 1);
amy.move();
and then changed the carlike function to
var carlike = function(obj, loc) {
obj.loc = loc;
obj.move = function() {
obj.loc++;
};
return obj;
};
Saying the Instead of referring to the parameter this which gets bound to a new value each time move is invoked we can use obj
How is this getting bound to new value. How can using obj prevent this.
When you call amy.move(), within move the "variable" this gets the value of amy, which is an object. If move contains the code this.loc++, then the value of the property amy.loc will be incremented.
You can, however, invoke that function in other ways. For example:
var func = amy.move; // copies reference to function into variable func
func(); // "this" is unspecified
In the above case, because this is unspecified, it defaults to window (in non-strict mode) or undefined (in strict mode).
Or:
var bill = { loc: 4 };
amy.move.call(bill); // "this" is bill, not amy
On the other hand, if the move function contains the code obj.loc++, then it will always increment the loc of same object: namely, the one that was passed to carlike when this instance of move was created:
var amy = carlike({}, 1);
var bill = { loc: 4 };
amy.move.call(bill); // "this" is bill, not amy
console.log(amy.loc); // prints 2
console.log(bill.loc); // prints 4
The move function, when created, becomes a closure on the local variable obj within carlike.
In this small example, there is no particular benefit to doing this, but closures are a powerful technique in general.
When you call the move function as:
amy.move();
then you are setting the value of this within move to amy. If you do:
var b = amy.move;
b();
you are now calling the function without setting this, so it defaults to the global/window object in non–strict mode, and is undefined in strict mode. By using:
obj.loc = loc;
obj.move = function() {
obj.loc++;
};
then the function keeps a reference to obj via a closure, so no matter how the function is called, obj always references the object originally passed to carlike.
Since this in javascript is decided at function invocation. Using it inside methods causes unwanted bugs. You may not realize this if you call the function yourself using amy.move().
Ex:
var carlike = function(obj, loc) {
obj.loc = loc;
obj.move = function() {
console.log(this);
this.loc++;
};
return obj;
};
var amy = carlike({}, 1);
amy.move(); => this will corresponds to object which are returned from constructor.
setTimeout(amy.move, 1000) => this will corresponds to window
Since the constructor is returning the object, its safe to use obj inside the function amy.
Ref: this in javascript
Is there a way to get the Function object, while the function is executing?
I am assigning properties to my function, and want to access them. "this" doesn't help. Something like:
a.b=function(){...code...};
a.b.c=100;
I want to access a.b.c from the code in the function, without knowing its own name. "this" refers to a. How can get b?
I tried binding the function to his own object, but I couldn't.
Thank you.
I'm adding this example, I have to repeat after several different "theString" and "someSpecificValues":
Object.defineProperty(theObject, theString, {get: function(...){...}.bind(theObject, someSpecificValues), configurable: true});
You can use a named function expression for this:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.b();
It allows code inside the function to access the function itself, but does not add the identifier to the enclosing scope.
Edit: Here is a more elaborate example of how the name myFunc only exists within the function:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.d = function myFunc() {
console.log(myFunc.c);
};
a.d.c = 300;
a.b(); // logs 100
a.d(); // logs 300
console.log(typeof myFunc); // logs "undefined"
// create a myFunc variable
var myFunc = function() {
console.log("nooooooo!!!!");
};
a.b(); // STILL logs 100. the myFunc variable in this scope
// has no effect on the myFunc name that a.b uses
function callFunc(theFunc) {
theFunc();
}
callFunc(a.d); // STILL logs 300
// ===========================
function returnNamedFunction () {
return function myFunc() {
console.log(myFunc.c);
};
}
var iGotAFunction = returnNamedFunction();
iGotAFunction.c = 700;
iGotAFunction(); // logs 700
In the case when you cannot use a named function expression, e.g. when you are using .bind() on it, then an IIFE will suffice most of the time:
var myObj = {};
myObj.theFunc = (function () {
var f = function (arg1, arg2) {
console.log(this.theProp);
console.log(arg1);
console.log(arg2);
console.log(f.lista);
}.bind(myObj, "A!");
return f;
})();
myObj.theProp = "B!";
myObj.theFunc.lista = [1, 2, 3];
myObj.theFunc("C!");
There are two ways to get current function.
One is "almost deprecated" usage of arguments.callee. In function body it always refers to this function.
var a = {};
a.b = function () {
console.log(arguments.callee.c);
};
a.b.c = 100;
a.b();
arguments.callee is forbidden in strict mode. Reference.
The second one is using named function expression as JLRishe pointed.
arguments.callee pros and cons
Advantages:
it can be safely used with bound functions (arguments.callee refers to bound function)
it can be used with functions created using new Function
Disadvantages:
it can slow your program due to disabling certain optimisations
it's considered as almost deprecated
it can't be used in strict mode
Named function expression pros and cons
Advantages:
it's faster than arguments.callee
it's easier to understand how it works
Disadvantages:
it won't work as expected with bound functions (functionName will refer to original function, not bound one)
it can't be used in functions created with new Function
I am calling the following 3rd party JavaScript function:
var Socket = function(url) {
sockets.push(this);
var me = this;
me.readyState = 0;
window.setTimeout(function() {
me.readyState = 1;
me.onopen();
}, 500);
};
via this:
connection = new Socket(socketURL);
Now I want to try and understand once and for all what it means to reference this inside a function. Is it the same as in Java. e.g. I am referring to myself or in the case of JavaScript I am referring to the namespace that the function resides in?
The referece of this depends on how you are calling the function.
For example:
function globalFn() { return this.val; }
var objectA = { val: 1, localFn: globalFn };
var objectB = { val: 2, localFn: globalFn };
objectA.localFn(); // `this` will be `objectA`, so it returns `1`.
objectB.localFn(); // `this` will be `objectB`, so it returns `2`.
So far, so good. It looks like the same as in Java or other object oriented languages. But, this may seem tricky:
var myFn = objectA.localFn;
myFn(); // `this` will be `undefined` in strict mode, causing an error
This shows that this reference is not bound to the function itself, but to the way the function is called. You can "cheat" it by using call method of a function object:
myFn.call(objectA); // `this` will be `objectA`, returns `1`.
globalFn.call(objectB); // `this` will be `objectB`, returns `2`.
objectA.localFn.call(objectB); // `this` will be `objectB`, returns `2`.
You can even do this for objects that does not have the function defined as a property:
var objectC = {val: 3};
myFn.call(objectC); // `this` will be `objectC` and will return `3`.
It's quite hard to understand it at first, there's a great video that illustrates how it works at YouTube: The Definitive Guide to Object-Oriented JavaScript by James Shore.
Edited. Previous answer was not correct. Here's a good explanation:
code.tutsplus.com/tutorials/fully-understanding-the-codethiscode-keyword--net-21117
I was going through this article http://dev.opera.com/articles/view/objects-in-javascript/
where I read "'this' keyword doesn’t always refer to the object on which a method is defined, but instead can change based on specific contexts."
I couldn't find any example in which 'this' does not refer to the object on a method is defined....please gimme an example if possible
One example that you could realistically run into and not expect this result:
var obj = {
testFunc : function(){
alert("testFunc: " + this);
}
}
obj.testFunc(); // this is the object
setTimeout(obj.testFunc, 1000); // this is window
http://jsfiddle.net/t7ycd/
There are many way to change context. jsfiddle
using bind: (not supported by older IE browsers (IE < 9))
var obj = {};
function fun1(){};
obj2 = {};
obj2.fun1 = fun1.bind(obj);
obj2.fun1(); // context inside fun1 would be obj.
Using apply or call.
var obj = {};
function fun1(){};
obj2 = {};
obj2.fun1 = function(){
fun1.apply(obj, arguments);
//or fun1.call(obj, ar1, arg2,...);
};
obj2.fun1(); // context inside fun1 would be obj.
Here is one way
var a = {};
a.foo = function(){ console.log(this); }
a.foo(); // object a
a.foo.call(window); // window object
If you call a method in class B from class A, the 'this' will refer to the class that is calling the method - A, not the class that it is in.
Here is an example taken directly from the Mozilla documentation
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this
var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // logs 37
So the function independent is defined in the global context, but is then attached to an object. When it is invoked on that object the context becomes the object on which the function is invoked rather than the object on which the function is defined.
You can achieve similar results using the javascript call and bind methods, and using anonymous functions.
like this
var MyObject = function()
{
this.initialize();
}
MyObject.prototype.SomeMethod = function()
{
//common fix is to use
//var self = this;
(function(){
//this has lost scope
//self will retain the this scope that was desired
})();
}