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.
Related
In the console tab of chrome developer tools, I typed this, and it has shown Window object. How this becomes window object here?
console.log(this);
Consider below snippet
var firstname = "Javascript";
var lastname = "Lover - SKT";
function getName() {
this.firstname = "Sivakumar";
this.lastname = "Tadisetti";
}
console.log(firstname);
getName();
console.log(this.lastname); // How this.lastname is working here?
I've read the following StackOverflow answers
what does this mean
this in javascript
But didn't understand how the above snippet is working (The line I commented)
Update:
I have tried above code snippet in jsfiddle where it outputs this.firstname is undefined. So that's the reason I am asking this question. But in the stackoverflow code snippet it is working fine
In your function, this is the same as window (or whatever the global context is in your runtime). If it was a Class method, this would be the Class instance.
You can change this by using bind, or specifying it using apply and call.
Global Function Example
var that = {}
function getTest() {
console.log(this === window ? "this is window" : "this is not window")
}
getTest()
getTest.call(that)
getTest.apply(that)
getTest.bind(that)()
Lambda Example
If you use lambda syntax, this is bound to this at time of calling and cannot be changed.
let that = {}
let fn = () => {
console.log(this === window ? "this is window" : "this is not window")
}
// this is always window. You CANNOT this on a lambda.
fn()
fn.call(that)
fn.apply(that)
fn.bind(that)()
Class Example
class Foo {
fn() {
console.log(this === window ? "this is window" : "this is not window")
}
// Static methods do not have a `this`, but it can be defined by call and apply, but not bind.
static fnStatic() {
console.log(this === window ? "this is window" : "this is not window")
}
}
// this is Class instance, NOT window
new Foo().fn()
// Change this from class instance to window
new Foo().fn.call(window)
new Foo().fn.apply(window)
new Foo().fn.bind(window)()
// this is undefined in a static method, unless you apply or call. YOU CANNOT BIND a static method
Foo.fnStatic()
Foo.fnStatic.call(window)
Foo.fnStatic.apply(window)
// YOU CANNOT BIND
Foo.fnStatic.bind()(window)
In global scope, this is actually points to window object. By invoking getName you are doing the same as if:
window.firstname = "Sivakumar";
window.lastname = "Tadisetti";
In the global execution context (outside of any function), this refers to the global object whether in strict mode or not.
and console.log(this.lastname); is in global scope so here this refers to window object.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
According to MDN
In most cases, the value of this is determined by how a function is
called. It can't be set by assignment during execution, and it may be
different each time the function is called.
In your case, commented this is called by the JavaScript's execution context, the context that called your program to be executed. Inside that context variable lastname lives and this means that it is a part of this object. You are calling it after your getTest function that changed the value of lastname variable and that is why you see in in console.log() with it's changed value.
If you're in a global context then this refers to the window object.
console.log(this);
this can refer to the window object in a function if the context stays the same
const funcArrow = () => {console.log(this)}
const func = function(){console.log(this)};
//this has no difference
const func2 = function(){console.log(this)}.bind(this);
funcArrow(); func();
The context changes if you create an instance.
var Car = function(){
this.name = "bmw";
console.log(this);
};
class Person {
constructor(){
this.name = "john";
console.log(this);
}
}
new Car(); new Person();
To keep the window context in an instance bind it.
class Person {
constructor(){
this.name = "john";
}
logWindow(){
const someFunc = function(){console.log(this)}.bind(window);
someFunc();
};
}
(new Person()).logWindow();
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);
I'm learning about angularjs and I keep noticing when a function is declared, most people usually make "this" into a var before modifying it. Why is that?
Code snippet below:
function NameService() {
var self = this; **THIS BLOCK. WHY??**
//getName returns a promise which when
//fulfilled returns the name.
self.getName = function() {
return $http.get('/api/my/name');
};
}
And at the bottom, the example uses self.getName. Why not just directly call this.getName?
Thanks
This is just a pattern that you can use. Generally it helps avoiding collisions of the 'this' keyword which is very common in the javascript 'world'.
Also helps with readability, so you can easier read your code.
Check out this example, where you can easily distinguish the public functions of the service and the local/private ones:
function NameService() {
var self = this; **THIS BLOCK. WHY??**
self.getName = getName;
self.setName = setName;
//getName returns a promise which when
//fulfilled returns the name.
function getName() {
return $http.get('/api/my/name');
};
function setName(){
//blablabla
}
function justAHelperFunction(){
//helper function, kind of inner function, a private function
}
}
In javascript this refers to the current object and the value of this in say a method depends how the function is invoked. When you pass a callback to a function call the context of this gets changed and inside the callback definition this doesn't refer to the object that has the method which further called the function with callback.
var person = {
firstName: 'John',
lastName: 'Doe',
printFullName: function () {
setTimeout(function () {
// here this doesn't point to the person object anymore
// as the callback passed to setTimeout was invoked by global window object
// so this points to window
console.log(this.firstName + ' ' + this.lastName);
}, 100)
}
}
To fix the above scenario where you expect this to be person you make an alias of the context capturing the reference in another variable. Here's the correct version of above method.
printFullName: function () {
var self = this;
// till now self == this
setTimeout(function () {
// here self still points to person whereas this is now pointing to window
console.log(self.firstName + ' ' + self.lastName);
}, 100)
}
(Sorry, another this question in javascript.)
I have the code below, and I'm wondering what 'this' represents in the call at the end-- the Window or the Bird?
var Bird = (function () {
Bird.name = 'Bird';
function Bird(name) {
this.name = name;
}
Bird.prototype.move = function (feet) {
return alert(this.name + (" flew" + feet + "ft."));
};
return Bird;
}).call(this);
Well, assuming there is no parent scope, it is window
EDIT: See example: http://jsfiddle.net/Umseu/1
Probably window, because it's not in any particular context that would give this any special meaning.
The window. .call(this) is not written inside the bird. It simply calls an anonymous function that happen to return "Bird" "constructor".
Call console.log(this) at first line in the anonymous function. That return the scope, window.
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.