When I first started learning JavaScript, I was thrown off by some of its terminology and quirks. This post is intended to offer some guidance into the craziness of the JavaScript world for beginning JavaScripters.
JavaScript is a dynamically-typed, object-oriented programming language that is usually used on the client side in web browsers.
Functions are central to one’s undertanding of JavaScript, so let’s start with the difference between function declarations and function expressions.
Function Declarations vs. Function Expressions
A function declaration, or function statement, is when you define a function without a variable assignment. A function expression is when you define a function and set the result of that function equal to a varialbe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Scoping
In JavaScript, you have global scope and local scope. If a variable is defined outside of any function, it is considering to be a global variable, which can be accessed by any function. It is scoped to the entire document.
If the variable is defined inside of a function, that variable is scoped to that function and is only accessible to that function.
1 2 3 4 5 6 7 8 9 10 |
|
Hoisting
One unique quirk in JavaScript is variable and function hoisting. Function declarations and function variables are always moved to the top of their scope by the interpreter.
Since all variables defined in a function are scoped to the function level, any variables declared throughout the function are initialized as undefined
at the beginning of the function. They are given a value when it reaches the variable assignment. Forward referencing is not possible for variables because the assignment itself isn’t hoisted, just the initialization is.
However, forward referencing for function declarations is possible because placement is irrelevant for simple function declarations. All function declarations are automatically moved to the top of the function.
Let’s look at some examples.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
To prevent variable hoising, you can use self-executing anonymous functions, also known as immediately-invoked function expressions (IIFEs).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
As you can see, IIFEs preserve the context of the origin function expression placement by passing the current state of the variable to the function.
Object-Orientation
Coming from Ruby, I had a good understanding of OOP before learning JS. However, object-oriented programming in JavaScript is a bit different.
You can create an object literal using a basic hash:
1
|
|
If you only need to ever use the object once, this technique is fine. But if you want to create multiple instances of it, you should use constructor functions. It is important to understand that all functions are objects in JavaScript. They all encapsulate a bit of reusable code.
In most languages, including Ruby, these functions are called classes, but in JavaScript you have constructor functions.
1 2 3 4 5 |
|
Now Amber
is an object created from the Person
object. The biggest advantage to using a constructor function over the basic hash above is that you can now reuse the Person function over and over again. You can give the Person function properties and methods, and those will be copied over to every instance of that object.
The constructor function can now have properties:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
If you have a group of methods that you want every instance of the constructor function to inherit, you can also encapsulate those methods in a prototype.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
When you add functions to a prototype, they are only created once. And then everytime an instance calls one of those methods, the instance refers to the one created in the prototype.
If you add functions to the constructor, they are duplicated every time you create a new instance of the constructor when is less efficient and consumes more memory.
However, one plus to creating methods inside the constructor function is that those functions have access to private data (i.e. they are privileged), whereas functions in prototypes are not.
Call vs Apply
If you would like to scope a function to an object, you can use the methods call
and apply
. For example, if you take the changeName
function outside of the prototype in the sample above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
apply
is very similar to call
, except you pass it arguments as an array and it can take an unknown amount of arguments.
1
|
|
There are many intricacies I have not discussed here, but I hope this post gives you a taste of JavaScript and some of its basic concepts and quirks.