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();
Related
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);
var name = "Window Object";
var a = {
name: 'manish',
getName: function() {
return this.name;
}
}
b = (a.getName = a.getName)();
console.log(b, window);
Above is the code that I had written on JSFiddle.
Here is the link: https://jsfiddle.net/shettyrahul8june/o49jn5fm/
Variable b returns result instead of Window Object. I saw that in the Window object there is a property called name which has result stored as string. But I am not sure why my global variable a didn't override that variable. Thanks in anticipation.
Edit: Guys I think I wasn't clear with my question. I know it's referencing the window object's name from JSFiddle. But I have also written var name = "Window Object".
Why my variable name didn't over ride Window objects name because I think even var name that I have declared should have got attached to window object. Is it because, the fiddle has a wrapper object where name gets assigned like
JSFiddleWrapper = {
name: "Window Object"
}
and hence it's referencing window.name?
There is something interesting whe you are doing a.getName = a.getName. The a.getName function is reassigned to the same . The parenthesis just returns that function with the Window as its context. So when inside the function you do this, it refers to the Window object.
var name = "Window Object";
var a = {
name: 'manish',
getName: function() {
return this.name;
}
}
b = (a.getName = a.getName)();
console.log(b);
You can use bind to change the context. Check the following snippet:
var name = "Window Object";
var a = {
name: 'manish',
getName: function() {
return this.name;
}
}
b = (a.getName = a.getName).bind(a)();
console.log(b);
In JavaScript, this behaves very different from most other languages. Its precise behavior depends entirely on how the function is called, notice:
console.log(a.getName(), window); // manish Window
This correctly gets name from a, because this is inferred to refer to the object on the left of the period. But here:
f = a.getName;
console.log(f(), window); // result Window
The function, f, is in a sense 'unbound' from the object at the time it's called, and so this is inferred to refer to the Window itself (in JSFiddle the name of the window in the result panel is 'result').
One fairly easy way to solve this is to use the bind method:
b = (a.getName = a.getName.bind(a))();
console.log(b, window); // manish Window
I have tried to organize my code in an object oriented way (as explained in MDN). In my case however, this refers to the window object. Because of that I get the error
Uncaught TypeError: Cannot read property 'render' of undefined
in
this.renderer.render(this.stage);
Why does this refer to the window object when it doesn't on MDN?
var GAME = GAME || {};
GAME.Application = function() {
this.renderer = PIXI.autoDetectRenderer(800, 600,{backgroundColor : 0x1099bb});
document.getElementById("game").appendChild(this.renderer.view);
this.stage = new PIXI.Container();
requestAnimationFrame(this.render);
}
GAME.Application.prototype.render = function() {
this.renderer.render(this.stage);
}
var app = new GAME.Application();
You need to bind your render function. This is probably the most straight forward solution.
requestAnimationFrame(this.render.bind(this));
Or instead, you could do
var context = this;
requestAnimationFrame(function() {
context.render();
});
Or you could avoid creating the free variable and use an IIFE
requestAnimationFrame((function(context) {
context.render();
})(this)));
Or, if you're using ES6, you can use an arrow function
requestAnimationFrame(() => this.render());
Another easy improvement you could make is passing the render element into your Application constructor
function Application(elem) {
this.renderer = ...
elem.appendChild(this.renderer.view);
}
new Application(document.getElementById("game"));
Lets talk about this, context, and functions
A good way to think about it, is that this refers to the object on the left of the . of the method that calls it.
var someObj = {
name:'someObj',
sayName: function(){
console.log(this.name);
}
};
someObj.sayName(); // prints someObj
Functions that are not methods of an object are bound to the window object.
window.name = 'window';
function sayName(){
console.log(this.name);
}
sayName(); //prints window
The above is equivalent to
window.sayName(); // window is on the left of the dot, so it is `this`
When you pass a method of an object as a parameter, or assign it to a variable, it loses its original context. Below, the sayName method of someObj loses someObj as the context and gains someOtherObj.
var someOtherObj = {
name:'someOtherObj'
};
someOtherObj.sayName = someObj.sayName;
someOtherObj.sayName(); // prints someOtherObj
To get around it, You can bind a context to a function
var yetAnotherObj = {
name: 'yetAnotherObj'
};
var sayYetAnotherObj = sayName.bind(yetAnotherObj);
sayYetAnotherObj(); // prints yetAnotherObj
Or pass an anonymous function that calls the the method on the object itself
var OneLastObj = function(){
var self = this;
this.someValue = aFunctionTakingAcallback(function(){
return self.doSomeStuff();
});
}
Something to remember when passing functions around as a parameters is that you are passing a reference to the function. The function itself is not bound to the object that it may be a method of.
I tried to create this syntax for JavaScript:
var user = new Class({
name: 'No name',
sayHello: function () {
console.log(self.name);
}
});
user.sayHello(); // will print "undefined" because "self" isn't visible
And I created this implementation of Class:
function Class (_properties) {
var self = this;
// copy all properties and methods to this class
for (var _property_name in _properties) {
self[_property_name] = _properties[_property_name];
}
}
But the problem is in self that I wish to use in each class. The self.name will be undefined because self is a [Window object].
Question: how to modify my code to use self inside all functions in class instances? The self is needed to not drop context if the function will be called from external context.
Expected result (I mean that code above should be executed as code below):
function Class (_properties) {
var self = this;
// properties
self.name = 'No name';
// methods
self.sayHello = function sayHello () {
console.log(self.name);
};
}
var user = new Class();
user.sayHello();
The goal of my experiment is to use self that always is reference to current object. Because sometimes when we use calls like this $.get('...', function () { console.log(this); }) - this is set to function local scope. But I wish to use self (magic property) that always be a reference to object of current class (scope of current class).
So I finally figured out that you are talking about the self variable in the sayHello method that is giving you problems.
You need to google JavaScript scope this tutorial - it's not the most intuitive concept, but once you get it, everything will make sense.
In the mean time, it's worth pointing out that self is not a reserved word in JavaScript and doesn't do anything special, but this is.
So what you want, is something like this:
function Class (_properties) {
// copy all properties and methods to this class
for (var _property_name in _properties) {
this[_property_name] = _properties[_property_name];
}
}
var User = new Class({
name: 'No name',
sayHello: function () {
console.log(this.name);
}
});
var user1 = new User();
var user2 = new User();
The keyword new in front of the Class() function causes it to be executed as a constructor function meaning that, inside of the constructor function this will reference it's own scope.
Also, because the property sayHello is a function to be executed inside the scope that you created, you can use this.name - as this will refer to the scope that you created when you instantiated a new Class.
And just because this scope thing is no doubt confusing (don't worry, it probably will be for a while) - if you haven't created a scope (by using a constructor or object literal) you're working inside of the global scope which, in the case of the browser, is the Window object.
That's because you never created an object:
var options = {
name: 'No name',
sayHello: function () {
console.log(self.name);
}
}
var user1 = new Class(options);
var user2 = new Class(options);
"this" refers to the object owner of the current function. In this case would be windows object. At least you construct an object from the function Class.
If you want to avoid someone overwrite a property of Class.prototype is necessary to use hasOwnProperty in your for in
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.