JavaScript local scoping: var vs. this - javascript

I can't seem to get my head around a specific case of scoping for JavaScript variables. Different from other examples and questions I have found, I am interested in the scoping for nested functions.
I've set up an example at this JSFiddle. The relevant part is the following:
function MyObject() {
var self = this;
var a = 1;
this.b = 2;
var innerMethod = function() {
//1 and 2: direct reference
logMessage("a = " + a); // a = 1
//logMessage("b = " + b); // Error: b is not defined
//3 and 4: using this
logMessage("this.a = " + this.a); // this.a = undefined
logMessage("this.b = " + this.b); // this.b = undefined
//5 and 6: using self
logMessage("self.a = " + self.a); // self.a = undefined
logMessage("self.b = " + self.b); // self.b = 2
}
}
Now, I understand that a reference to a directly works.
I also understand that messages 3 and 4 (this.a and this.b) will fail because this refers to the internal function. I also understand that line 6 works because I save the reference to the original object.
What I do not understand is:
why aren't messages 1 and 2 working alike?
why aren't messages 5 and 6 working alike?

The a variable is just that, a variable. It's visible in the scope of innerMethod (which is just a nested function), as a, which is how it was declared (ie. JavaScript has lexical scoping rules, inner functions can see variables of the functions they're defined inside of).
this isn't the same as the local scope of the MyObject constructor.
You've seen that self is an alias for this of MyObject, and that innerMethod has overwritten this in its own scope. Still, since this is not an alias for function scope, neither self.a nor this.a will ever work here.
For a more rigorous explanation of lexical scoping you can e.g. start at wikipedia: http://en.wikipedia.org/wiki/Scope_(computer_science)
You can read about the execution contexts and identifier resolution rules in the ECMA standard http://es5.github.com/#x10.3

It's a problem with scope, when functions are created they save their surroundings (including variables).
So when innerMethod is created, it can see variables self and a.
An important concept is that the scope is created when the function is declared, instead of when it is called.
In your case 1, b is not being declared (the this object is not the same).
In cases 5 and 6, you did not create self.a.

The main reason is that self is not equal to this in scope of innerMethod. this is a keyword to reference the owner of the function. For innerMethod, it is NOT a instance method, it belongs to the Window.
function MyObject() {
var self = this;
var innerMethod = function() {
alert("inner method, self == this?: " + self == this); // false
alert("inner method: " + this); // [object Window]
alert("closest constructor name of in prototype chain ?: "+ this.__proto__.constructor.name); // Window
}
this.outerMethod = function(){
innerMethod();
alert("outer method: " + this); // [object MyObject]
alert("closest constructor name in prototype chain?: "+ this.__proto__.constructor.name); // MyObject
}
}
var o = new MyObject();
o.outerMethod();
You can play at here

Related

Why do some variables declared using let inside a function become available in another function, while others result in a reference error?

