Cant understand what this refers to - javascript

Can anybody elaborate below in innerF, what does this refer to? User or innerF?
function User(){
this.id = 1;
};
User.prototype.sayHi = function(){
var innerF = function(){
this.id = 2; // "this" refers to User or innerF ?
};
return innerF;
};
Also does the new keyword or anonymous function has to do with changing reference of this keyword?
What if I call it all like this:
var u = User;
var f = u.sayHi();
f();
Or
var u = new User;
var f = u.sayHi();
f();
Thanks

What the this local refers to inside of innerF will depend on how the function is eventually invoked. It can be invoked in a variety of ways that will change the meaning of this. For example
var u = new User();
var innerF = u.sayHi();
innerF(); // 'this' is window
innerF.call(u); // 'this' is 'u'
innerF.call("hello"); // 'this' is "hello"
Based on your code though it appears that you want this to refer to the instance of User on which sayHi was invoked. If so then you need to store this in a local and refer to that local within innerF.
User.prototype.sayHi = function(){
var self = this;
var innerF = function(){
self.id = 2;
};
return innerF;
};
Note though that this inside sayHi isn't guaranteed to point to User instance either. In general it will the same tricks can be done to sayHi that were done to innerF. For example
var sayHi = u.sayHi;
sayHi(); // 'this' is window

You're not calling the function in that code, so it doesn't refer to anything yet.
The value of this is determined when you call the function, not define it (unless you use something like bind).

var u = User;
var f = u.sayHi();
f();
The code above will throw error. User is a function, not a User object, so it doesn't have the method sayHi, so you will get error of below.
Uncaught TypeError: Object function User(){
this.id = 1;
} has no method 'sayHi'
var u = new User;
var f = u.sayHi();
f();
The code above will not throw error, and u is an object of User, (how new worksfrom mdn), and it's method sayHi return a function, and you execute the function by f();, so the this inside of the function is refer the current context when the function be called. So if your code is in global scope, the this is referring the window object.
And you could set the context by f.call(u);, then the this is referring the object u, and you changed the User object u's id to 2.

Related

issue when access outer function scope in JS

Why the following happens?
function f1() {
this.myRefVar = 30;
this.myRefVar2 = 30;
var parent = this;
return function() {
this.myRefVar = 20;
console.log('parent contains ' + Object.keys(parent).filter(function(k) {
return k.indexOf('myRefVar') > -1;
}));
console.log('parent value of myRefVar: ' + parent.myRefVar);
console.log('this value of myRefVar: ' + this.myRefVar);
};
}
f1()();
Output:
parent contains myRefVar,myRefVar2
parent value of myRefVar: 20
this value of myRefVar: 20
Because there is actually no scoping here. All of this accesses refer to the window object. Hence, when you are editing this.myRefVar at the inner scope, you are actually editting the value at the window.
var theName = "SO";
var myObject = function(){
this.theName = "SO2";
this.foo = function() {
this.theName = "SO3";
}
}
Here, I defined some variables, and functions. The variable theName, first declared at root(window) scope, then inside myObject scope (There is no scope like this, just for the explanation, and then inside foo scope.)
console.log(theName); // SO
console.log(this.theName); // SO
console.log(window.theName); // SO
console.log(myObject.theName); // undefined
console.log(myObject.foo); // undefined
console.log(this.foo); // undefined
console.log(window.foo); // undefined
And here, I am trying to access theName variable via different ways. If there is actually scopping here 4th one should work after function call. The others just representing same idea, but different way.
myObject();
console.log(theName); // SO2
console.log(this.theName); // SO2
console.log(window.theName); // SO2
console.log(myObject.theName); // undefined
console.log(myObject.foo); // undefined
console.log(this.foo); // function myObject/this.foo()
console.log(window.foo); // function myObject/this.foo()
After function call, I still can't access myObject.theName as I hoped. That's because, calling it this way myObject.theName does not actually accessing myObject scope, rather than I am trying to access theName property of myObject function. And, without actually defining/instantiating/creating this function as an object, I cannot access the properties.
myObject.theName;// undefined. Accessing myObject as a function
new myObject().theName // SO2. Accessing an object derived from myObject.
What's going on in your code is actually not scopping but closure. For better understanding:
Scopping
Closures
Similar SO question
In JavaScript function have global scope
For example
function parent() {
var self_parent = this;
function firstChild() {
var self_first_child = this;
function childOfChild() {
var self_child_of_child = this;
}
}
}
in the above code following will be true
self_parent === self_first_child === self_child_of_child
for more Info see JavaScript-Garden-About-this

