JavaScript Variables are named memory locations that hold a value. JavaScript supports only a handful of data types. The primitive types are number
, string
, boolean
, and two special types: null
and undefined
.
Primitive types are the basic, ready-to-use variable types that are built into the language.
JavaScript's number is the only type to hold numbers. It does not distinguish
between byte, integer, long, double, or any other numeric type. As far as JavaScript
is concerned a number is a number. Most programming languages support a separate integer type,
but JavaScript does not. The implication of this is that in JavaScript the values
10
, 10.0
, and 1e1
are all the same.
var a = 10;
var b = 10.0;
var c = 1e1;
console.log(a === b); // => true
console.log(a === c); // => true
console.log(b === c); // => true
Here are some valid numeric literals: 1
, 209
,
-8
, 4.5
, -99.9999
,
3e2
.
JavaScript supports two special numeric values: NaN
and Infinity
.
They are discussed on the page about 'JavaScript Operators'.
JavaScript's strings are immutable sequences of characters. String literals are enclosed
by single or double quotes, like so: "Hello"
or 'Hello'
.
Once created a string cannot be changed (this is what immutable refers to). However, it is easy
to create a new string by manipulating existing strings, such as: "Hello".substr(3)
,
which creates a new string with "lo"
as its value. JavaScript does
not support the single character (char) type, but you can easily use a single character string,
such, as "a"
, or "Y"
.
Here are some string examples:
var s = "Hello World";
var t = s.substr(6); // new string
console.log(t); // => World
Like other languages, JavaScript's boolean has two possible values: true and false. Note that true and false are language keywords and they are distinct from 1 and 0.
var b = false;
console.log(b); // => false (i.e. not 0)
Both null
and undefined
can be regarded as a special value that indicates
"no value".
The null
is a language keyword (in fact, it is an object) which is used to indicate
the expected lack of value. On the other hand, undefined
is a predefined global variable
that has a deeper meaning and is used to indicate an error-like, unexpected lack of value.
When your function has no return value, it returns undefined. If you declare a variable and don't initialize it, it returns the undefined value. If you query a non-existent array element or object property, again an undefined is returned. Here is an example.
var book;
console.log(book); // => undefined
console.log(typeof book); // => undefined
If you want to indicate the 'lack of value' in your code, you typically use null rather than undefined.
var book = null;
console.log(book); // => null
console.log(typeof book); // => object (although null is not a true object)
Both null and undefined qualify as false when a boolean value is required. They don't have any properties. If you attempt to access a property on them, an exception will be raised.
It is considered good practice to leave the use of undefined to JavaScript. In other words, let JavaScript determine if something is undefined, rather than you setting variables or properties to undefined. If your app requires that a variable or property value is unknown, give it a value of null and not undefined.
It is interesting to note that undefined is implemented as a global variable named 'undefined'. Its value is undefined. Since it is a global variable, there is nothing that prevents a malicious coder from re-assigning the value of undefined to something else, like so:
// hacker's code undefined = true;
Clearly, this would wreak havoc with many JavaScript programs. Our Dofactory JS product has a lot more to say about this attack and ways to protect your code against this risk. To learn more click here.
Variables in JavaScript are declared with the var
keyword. You have several options on
structuring your variable declaration and initialization:
// declaring one variable var cost; // declaring multiple variables, delimited by commas var cost, profit; // declaring and assigning one variable var cost = 120; // declaring and assigning multiple variables var cost = 120, profit = 77;
You can declare one variable at a time.
Let's look at variable naming rules. A variable name can contain any combination of alpha-numeric characters, the $ sign, and the underscore character. Its first character cannot be a digit. Variable names cannot contain space characters or any of the punctuation characters. Here are some examples of valid variable identifiers:
var _groupName_; var $bicycle12; var ABH; var particle_X_Y; var abc$123; var easy;
If a variable is not declared explicitly (using var
), then JavaScript will automatically treat
it as a global variable. This can hide misspelled and forgotten variable declarations and
consequently introduce bugs in your program. This is demonstrated below.
In this example, the variable count is
missing a var
and will be created implicitly. The variable reslt
is a misspelling of result
and a new global variable named reslt
will be created. Worse, the original result value will
always remain false.
count = 4; // => global count is created var result = false; if (condition === true) { reslt = true; // => global reslt is created! }
As you can see, typos are not called out in JavaScript and can lead to subtle and hard-to-detect bugs.
JSLint uncovers implied global variables and requires that you declare them explicitly using the
var
keyword before they are assigned a value. Using var
also improves program readability.
Even if you use var
, you still have to be careful when chaining declarations and assignments.
In the following code all seems fine, but total
is a local variable, but summary
is an implied global.
function calculate() { var total = summary = 0; // => summary is implied global variable ... }
The expression summary = 0
is evaluated first.
Since summary
is not declared, it is treated as global.
The expression returns the value 0 which is further assigned to the variable total
.
Because total
is declared with a var
keyword,
it is a local variable with function scope.
When declaring a global variable, you are actually defining a property on the global object.
If the global variable is created with var
, the property that is created
cannot be deleted (undefined) with the delete operator. On the other hand, implied globals
can be deleted.
var a = 1; // => explicit global b = 2; // => implied global delete a; // => cannot delete delete b; // => deleted
The scope of the variable determines its visibility and its lifetime. Visibility determines the portions of the program in which it is accessible. Lifetime is the period during execution of a program in which a variable or a function exists.
I n programming, variable scoping is an important concept. JavaScript supports two scope-levels, global and functional, which are discussed next.
In JavaScript, all variables that are defined outside functions are globally scoped; this means they are visible and accessible anywhere in the program. Variables that are defined inside a function have function scope, meaning they are only visible and accessible within the function, for the duration of that function.
In the example below variable g
is global and is visible anywhere,
including the function. The variables u
and c
are only
visible within the function. It is said that variable g
has global scope
and variables u
and c
have function scope.
var g = "World"; // global scope
function countries() {
var u = "US"; // function scope
var c = "China"; // function scope
console.log(g); // => World
console.log(u); // => US
console.log(c); // => China
}
countries();
console.log(g); // => World
console.log(typeof u); // => undefined
The last line demonstrates the variable u
is not visible outside the
countries()
function.
If you declare a local variable inside a function with the exact same name as a global variable, then the local variable will hide the global variable. In the next example, the local client variable hides the global client variable.
var client = "Joan"; // global
function getClient() {
var client = "Timothy"; // local, hides global
return client;
}
console.log(getClient()); // => "Timothy"
In C-like languages, when control enters a code block (for example an if statement enclosed by brackets), then local variables defined within the block will have their own execution context and are destroyed when the closing block brace is encountered. However, JavaScript does not support block-level scoping, only function and global level scoping.
In the example below, the client variable in the if-block refers to the global variable. There is no hiding or anything of that nature, just one global variable named client.
var client = "Joan";
if (true) {
var client = "Timothy"; // refers to global variable
console.log(client); // => "Timothy"
}
console.log(client); // => "Timothy"
When using variables in for
loops you have to be careful because
they continue to exist outside the loop. In the example below, the for-statement creates the
variable i
which continues to exist outside the loop, even after the
for-statement finishes execution. Most other languages that support block level scoping the
looping variables cease to exist outside the for loop.
for (var i = 0; i < 5; i++) {
// do something
}
console.log(i); // => 5
The JavaScript compiler invisibly moves (hoists) all the variables to the top of their containing scope. Consider this code:
function f() { doSomething(); var count; }
JavaScript transforms the above code to this:
function f() { var count; // hoisted doSomething(); }
All variables that you declare inside a function are visible throughout the function body (this is what we mean with function scope). This implies that variables are visible even before they are declared, but using a variable before it is initialized can lead to bugs. Here is an example:
var x = 1; function f () { console.log(x); // => undefined var x = 2; }
Notice we have a global variable x
and a local variable x
.
The undefined result may surprise you. Perhaps you expected a value of 1 or possibly 2, but not undefined.
It's all because of hoisting which involves the variable declaration, but does not include the
assignment portion. Here is how the code executes:
var x = 1; function f () { var x; // hoisted. hides global variable, but is unitialized. console.log(x); // => undefined x = 2; }
It's not only variables that are hoisted, functions are too. Consider the following code:
var text = "Hello";
function f() {
text = "Greetings";
return;
function text() { }
}
f();
console.log(text); // => "Hello"
What is going on here? Well, the compiler lifts (hoists) the local function text()
to the top of f()
's function body. Since declarations are function-scoped,
the assignment of "Greetings" is made to the local text
instance (which is a function)
and, therefore, the global text variable remains unchanged. The code executes like this:
var text = "Hello";
function f() {
function text() { } // local variable text. Hides global text.
text = "Greetings"; // local assignment to function named text
return;
}
f();
console.log(text); // => "Hello"
Finally, consider this example in which two local print functions are within an if-else statement:
function f() {
var condition = true;
if (condition) {
function print() { console.log("true"); };
} else {
function print() { console.log("false"); };
}
print(); // => true or false (depending on browser)
}
f();
We know that functions get hoisted, so what will happen? Since the value of condition is true,
you may expect that the print()
inside the if block will execute. But this is
not the case. Edge prints false and Firefox prints true. What this indicates is that hoisting is not
concerned about the runtime code, that is, at compile time the conditions in the if-else statements
are irrelevant. Also, there are no definite rules that dictate which function declaration shall prevail
over the others.
The lesson learned here is that side effects of implicit global variables and of hoisting can result in hard-to-find bugs. Our Dofactory JS offers proven patterns and best practice techniques to minimize these kinds of problems. To learn more click here.