I can't understand why variables act so strange when declared inside a function.
In the first function I declare with let the variables b and c with the value 10:
b = c = 10;
In the second function I show:
b + ", " + c
And this shows:
10, 10
Also in first function I declare a with value 10:
let a = b = c = 10;
But in the second function it shows an error:
Can't find variable: a
Now in the first function I declare d with value 20:
var d = 20;
But in the second function it shows the same error as before, but with the variable d:
Can't find variable: d
Example:
function first() {
let a = b = c = 10;
var d = 20;
second();
}
function second() {
console.log(b + ", " + c); //shows "10, 10"
try{ console.log(a); } // Rreference error
catch(e){ console.error(e.message) }
try{ console.log(d); } // Reference error
catch(e){ console.error(e.message) }
}
first()
It's because you're actually saying:
c = 10;
b = c;
let a = b;
And not what you think you are saying, which is:
let a = 10;
let b = 10;
let c = 10;
You'll notice that no matter how many variables you add to your chain, it will only be the first (a) that causes the error.
This is because "let" scopes your variable to the block (or, "locally", more or less meaning "in the brackets") in which you declare it.
If you declare a variable without "let", it scopes the variable globally.
So, in the function where you set your variables, everything gets the value 10 (you can see this in the debugger if you put a breakpoint). If you put a console log for a,b,c in that first function, all is well.
But as soon as you leave that function, the first one (a)--and again, keep in mind, technically in the order of assignment, it is the last one-- "disappears" (again, you can see this in the debugger if you set a breakpoint in the second function), but the other two (or however many you add) are still available.
This is because, "let" ONLY APPLIES TO (so only locally scopes) THE FIRST VARIABLE--again, which is technically the last to be declared and assigned a value--in the chain. The rest technically do not have "let" in front of them. So those are technically declared globally (that is, on the global object), which is why they appear in your second function.
Try it: remove the "let" keyword. All your vars will now be available.
"var" has a similar local-scope effect, but differs in how the variable is "hoisted", which is something you should definitely understand, but which is not directly involved with your question.
(BTW, this question would stump enough pro JS devs to make it a good one).
Strongly suggest you spend time with the differences in how variables can be declared in JS: without a keyword, with "let", and with "var".
In the function first(), variables band c are created on the fly, without using var or let.
let a = b = c = 10; // b and c are created on the fly
Is different than
let a = 10, b = 10, c = 10; // b and c are created using let (note the ,)
They become implicit global. That's why they are available in second()
From documentation
Assigning a value to an undeclared variable implicitly creates it as a global variable (it becomes a property of the global object) when the assignment is executed.
To avoid this, you can use "use strict" that will provide errors when one use an undeclared variable
"use strict"; // <-------------- check this
function first() {
/*
* With "use strict" c is not defined.
* (Neither is b, but since the line will be executed from right to left,
* the variable c will cause the error and the script will stop)
* Without, b and c become globals, and then are accessible in other functions
*/
let a = b = c = 10;
var d = 20;
second();
}
function second() {
console.log(b + ", " + c); //reference error
console.log(a); //reference error
console.log(d); //reference error
}
first();
Before calling things strange, let’s know some basics first:
var and let are both used for variable declaration in JavaScript. For example,
var one = 1;
let two = 2;
Variables can also be declared without using var or let. For example,
three = 3;
Now the difference between the above approaches is that:
var is function scoped
and
let is block scoped.
while the scope of the variables declared without var/let keyword
become global irrespective of where it is declared.
Global variables can be accessed from anywhere in the web page (not recommended because globals can be accidentally modified).
Now according to these concepts let's have a look at the code in question:
function first() {
let a = b = c = 10;
/* The above line means:
let a=10; // Block scope
b=10; // Global scope
c=10; // Global scope
*/
var d = 20; // Function scope
second();
}
function second() {
alert(b + ", " + c); // Shows "10, 10" //accessible because of global scope
alert(a); // Error not accessible because block scope has ended
alert(d); // Error not accessible because function scope has ended
}
Variables using the let keyword should only be available within the scope of the block and not available in an outside function...
Each variable that you are declaring in that manner is not using let or var. You are missing a comma in the variables declaration.
It is not recommended to declare a variable without the var keyword. It can accidentally overwrite an existing global variable. The scope of the variables declared without the var keyword become global irrespective of where it is declared. Global variables can be accessed from anywhere in the web page.
function first() {
let a = 10;
let b = 10;
let c = 10;
var d = 20;
second();
}
function second() {
console.log(b + ", " + c); //shows "10, 10"
console.log(a); //reference error
console.log(d); //reference error
}
first();
It's because of when you don't use let or var then variable is getting declare on the fly, better you declare like following.
let a = 10;
let b = 10;
let c = 10;
The strange issue is caused by scoping rules in JavaScript
function first() {
let a = b = c = 10; // a is in local scope, b and c are in global scope
var d = 20; // d is in local scope
second(); // will have access to b and c from the global scope
}
Assuming that you want to declare 3 local variables initialised to the same value (100). Your first() will look like below. In this case, second() will not have access to any of the variables because they are local to first()
function first() {
let a = 100; // a is in local scope init to 100
let b = a; // b is in local scope init to a
let c = b // c is in local scope init to b
var d = 20; // d is in local scope
second(); // will not have access a, b, c, or d
}
However, if you want global variables then your first() will look like below. In this case, second will have access to all the variables because they are in global scope
function first() {
a = 100; // a is in global scope
b = a; // b is in global scope
c = b // c is in global scope
d = 20; // d is in global scope
second(); // will have access to a, b, c, and d from the global scope
}
Local variables (aka. accessible in the code block where they are declared). A Code block is any {} with line(s) of code between.
function() {var, let, const in here is accessible to entire function},
for() {var in here is accessible to outer scope, let, const accessible only in here},
etc.
Global variables (aka accessible in the global scope).
These variables are attached to the global object. The global object is environment dependent. It is the window object in browsers.
Special note: You can declare variables in JavaScript without using the var, let, const keywords. A variable declared this way is attached to the global object, therefore accessible in the global scope.
a = 100 // is valid and is in global scope
Some articles for further reading:
https://www.sitepoint.com/demystifying-javascript-variable-scope-hoisting/
https://scotch.io/tutorials/understanding-scope-in-javascript
https://www.digitalocean.com/community/tutorials/understanding-variables-scope-hoisting-in-javascript
Main difference is scoping rules. Variables declared by var keyword are scoped to the immediate function body (hence the function scope) while let variables are scoped to the immediate enclosing block denoted by { } (hence the block scope). And when you say
c = 10;
b = c;
let a = b;
c and b have the life span as fun have but a only have block span and if you try to access a by referencing it always show error but c and b are globally so they don't.You'll notice that no matter how many variables you add to your chain, it will only be the first (a) that causes the error.This is because "let" scopes your variable to the block (or, "locally", more or less meaning "in the brackets") in which you declare it.If you declare a variable without "let", it scopes the variable globally.So, in the function where you set your variables, everything gets the value 10 (you can see this in the debugger if you put a break-point). If you put a console log for a,b,c in that first function, all is well.But as soon as you leave that function, the first one (a)--and again, keep in mind, technically in the order of assignment, it is the last one-- "disappears" (again, you can see this in the debugger if you set a break-point in the second function), but the other two (or however many you add) are still available.
Here are the 3 interesting aspects of variable declarations in JavaScript:
var restricts the scope of variable to the block in which it is defined. ('var' is for local scope.)
let allows temporary overriding of an external variable's value inside a block.
Simply declaring a variable without var or let will make the
variable global, regardless of where it is declared.
Here is a demo of let, which is the latest addition to the language:
// File name: let_demo.js
function first() {
a = b = 10
console.log("First function: a = " + a)
console.log("First function: a + b = " + (a + b))
}
function second() {
let a = 5
console.log("Second function: a = " + a)
console.log("Second function: a + b = " + (a + b))
}
first()
second()
console.log("Global: a = " + a)
console.log("Global: a + b = " + (a + b))
Output:
$ node let_demo.js
First function: a = 10
First function: a + b = 20
Second function: a = 5
Second function: a + b = 15
Global: a = 10
Global: a + b = 20
Explanation:
The variables a and b were delcared inside 'first()', without var or let keywords.
Therefore, a and b are global, and hence, are accessible throughout the program.
In function named 'second', the statement 'let a = 5' temporarily sets the value of 'a' to '5', within the scope of the function only.
Outside the scope of 'second()', I.E., in the global scope, the value of 'a' will be as defined earlier.

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

