I am currently reading a book on Javascript by Pragmatic, and I'm confused about one thing. They have a section on how to make variables global, local, or private.
What is the difference between local and private variables? Is there one?
How does one make a variable global or local, They said something about putting 'var =' before it, but it was very vague.
None, People use "private" because they are mistaken and are meant to say "local"
local variables are defined as
var foo = "local";
global variables are a properties of the global scope object (which is window in the browser)
window.foo = "global";
The fact you can do foo = "global"; without first declaring variable foo with var foo is a "bug". This is fixed in ES5 strict mode.
(function () { "use strict"; foo = 42; })()
gives ReferenceError: foo is not defined
Note that you can make variables global by declaring them in outer most scope
var foo = "global";
function bar() {
var foo = "local";
}
It should be noted that you shouldn't have any code in outer most scope, ever. You should be wrapping all your scope in anonymous functions so that you get "module level scope". This means you have a per file based top level scope. This is part of the module pattern.
In the context of the browser, the var keyword scopes the variable to that of the current function.
var a = 10;
var b = function(a) {
console.log(a); # 15
}
b(15);
console.log(a); # 10
If you do not include the var keyword, it is assigned the scope of window and is considered global. Unless you have a very good reason to exclude it, always include the var keyword.
A variable is considered private if it only exists inside a function scope. This commonly takes the form of an anonymous function. This is not actually a private variable in the common sense of the term, it is simply a local variable.
(function() {
var x = 10;
})();
console.log(x); #undefined
What is the difference between local and private variables? Is there
one?
Depends in which context they are used. Generally they mean the same thing. From the OOP perspective, a local variables is usually called private.
How does one make a variable global or local, They said something
about putting 'var =' before it, but it was very vague.
When you put var before variable, it becomes local variables, in the absence though, it becomes global variable. For example:
var foo = 1; // local
foo = 1; // global equivalent to window.foo = 1 becomes part of window object
More Practical Example:
function myfunc(){
var foo = 1; // presence of var keyword
bar = 2; // absence of var keyword
}
alert(foo); // error eg undefined
alert(bar); // 2 because bar is part of window global object
Javascript has a function scope, any variable defined within a function with a var keyword is local to the function and is not visible outside. variables defined in function without var keyword are globals and are visible everywhere.
function test(){
var local = 'local'; // this is local
global = 'global'; // this is global
}
test(); // call a function
alert(local) // undefined
alert(global) // global
Private variables only make sense when you are constructing objects. The typical prototype pattern has you add any necessary variables and helper functions as properties of the instance of the object and/or its prototype, but this has the disadvantage of making them visible to anyone with access to the object. To avoid this, there is an alternative pattern where the variables are local variables of the constructor, and all the methods are declared in the constructor scope and only the public ones are assigned as actual properties of the object.
I find all your answers very odd as I thought it was as follow :
/* A globally scoped and public variable */
var globalVariable = 'global';
/* A globally scoped and public constructor */
function Obj() {
/* private */
/* A locally scoped and private variable */
var privateVariable = 'private';
/* A locally scoped and private method */
privateMethod = function() {
return privateVariable;
}
/* public */
/* A locally scoped and public variable */
this.publicVariable = 'public';
/* A locally scoped and public method */
this.publicMethod = function() {
console.log(privateVariable + ' ' +
privateMethod() + ' ' +
globalVariable + ' ' +
this.publicVariable);
}
};
/* A globally scoped and public object */
var obj = new Obj();
/* displaying various variables and calling methods */
console.log(globalVariable); // global
console.log(obj.privateVariable); // undefined
/* if uncommented will display : ReferenceError: privateVariable is not defined */
// console.log(privateVariable);
/* if uncommented will display : TypeError: obj.privateMethod is not a function */
// obj.privateMethod();
privateMethod(); // nothing is displayed
console.log(obj.publicVariable); // public
obj.publicMethod(); // private private global public
Related
The var keyword in javascript causes a variable to be stored in the local scope. Without var variables belong to the global scope. What about functions? It's clear what happens when functions are declared like variables
var foo = function() {...}
but what scope does
function foo() {...}
belong to?
EDIT:
I realized I didn't ask quite the right question so as a follow up. In the outer most nesting is there a difference between the above two declarations and the following declaration?
foo = function() {...}
It belongs to the current scope, always. For example:
// global scope
// foo is a global function
function foo() {
// bar is local to foo
function bar() {
}
}
Regarding your second question, this:
foo = function() {...}
is an anonymous function expression assigned to a global variable (unless you're running is strict mode, then foo would be undefined). The difference between that and function foo() {} is that the latter is a function declaration (versus a variable declaration, which is assigned an anonymous function expression).
You might be interested in this excellent article about function declarations and function expressions: Named function expressions demystified.
Function declarations are always local to the current scope, like a variable declared with the var keyword.
However, the difference is that if they are declared (instead of assigned to a variable) their definition is hoisted, so they will be usable everywhere in the scope even if the declaration comes in the end of the code. See also var functionName = function() {} vs function functionName() {}.
Noteworthy distinction taking implicit globals into account:
var foo = function() {
// Variables
var myVar1 = 42; // Local variable
myVar2 = 69; // Implicit global (no 'var')
// Functional Expressions
var myFn1 = function() { ... } // Local
myFn2 = function() { ... } // Implicit global
function sayHi() {
// I am a function declaration. Always local.
}
}
Hopefully that clarifies a little. Implicit globals are defined if you forget a var before your assignment. Its a dangerous hazard that applies to variable declarations and functional expressions.
Your first example (var foo = function() {...}) is called an anonymous function. It is dynamically declared at runtime, and doesn't follow the same rules as a normal function, but follows the rules of variables.
If variables in the global context are properties (on the global context), then how are they distinguished from other properties on the global context for the purposes of closures?
Obviously this doesn't work:
function foo() {
this.a = 'a';
this.bar = function() { console.log(a); }
}
new foo().bar(); // ReferenceError: a is not defined
Obviously this does work:
var a = 'a';
function bar() {
console.log(a);
}
bar(); // a
But how given that variable a is a "property". Where is my misunderstanding?
They are not distinguished - they are simply both a variable and a property. You might imagine that the global scope is the only scope object that is accessible as an actual language object.
The global environment consists of an environment record that is bound (like a with statement) to the global object, which itself is exposed as the window object in browsers.
To use your constructor example:
function Foo() {
with (this) {
this.a = 'a';
this.bar = function() { console.log(a); }
// Is `a` a variable or a property? It's *one* thing, available as both.
}
}
new Foo().bar(); // 'a'
Global scope is window object in Web browsers. Thus, a variable declaration in the global scope becomes a property of window.
// Somewhere in the global scope...
// Both declarations add a property to window
window.a = "hello world";
var a = "hello world";
In the other hand, when you add a property to an object using this keyword you're not adding it to the built-in window object. This is why the closure won't locate this.a as just a.
If you don't qualify a property name with this it's a variable that can be local or global - understanding global as a property of window object -.
JavaScript runtime looks for a variable in its current scope, otherwise in the parent scope, and so on, until it reaches global scope and, if window doesn't own a property - actually the variable identifier -, your browsers or any JavaScript runtime will determine that the variable is undefined.
In your first example, this.a is scoped to the this context of foo. If you change your code to this:
function foo() {
var a = 'a';
this.bar = function() { console.log(a); }
}
new foo().bar();
It will work. Otherwise you have to do this:
function foo() {
this.a = 'a';
this.bar = function() { console.log(this.a); }
}
new foo().bar();
The reason your first code example doesn't work is that:
console.log(a);
is looking for a variable named a in scope of the bar() method. But you have never declared such a variable. You've only declared a property on some other object with the name a. If you want to refer to that property, you have to use the appropriate object reference like this:
console.log(this.a);
All properties in Javascript MUST include the object that the property is on in order to access them except for properties on the global object which are treated as global variables. So, a is not the same thing as this.a in your context.
Variables are only global if they are declared in the global scope or explicitly attached to the global object (which is window in a browser) or if they are implicitly assigned to without declaration and you are not in strict mode (I call these accidental globals and consider them a horrible thing).
So, here are a couple things you could do.
Use a public instance variable:
function foo() {
this.a = 'a';
this.bar = function() { console.log(this.a); }
}
new foo().bar(); // outputs the member variable a
Or use a constructor local variable (essentially a private instance variable):
function foo() {
var a = 'a';
this.bar = function() { console.log(a); }
}
new foo().bar(); // outputs the member variable a
Or use an actual global (not recommended):
var a;
function foo() {
a = 'a';
this.bar = function() { console.log(a); }
}
new foo().bar(); // outputs the global a
Trying to understand fundamentals of javascript I ran into a following code and expected value of variable named "foo" would be 7 and 5 however it came out as 7 and 7. Not sure why....
var foo = 5;
(function Test() {
foo = 7;
console.log("foo=" + foo);
})();
console.log("foo=" + foo);
foo=7
foo=7
Because when you do foo = 7; it makes a global variable and sets it to 7, even after the function is done it's still 7. You probably want it to be a local variable:
(function Test() {
var foo = 7;
console.log("foo=" + foo);
})();
To get 7 and 5, you need to put "var" before "foo = 7;" in your function in order to keep it from overwriting the the global foo you declared outside the function.
That is, you need to use var when declaring variables within functions to make them locally scoped to the function.
You are declaring a global variable and then referencing it inside your function. if you want a local variable, declare it inside your function using the var keyword.
//foo variable definition here
var foo = 5;
(function Test() {
//Referencing the already globally defined var.
//Use var foo = 7 in order to define a new local var.
foo = 7;
console.log("foo=" + foo);
})();
console.log("foo=" + foo);
Referencing a global variable inside an immediately called anonymous method doesn't mean it overrides the variable in the global scope!
Something like foo=7 will create a new variable only if there is no other foo that is accessible from the current scope. Which in this case exists!
Immediately called Anonymous function is not a completely isolated scope. As a function, it has a local scope, which is not available outside the block. But it still have access to the global scope.
JavaScript normally follows the function scope i.e. variables are accessible only within the function in which they are declared.
One of the ways to break this convention and make the variable accessible outside the function scope is to use the global window object
e.g.
window.myVar = 123;
My question is are there any other ways in JavaScript/jQuery to make the variable accessible outside the function scope?
Not with variable declarations, no. You can obviously declare a variable in an outer scope so that it's accessible to all descendant scopes:
var a; // Available globally
function example() {
a = "hello"; // References a in outer scope
}
If you're not in strict mode you can simply remove the var keyword. This is equivalent to your example:
// a has not been declared in an ancestor scope
function example() {
a = "hello"; // a is now a property of the global object
}
But this is very bad practice. It will throw a reference error if the function runs in strict mode:
function example() {
"use strict";
a = "hello"; // ReferenceError: a is not defined
}
As you wrote, variables are only visible inside the function in which they were defined (unless they are global).
What you can do is assign variables to the function object itself:
function foo() {
foo.myVar = 42;
}
console.log(foo.myVar); // outputs "undefined"
foo();
console.log(foo.myVar); // outputs "42"
But I would advise against it. You should really have a very good reason to do something like this.
You can define them as part of a global object, then add variables later
// Define your global object
var myObj = {};
// Add property (variable) to it
myObj.myVar = 'Hello world';
// Add method to it
myObj.myFunctions = function() {
// Do cool stuff
};
See the link below:
Variable declaration
Also, you can declare it without the var keyword. However, this may not be a good practice as it pollutes the global namespace. (Make sure strict mode is not on).
Edit:
I didn't see the other comments before posting. #JamesAllardice answer is also good.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What advantages does using (function(window, document, undefined) { … })(window, document) confer?
I'm increasingly seeing code like this in libraries I've been using:
(function (window) {
var Foo = function () {
}
window.Foo = Foo;
})(window);
The argument I've seen for doing this is to avoid working in the global scope when creating (pseudo) classes. But, correct me if I'm wrong, I always understood that window IS the global scope. I believe, when you create a global variable, you are really only adding a property to window anyway... Unless this is changing for ES5 strict?
So, basically, what's the point? The only benefit I can see to code organised like this is if you wanted to easily change the namespace of your classes at a later date by passing in an argument other than window.
Infact, strict mode throws an exception if you forget to use var for any variable declaration. But that works even without using an outer closure.
Using this pattern is much more for protecting yourself from the outside javascript world. For instance, some other script overwrites window.undefined or any other variable, you can grab the value within that closure to savely access it from within.
For instance
(function _myApp( win, doc, undef ) {
// app code
}( this, this.document ));
Also, when declaring variables with var, or creating function declarations, those are always stored within the current Activation Object respectively the Lexical Environment Record. That means, without using a Function context, you can easily overwrite methods and variables from some other point, because all of those would get stored in the current Context (which would be the global one)
So:
(function _myApp( win, doc, undef ) {
var myVar = 42;
function myFunc() {
}
}( this, this.document ));
(function _myModule( win, doc, undef ) {
var myVar = 42;
function myFunc() {
}
}( this, this.document ));
This works because of closure and Context, but if you would use the same code, without the Function Context, we would obviously overwrite our myVar and myFunc. This could happen from everywhere, within the same file or in another loaded script.
As evil as global variables are, you need to have atleast one or there's no way to access your script. The code you provided is one way to create that one global variable. I prefer this way:
window.Foo = (function () {
var func = function () {
// ...
};
return {
func: func
};
})();
Your're right, but the difference is that the code inside of the function acts like an automatic init function.
(function (window) {
var Foo = function () {
}
var Bar = 69; // not in global scope
window.Foo = Foo; // in global scope
})(window);
As opposed to
var Foo = function () { // in global scope
}
var Bar = 69; // in global scope
and
var Foo = function () { // in global scope
}
function init () {
var Bar = 69; // not in global scope
}
init();