I am learning javascript and i came across a doubt. Why is the value of "this" undefined in the first example , but prints out correctly in the second.
example 1:
var myNamespace = {
myObject: {
sayHello: function() {
console.log( "name is " + this.myName );
},
myName: "john"
}
};
var hello = myNamespace.myObject.sayHello;
hello(); // "name is undefined"
example 2:
var myNamespace = {
myObject: {
sayHello: function() {
console.log( "Hi! My name is " + this.myName );
},
myName: "Rebecca"
}
};
var obj = myNamespace.myObject;
obj.sayHello();//"Hi! My name is Rebecca"
Why does the value of "this" changes within the function. What concept am i missing?
First case you are just getting the reference of the function to the vairable hello, and invoking it from global context (window in browsers, global in node), So this becomes what invoked the function except for (bound functions). You can always set the context explicitly using function.call or set the context explicitly to the function using Ecma5 function.bind
hello.call(myNamespace.myObject); //now you are setting the context explicitly during the function call.
or just bind it while getting the function reference.
var hello = myNamespace.myObject.sayHello.bind(myNamespace.myObject); //Now no matter where you call it from `this` will point to the context of myObject
Second case you are invoking it from the object itself so this points to the object.
In the first case, the implicit this object is the global scope. Because there is no myName in the global scope, you get undefined.
If you want a free function with the proper this, use bind:
var hello = myNamespace.myObject.sayHello.bind(myNamespace.myObject);
Related
My question sounds simple: does a function defined as an object member have closure over function's scope which contains the object?
For example:
function foo() {
/* some
* code*/
var obj = {
prop1: //something;
prop2: //something;
someCoolProp: function() {
//code
}
}
}
Does the someCoolProp function reference have closure over the scope of foo? Where is the anonymous function defined so if we gave it a name where would it be accessible?
Thanks.
My question sounds simple: does a function defined as an object member have closure over function's scope which contains the object?
Does the someCoolProp function reference have closure over the scope of foo?
Yes. It being defined within the object initializer doesn't have any effect at all on what it closes over. It still closes over the context of the call to foo that created it.
Where is the anonymous function defined so if we gave it a name where would it be accessible?
As of ES2015, that function does have a name: someCoolProp. (ES2015 added a lot of function name inference to the specification; a large number of "anonymous function expressions" no longer create anonymous functions, amusingly.) That name isn't added to any execution context's binding object (loosely, "scope"), though; the only reference to the function that exists is on the object's property of the same name.
But if you mean, if you used a named function expression:
var obj = {
prop1: //something;
prop2: //something;
someCoolProp: function someNameHere() {
// ^^^^^^^^^^^^---------------- added
//code
}
}
...the situation is the same: Because it's a function expression, the name isn't added to the context where it's defined. (Whereas with a function declaration, it is.)
My question sounds simple: does a function defined as an object member have closure over function's scope which contains the object?
Yes, it has.
function foo() {
var bar = 42,
obj = {
prop1: 'something',
prop2: 'something',
someCoolProp: function() {
console.log(bar);
}
};
return obj;
}
foo().someCoolProp();
When you declare a function a new scope is created, that's means all property inside it are private so none other scope can call these property. Let me explain with different examples because it's really important to understand this.
Here, you can't call x in the window scope, x is only inside the foo() scope
function foo() {
var x = 'Hey';
function transformX( val ){
// I can call x because transformX is inside Foo()
x = 'Ho';
}
return transformX(x);
}
console.log( foo() ); // 'Ho'
console.log( x ); // Reference Error can't read x
Here it's a ****** bad practice, I declare y without the var keyword, so at first window doesn't know y but during bar() execution y is declared & attached inside the window scope (default behavior) ! Always use a keyword declaration : var | let | 'const`
function bar() {
y = 'Hey';
function transformX( val ){
y = 'Ho';
}
return transformX(y);
}
console.log( y ); // 'Error y is not defined'
bar();
console.log( y ); // 'Ho'
This example is pretty hard than before, you can see a people variable inside the peopleObject and inside the window object. This practice is good to keep some variables like private.
var peopleObject = function(){
var people = {
name: 'Yann',
age: 25
}
function sayMyName(){
console.log('Hi', people.name);
}
function getName(){
return people.name;
}
return {
name : getName,
p: people
};
};
var people = peopleObject();
console.log( people.name() );
console.log( people.p );
console.log( people.sayMyName() ); // error sayMyName is not a function
Hi hope it's gonna help you :)
I previously posted a similar question in context to jquery but jquery's inner handling of this confused matters. So to keep it plain and simple consider:
function someCallbackFunction() {
this.name = "Tom";
}
anObject.method(someCallbackFunction);
what is the "this" of someCallbackFunction pointing to when invoked by "anObject"?
That is, when the function "some callback function" is being invoked by an object (within one of its function), what is "this" of (inner) "some callback function" pointing to then? [not the "this" of "outer" (AnObject.function - which is of course pointing to AnObject or another invoking function when called with call or apply)]
I think it should point to the global object (window object) since this inside a closure will point to the global DOM window object (in non-strict mode) or be undefined (in strict mode).
this depends on the way the function is called.
If you call it like mycallback(), this will refer to window object.
If you call it by mycallback.call(object) (or apply), this will refer to object.
http://jsfiddle.net/ydqZ8/1/
function callback()
{
alert(this.toto);
}
window.toto = 0;
var obj = {
toto : "TOTO"
};
callback(); // displays 0
callback.call(obj); // displays TOTO
Try this:
var self = this;
some callback function () {
self.name = "Tom";
}
Object.function (some callback function);
Generally 'this' is pointing to the object hosting the method called. (You may override this by function.call(thisObject, arg1, arg2) or function.apply(thisObject, [argList]).)
A simple example:
var myObject = {
value: 1,
report: function() {
return "value: " + this.value;
}
}
console.log( myObject.report() ); // "value: 1"
Should be quite clear.
Using a constructor and a prototype, it would be:
function Reporter(v) {
this.value = v;
}
Reporter.prototype = {
report: function() { return "value: " + this.value; }
};
var myObject = new Reporter(1);
console.log( myObject.report() ); // "value: 1"
Works just the same. 'this' is the object created by calling "new Reporter(1)" and the 'this' in the prototype is referring to the object which's method "report()" is called.
(The prototype comes only into play, if there's no method "report()" defined in the "myObject" as an own property.)
Now a bit more nested:
function ComplexReporter(v) {
this.value = v;
}
ComplexReporter.prototype = {
report: function() { return "value: " + this.value; },
utils: {
innerReport: function() { return "value: " + this.value; }
}
};
var myObject = new ComplexReporter(1);
console.log( myObject.report() ); // "value: 1"
console.log( myObject.utils.innerReport() ); // "value: undefined"
The first call is just as above and provides the expected result.
In the second call, 'this' is not as might be expected 'myObject', but 'myObject.prototype.utils', which has no property #value of any kind.
This is effectively
ComplexReporter.prototype.utils.innerReport.apply( myObject.prototype.utils, [] );
So as a rule of thumb, 'this' is the entity described by the path to the very last identifier before the last dot when invoking an object's method in dot-notation.
The last example without the prototype (to make it a bit simpler again):
var myComplexObject = {
value: 1,
report: function() {
return "value: " + this.value;
},
utils: {
innerReport: function() {
return "value: " + this.value;
}
}
}
console.log( myComplexObject.report() ); // "value: 1"
console.log( myComplexObject.utils.innerReport() ); // "value: undefined"
// same as myComplexObject.utils.innerReport.apply( myComplexObject.utils, [] );
console.log( myComplexObject.utils.innerReport.apply( myComplexObject, [] ) ); // "value: 1"
And: 'this' is always evaluated the very moment, the function is called (so you can't save the contextual meaning of 'this' when constructing a closure).
I hope, these examples helped a bit in understanding how 'this' works ...
P.S.: If the this-object provided with a call to function.call() or function.apply() is undefined or null, the global object ('self', in a browser identical to 'window') is used as 'this'.
I get confused on a JavaScript this reference situation.
I am working on a code that I declare function inside an object method. (The reason is to tidy up code inside an object method, while keeping the functions private to the method.)
The following is an experiment to re-produce my problem.
I found that the this inside greeting function refers to the window scope instead of person scope.
var person = {
nickname: "Makzan",
sayHi: function() {
console.log(this);
var greeting = function() {
console.log(this);
return "Aloha " + this.nickname;
}
console.log(greeting());
}
}
person.sayHi();
(same code in jsfiddle: http://jsfiddle.net/makzan/z5Zmm/)
And this is the log result in browser:
> Object
> Window
Aloha undefined
In JS, I know that this reference is tricky. And I can change the scope by using .call method to make this code works.
var greeting = (function() {
console.log(this);
return "Aloha " + this.nickname;
}).call(this);
However, I am curious to know why by default the this refer to window scope inside the greeting method?
Thanks in advance for all your help.
this has nothing to do with scope. It is determined by context.
greeting() calls the function with no context, so this is the default object (window in a browser).
The this, references is not related to scope, it depends on the calling context.
As per the MDN doc,
In general, the object bound to this in the current scope is
determined by how the current function was called
Try person.nickname, this refers to the var greeting in your case
If we modify your code a little, we can see that this works:
var person = {
nickname: "Makzan",
greeting: function () {return "Aloha " + this.nickname;},
sayHi: function () {return console.log(this.greeting());}
}
person.sayHi();
So we may conclude the reason that this doesn't:
var person = {
nickname: "Makzan",
sayHi: function () {var greeting = function () {return "Aloha " + this.nickname}; console.log(greeting()); }
};
person.sayHi();
is because for greeting() to have the this context of the person object, it must be explicitly declared as a direct property of the person object.
var name = 'The Window';
var object = {
name: 'My Object',
getNameFunc: function(){
return function() {
return this.name;
};
}
};
console.log( object.getNameFunc()() );
when i tested the code. the result is The Window. but i think this.name; should be My Object. what's wrong with my thinking.
when i add var before the name : "My Object", it show's an error.? why?
this inside a function is the "receiver" it was invoked upon.
That is,
for the construct x.f(), this inside the function (f) will evaluate to the value of x.
for all other cases, this will evaluate to window inside the invoked function. (The functions call, apply, and bind can also alter this... but that's another story.)
In the posted example the second function (the one with this.name) is not invoked using the x.f() form and so this is the window object.
The "simple fix" is to use a closure: (The first function is invoked in the x.f() form and thus this is the same as object, which is as expected. We capture the value of this in the current scope via a closure created with self and the returned function.)
getNameFunc : function () {
var self = this
return function () {
return self.name
}
}
However, I may consider another design, depending :)
Happy coding.
Additional clarification, for comment:
...that is because you are using circle.getArea() which is of the form x.f(). Thus this inside the getArea function evaluates to circle.
In the code posted you are invoking two different functions in a row. Imagine writing the code like this:
var nameFunc = object.getNameFunc()
nameFunc()
The first function call is in the form of x.f() and thus this inside getNameFunc is the evaluation of object. However, in the second line, the function (nameFunc) is not invoked in the form x.f(). Therefore, the this inside nameFunc (the function returned from getNameFunc) will evaluate to window, as discussed above.
var myObject = {
name:'My Object'
};
console.log(myObject.name);
console.log(myObject['name']);
There are various other ways to make objects in javascript.
this is a hidden argument that is automatically passed from the calling function to the callee. The traditional way is to do:
function MyObject() {
this.name = 'My Object';
}
myObject = new MyObject();
console.log(myObject.name);
Nowadays you might just use closures:
[**edit**: redacted because not a good method]
Nowadays you might just use closures, correctly:
function makeObject() {
var THIS = {};
THIS.name = 'My Object';
THIS.sayMyName = function () {
return THIS.name+" is my name";
}
return THIS;
}
There are many libraries that support "smarter" ways to make objects as well.
You need to use .bind() to set the right context for the method, so the this keyword will be what you want it to actually be.
The default is in such a scenario for the this keyword is to point to the window object, because...this is how the JS engine works.
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
}.bind(this); // <-- sets the context of "this" to "object"
}
};
console.log( object.getNameFunc()() );
As the others have written, you need to target this. I believe this piece of code will help you to understand how this in javascript works
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
that = this; // targeting this
return function() {
return that.name;
};
}
};
alert(object.getNameFunc()()); // it is My Object now
var object = {
name : "My Object",
getNameFunc : function(){
return (function(){
return this.name;
}).bind(this);
}
};
.bind, use the ES5-shim for browser support
The problem lies in the way you have declared your function.
The important point we need to remember while placing function inside a method is to use arrow function (if our function block is going to have a this keyword).
Instead of declaring a new variable and assigning this keyword to the variable, we can easily solve this problem using Arrow Functions.
Just convert the normal function into arrow function and boom it will work.
var name = 'The Window';
var object = {
name: 'My Object',
getNameFunc: function(){
return () => {
return this.name;
};
}
};
console.log( object.getNameFunc()() );
This works because arrow functions are always lexically binded and not dynamically binded like any other functions.
what is the this (inside inner functions) referring to in the following code context? Does it point to TimeSpan?
var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
var attrs = "days hours minutes seconds milliseconds".split(/\s+/);
var gFn = function (attr) {
return function () {
return this[attr];
};
};
var sFn = function (attr) {
return function (val) {
this[attr] = val;
return this;
};
};
}
Thanks
The this value is set implicitly depending on how the function is invoked, there are three cases where this happens:
When a reference with no base-object, or a non-reference is invoked:
myFn(); // the myFn reference has no base object
(function () {})(); // non-reference
The this value will point to the global object 1
When a reference contains a base object, for example:
myObj.method();
The this value inside method will point to myObj.
When the new operator is used:
var obj = new Foo();
The this value inside the Foo function, will point to a newly created object that inherits from Foo.prototype.
The this value can be set also explicitly, by using the call and apply methods, for example, with call:
function test(a) {
return alert(this + a);
}
test.call("hello", " world"); // alerts "hello world"
Or with apply if we need to "apply" a set of arguments from an array to a function:
function test(a, b) {
return alert(this + a + b);
}
var args = ["my ", "world "];
test.apply("hello ", args); // alerts "hello my world"
[1] This has changed on the new ECMAScript 5th Strict Mode, now when a function reference with no base object, or a non-reference is invoked (as the first case), the this value will contain undefined.
This was made because when working with constructor functions, people often forgot to use the new operator when calling the constructor.
When that happened, the this value pointed to the global object, and that ended up adding unwanted global properties.
Now on strict mode, this will contain undefined, and if property lookup is made on it (this.foo = 'foo') we will have a nice TypeError exception, instead of having a global foo property.
this refers to the current object, in this case the function you are inside of. Since everything in JavaScript is an object you can modify the attributes of a function object using the this keyword:
var f = function() {
this.key = "someValue";
}
console.log(f.key); // prints "someValue"
So in this case this should point to the function at the deepest scope level, and not TimeSpan.