Functions created with the Function constructor are always created in the global scope

From the MDN description of Function:
Note: Functions created with the Function constructor do not create
closures to their creation contexts; they always are created in the
global scope. When running them, they will only be able to access
their own local variables and global ones, not the ones from the scope
in which the Function constructor was called. This is different from
using eval with code for a function expression.
I understand,
var y = 10;
var tester;
function test(){
var x = 5;
tester = new Function("a", "b", "alert(y);");
tester(5, 10);
}
test(); // alerts 10
Replacing the tester = new Function("a", "b", "alert(y);"); with tester = new Function("a", "b", "alert(x);");, I will get
// ReferenceError: x is not defined
But couldn't understand the author's line-
...they always are created in the global scope.
I mean how is the new Function("a", "b", "alert(y);"); nested within the test fn is in global scope?
In fact, accessing it from outside the test fn will simply result in
Uncought TypeError:tester is not a function
Please elucidate.
In your example, "created in the global scope" means that tester will not have closure over x from test:
function test(){
var x = 5;
tester = new Function("a", "b", "alert(x);"); // this will not show x
tester(5, 10);
}
When you new up a Function, it does not automatically capture the current scope like declaring one would. If you were to simply declare and return a function, it will have closure:
function test(){
var x = 5;
tester = function (a, b) {
alert(x); // this will show x
};
tester(5, 10);
}
This is the trade-off you make for having dynamically compiled functions. You can have closure if you write the function in ahead of time or you can have a dynamic body but lose closure over the surrounding scope(s).
This caveat doesn't usually matter, but consider the (slightly contrived) case where you build a function body as a string, then pass it to a function constructor to actually be evaluated:
function addOne(x) {
return compile("return " + x + " + 1");
}
function addTwo(x) {
return compile("return " + x + " + 2");
}
function compile(str) {
return new Function(str);
}
Because the function is instantiated by compile, any closure would grab str rather than x. Since compile does not close over any other function, things get a bit weird and the function returned by compile will always hold a closure-reference to str (which could be awful for garbage collection).
Instead, to simplify all of this, the spec just makes a blanket rule that new Function does not have any closure.
You have to create an object to expose via return inside the test() function for it to be global. In other words, add var pub = {} and name your internal functions as properties and/or methods of pub (for example pub.tester = new func) then just before closing test() say return pub. So, that way it will be publically available (as test.tester). It's Called the Revealing Module Pattern.
What it means is that inside the function you can only refer to global variables, as you've found. However, the reference to the function itself is still in the local scope where it was created.
I'm confused as to where the confusion is.
It says that the function will be in global scope...and therefore will only have access to its own scope and the global scope, not variables local to the scope in which it was created.
You tested it and it has access to its own scope and the global scope, not variables local to the scope in which it was created.
So where's the confusion?
Is it in your assigning of the function to the variable testing? testing is just a local variable with a reference to the function...that has nothing to do with the scope of the creation of the function.
Scope is lexical, and has to do with where the function is created, not what random variables a function reference happens to be assigned to at runtime. And the documentation is telling you that when you make a function this way it acts as if it was created in the global scope...so it's acting completely as expected.
Here's an illustration:
This:
var y = 10;
var tester;
function test()
{
var x = 5;
// 10 and errors as not defined
tester = new Function("console.log(y); console.log(x);");
}
Is similar to this:
var y = 10;
var tester;
function test()
{
var x = 5;
// also 10 and errors as not defined
tester = something;
}
function something()
{
console.log(y);
console.log(x);
}
NOT
var y = 10;
var tester;
function test()
{
var x = 5;
// 10 and 5...since x is local to the function creation
tester = function()
{
console.log(y);
console.log(x);
}
}