Why is the value of this variable undefined

I am currently learning javascript and came across this example
var t = function()
{
this.name = "Jam";
no = "123";
}
console.log(t.no); //Undefined
var m = new t();
console.log(m.name);
Why is the first statement undefined ?
t is a function object. As any other object, the function may have properties assigned. So in order your code to work you shall assign "123" to no property of your function (line A):
var t = function()
{
this.name = "Jam";
}
t.no = "123"; // line A
console.log(t.no); // "123"
var m = new t();
console.log(m.name);
Why is the first statement undefined ?
Because t doesn't have a property no.
First of all, the code inside the function, namely
this.name = "Jam";
no = "123";
is only executed when the function is called. You are doing this with var m = new t();, which comes after console.log(t.no);.
Secondly, no = "123"; does not create a property on the function object. It will attempt to set the value of variable no. Since the variable doesn't exist in your example, that line will either create a global variable no, or throw in error if your code is in strict mode.
Consider the following example:
var no = 21;
function foo() {
no = 42;
}
console.log(no); // 21
foo();
console.log(no); // 42
Because t is a function, that would be executed by t();. no on the other hand is a global scooed variable that is reached without prefix from everywhere.
t is a function expression. You you can access a returned object of a function like t().no or you can create a new object by using the function as a constructor like this
myT = new t()
console.log(t.no);
But your no variable is just a global variable inside the function and it is not a part of what it returns nor it is not attached to the returning object of the constructor function.
Here is a very good tutorial which covers all these topics at depths.

JavaScript scope issue (this)

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.

javascript private members not working

I am trying to get private properties to work in javascript.
var obj = function() {
var a = 0;
this.run = function() {
var q = a;
a += 1;
return q;
};
};
alert(obj.run());
alert(obj.run());
I have a private variable a and a public function run, however when I call it, it throws an error saying obj.run is not a function. Does anyone know what's wrong?
Thanks
You should create instance of your obj
var o = new obj();
console.log(o.run());
console.log(o.run());
Example,
or you can use module pattern, like so
var obj = (function() {
var a = 0;
return {
run: function () {
var q = a;
a += 1;
return q;
}
};
})();
console.log(obj.run());
console.log(obj.run());
Example
the value of this is determined by how a function is called. (Context)
your obj is a function type. It has not been called, not been invoked, or no instance of it has been created yet. Thats y 'this' here refers to window object, not function obj type. Context is 'window' here
this.run = function () {
//code
}
// here the context is window, hence attaches run property to window
// object making run method accessible in global scope.
When you do
obj.run()
// remember 'this' to be window , this statement will not work,
// because obj doesn't have run property.
When you create instance of obj like
var o = new obj(); // context of 'this' is set to function now
so, if you call o.run() // it will work.
this in javascript

Declaring variables with this or var?

What is the difference between declaring a variable with this or var ?
var foo = 'bar'
or
this.foo = 'bar'
When do you use this and when var?
edit: is there a simple question i can ask my self when deciding if i want to use var or this
If it is global code (the code is not part of any function), then you are creating a property on the global object with the two snippets, since this in global code points to the global object.
The difference in this case is that when the var statement is used, that property cannot be deleted, for example:
var foo = 'bar';
delete foo; // false
typeof foo; // "string"
this.bar = 'baz';
delete bar; // true
typeof bar; "undefined"
(Note: The above snippet will behave differently in the Firebug console, since it runs code with eval, and the code executed in the Eval Code execution context permits the deletion of identifiers created with var, try it here)
If the code is part of a function you should know that the this keyword has nothing to do with the function scope, is a reserved word that is set implicitly, depending how a function is called, for example:
1 - When a function is called as a method (the function is invoked as member of an object):
obj.method(); // 'this' inside method will refer to obj
2 - A normal function call:
myFunction(); // 'this' inside the function will refer to the Global object
// or
(function () {})();
3 - When the new operator is used:
var obj = new Constructor(); // 'this' will refer to a newly created object.
And you can even set the this value explicitly, using the call and apply methods, for example:
function test () {
alert(this);
}
test.call("hello!"); //alerts hello!
You should know also that JavaScript has function scope only, and variables declared with the var statement will be reachable only within the same function or any inner functions defined below.
Edit: Looking the code you posted to the #David's answer, let me comment:
var test1 = 'test'; // two globals, with the difference I talk
this.test2 = 'test'; // about in the beginning of this answer
//...
function test4(){
var test5 = 'test in function with var'; // <-- test5 is locally scoped!!!
this.test6 = 'test in function with this'; // global property, see below
}
test4(); // <--- test4 will be called with `this` pointing to the global object
// see #2 above, a call to an identifier that is not an property of an
// object causes it
alert(typeof test5); // "undefined" since it's a local variable of `test4`
alert(test6); // "test in function with this"
You can't access the test5 variable outside the function because is locally scoped, and it exists only withing the scope of that function.
Edit: In response to your comment
For declaring variables I encourage you to always use var, it's what is made for.
The concept of the this value, will get useful when you start working with constructor functions, objects and methods.
If you use var, the variable is scoped to the current function.
If you use this, then you are assigning a value to a property on whatever this is (which is either the object the method is being called on or (if the new keyword has been used) the object being created.
You use var when you want to define a simple local variable as you would in a typical function:-
function doAdd(a, b)
{
var c = a + b;
return c;
}
var result = doAdd(a, b);
alert(result);
However this has special meaning when call is used on a function.
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
doAdd.call(o, a, b);
alert(o.c);
You note the first parameter when using call on doAdd is the object created before. Inside that execution of doAdd this will refer to that object. Hence it creates a c property on the object.
Typically though a function is assigned to a property of an object like this:-
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
o.doAdd = doAdd;
Now the function can be execute using the . notation:-
o.doAdd(a, b);
alert(o.c);
Effectively o.doAdd(a, b) is o.doAdd.call(o, a, b)
var foo = 'bar'
This will scope the foo variable to the function wrapping it, or the global scope.
this.foo = 'bar'
This will scope the foo variable to the this object, it exactly like doing this:
window.foo = 'bar';
or
someObj.foo = 'bar';
The second part of your question seems to be what is the this object, and that is something that is determined by what context the function is running in. You can change what this is by using the apply method that all functions have. You can also make the default of the this variable an object other than the global object, by:
someObj.foo = function(){
// 'this' is 'someObj'
};
or
function someObj(x){
this.x=x;
}
someObj.prototype.getX = function(){
return this.x;
}
var myX = (new someObj(1)).getX(); // myX == 1
In a constructor, you can use var to simulate private members and this to simulate public members:
function Obj() {
this.pub = 'public';
var priv = 'private';
}
var o = new Obj();
o.pub; // 'public'
o.priv; // error
Example for this and var explained below:
function Car() {
this.speed = 0;
var speedUp = function() {
var speed = 10; // default
this.speed = this.speed + speed; // see how this and var are used
};
speedUp();
}
var foo = 'bar'; // 'var can be only used inside a function
and
this.foo = 'bar' // 'this' can be used globally inside an object

Categories

Resources