Scope within an anonymous function?

I'm coming from an Actionscript background and (very late to the party) I am trying to learn JavaScript. I am going through this AngularJS - Video Tutorial For Beginners on YouTube (it's pretty good) and saw something really basic that I don't understand.
At line 5 the var workcount is defined. Then two anonymous functions are defined and returned in an object. The functions reference workcount but isn't workcount in a different scope? Is this like blocks in Objective-C where local vars remain accessible within the block. Is there a name for what this is?
Or if a function "knows about" vars previously defined in its scope, would the function task2 "know about" task1?
It bugs me that I can't make sense of this.
Update: Thanks for all the replies. I get it now – and while I have seen the term "closures" before, I never understood it (it seems a not very descriptive term. In reading up, I saw the term "stack-frames" and then the light bulb lit up: stack... frame of reference);
var createWorker = function(){
var workCount = 0;
var task1 = function(){
workCount += 1;
console.log("task1" , workCount);
};
var task2 = function(){
workCount += 1;
console.log("task2" , workCount);
};
return {
job1: task1,
job2:task2
}
};
worker=createWorker();
worker.job1();
worker.job2();
Output:
task1 1
task2 2
Just note that the variable and the two anonymous functions are wrapped inside the same function (let's call it a parent function). So the scope of this variable is available within this parent function.
So now this variable acts as a global variable for these two inner functions But the scope is limited to the parent function. Both the inner functions share the same variable.. Changing the value of the variable in one function will have effect in other function too..
So taking the logic in the post Let's say we execute task1 and task2 one after the other. The variable is initially set to 0. Then in your task1 it's incremented by one. Which makes the variable value 1 (0 + 1). Now in task two also its increased by one, making its value 2 (1 + 1).
This scope concept is called as closure in JavaScript.
This is called a closure in JavaScript.
The scope of a closure in JavaScript is lexical, which means that everything that is contained within the function the closure belongs to, has access to any variable that is in it
Basically createWorker is a scope and since task 1 and task 2 are declared inside createWorker they have access to all the variables declared in createWorkers scope.
But createWorker does not have access to any variables declared inside task 1 and task 2.
Yes, functions are aware of everything in their scope, including each other.
There are two parts to your question.
The second part is easy to answer first: all variables and functions in a scope are "hoisted," allowing you to use a variable before you declare it:
x = 5;
var x;
console.log(x); // Gives 5
Back to the first part of your question: in terms of scope, I won't expand too much on it since it is a widely covered topic on this and other sites. w3schools has a good guide on this.
Basically, it boils down to global and local scope. Global scope works as you might imagine, with the variable (or function) being available globally:
var x = 10;
function foo() {
console.log('Global scope! ' + x);
}
Local scope is, basically, for everything within a closure (a topic well beyond this question), which functions are:
function foo() {
bar(); // This will work, since foo and bar share scope
foobar(); // This will not work: foobar is only in scope within bar
}
function bar() {
function foobar() {
console.log('foobar');
};
console.log('bar');
foobar(); // This will work, since foobar is defined within bar's local scope
}
Things get a little more complicated with var declarations. This is being greatly simplified by the ES6 let declaration. Read more.
And by the way, while your functions are anonymous, they aren't really since you are saving references to them. Functionally, the two examples below are perfectly equivalent:
// These give the exact same result
function foo() {}
var foo = function() {}
// You can use either by calling
foo();
This code illustrates how it works.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Closure JS</title>
<script type="text/javascript">
var createWorker = function () {
var workCount = 0;
var task1 = function () {
var t = t || 0;
workCount += 1;
console.log("task1: " + workCount);
console.log("task1 t: " + (t++));
}
var task2 = function () {
var t = t || 0;
workCount += 1;
console.log("task2: " + workCount);
console.log("task2 t: " + (t++));
}
return {
job1: task1,
job2: task2
};
}
var app = new createWorker();
</script>
</head>
<body>
<div>
<input type="button" value="task1" onclick="app.job1()" />
<input type="button" value="task2" onclick="app.job2()" />
</div>
</body>
</html>
Console output after several clicks on buttons:
task1: 1
task1 t: 0
task1: 2
task1 t: 0
task2: 3
task2 t: 0
task2: 4
task2 t: 0
It easy to see that task1 and task2 know about their parent scope and know nothing about each other and about their previous execution.
This way ball bounces.
You can write write your code as in below and javascript will interpret it the same.
var createWorker = function(){
var workCount, task1, task2;
workCount = 0;
task1 = function(){
workCount += 1;
console.log("task1" , workCount);
};
task2 = function(){
workCount += 1;
console.log("task2" , workCount);
};
return {
job1: task1,
job2:task2
}
};
What happens here is, variables are defined at the top of the enclosing function block. No matter in what order they are defined. So not only task2 knows about task1, task1 also knows about task2. However order of assignments in important. Consider the code:
function foo1() {
console.log("foo1: " + a);
var a = "Hello";
}
function foo2() {
var a = "Hello";
console.log("foo2: " + a);
}
function foo3() {
console.log("foo3: " + a);
let a = "Hello";
}
function foo4() {
console.log("foo4: " + b);
}
var b = 5;
foo1(); // undefined
foo2(); // Hello
try {
foo3(); // Throws ReferenceError
} catch (e) {
console.log("foo3: " + e.message);
}
foo4(); // 5
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
When foo1 tries to use a, it was defined but it was not assigned.
foo3 uses let instead of var. let is more intuitive for some
coming from other programming languages. But be careful as it is part
of ES6 specification and not widely supported yet.
foo4 works since b was defined before foo4 was
defined. b was assigned before foo4 was invoked.
JavaScript has some interesting variable scoping rules. Here is a quick overview:
x = 0; // Global, as no "var" keyword preceeds it. Btw: var is optional!
var x = 0; // This is scoped to it's parent fn. Child fn's can use it.
let x = 0; // This is similar to var, but has a special use case. (See below.)
As an added bonus, this next line of code looks like it's a variable declaration, but it's not. It defines a constant. It's part of the EcmaScript 2015 spec, AKA ES6. Here's what's new in ES6.
const x = 0; // This is a constant (locked variable) and can't be changed.
While both var & let are accessible by their immediate function & their children functions, here is where they're different: The let keyword can allow someone to make duplicates variables with the same name, from both inside of the parent & child functions! It just makes JS stranger!
Since workCount is defined inside of the parent createWorker function with the "var" keyword, then the task1 & task2 functions can change it's value, as they are children functions.
Check out the MDN specs on how the var & let keywords work.
So the answers to some of your questions are:
No, it's in the same parent "createWorker" function scope.
Unknown as I don't write ObjectiveC code. Someone else can answer that one.
Yes & No: Yes, because it can tell that task1 is a function, but No, because the code in task2's function block can't see inside of task1's function block.
task 2 would not know about variables created within task 1, task 1 and task 2 do know about workCount.

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