Disclaimer: this is pretty stream-of-consciousness and was written pretty quickly. I'll clarify it over time, as I get feedback on parts that are confusing.
If you're TOTALLY new to Javascript, use my article as a companion to Codecademy's Javascript Introduction
I taught myself Javascript. By that I mean, I muddled through it for a few years until I realized that I could probably make myself more employable if actually figured how to do more complicated things.
Since I never understood the foundations of JS, I always found myself frustrated because my code wouldn't work as I expected. Mainly, I was used to jQuery API, and didn't quite grasp that the language was more complicated than $('div').something().
Luckily I had some pretty great coworkers who taught me more and more, and eventually everything made sense. I learned about closures, prototypes, loops, and now feel pretty comfortable in the language.
Had I started off on the right foundations, I could have been much better, much faster. So, here's a run down on everything I wish I knew first.
##Primitives, objects and variables: Javascript is a language that allows you to build a program in pieces, known as objects, by writing the manners in which objects interact with one another.
Javascript has a bunch of basic primitives:
string- a sequence of charactersnumber- a numerical valueboolean- true or falsenull- a non-existent valueundefined- a reference to a lack of a valuesymbols- For the sake of simplicity, let's not bother with symbols for now
And a few other objects:
array- a collection of other objectsfunction- an object that can be 'run'
We can declare an object in any manner:
1+1 // returns 2
'abc' // 'abc'
We tend to store a reference to an object in a variable, so that we can easily use the object at will:
var str = 'abc';
str; // 'abc'
var num = 1 + 1;
num; // 2
A collection is a grouping of a bunch of objects. This can be done in two ways:
- Object literal:
var collection = {
a: 1,
b: '2',
c: function() {
return 3;
}
}
- Array:
var array = [1, '2', function() {return 3}]
The main difference between the two structures is how they are indexed. In the case of an object literal, each value has it's own key that the programmer must declare. In an array, these are numerically keyed (referred to as the index), starting from an index of 0.
So in the above 2 examples, if I wanted to isolate the object property that has a value of 1, I could use square brackets, which let me declare which value I want to isolate.
collection['a']; // 1
array[0]; //1
The other unique thing about an object literal, is that it's a nested data structure, meaning, it's an object that holds other objects. This means I can also isolate a value like so: collection.a // 1. This basically means, within the collection object, I want to isolate the value of a.
###Functions As I mentioned above, a function is a runnable object. This means that you can define a function to take inputs, and return an output:
function add(firstNumber, secondNumber) {
return firstNumber + secondNumber;
}
add(1,2); // 3
A function doesn't have to explicitly return anything, either. In that case, it would inherently return undefined.
function printString(str) {
console.log(str);
}
function printHello() {
printString('hello');
}
function printByeTwice() {
printString('bye');
printString('bye');
}
printHello();
// hello
printByeTwice();
// bye
// bye
// undefined
The (); or ('hello'); part is how I call a function. If above I was just to use printHello;, it would just show me the definition of the function. I need to call it (); for it to run.
The other interesting thing about functions in javascript is that they are objects. This means that you can assign a function to a variable, or store them within a collection:
var obj = {
funcA: function a() {
console.log('This is obj.a')
}
};
obj.funcA() // This is obj.a
funcA() // undefined
Since funcA is a key within obj, I need to do the fully nested version to call the function.
Above I just introduced the concept of scope. Scope means that objects can exist in specific contexts, and not in others. In the example above, I used the object obj to establish a scope, and as funcA was a property of obj, it can be considered to be scoped to obj.
Proper scoping is a very useful thing, because it lets us organize our program nicely by keeping our objects away from one another. Here's a good example why this is useful:
var person1 = {
name: 'Rohan'
};
var person2 = {
name: 'Elon'
};
In this case, I can have two objects with the same key, but each holds a different value: person1.name; // Rohan and person2.name; // Elon.
Here's another example of scope, but this time while using a function:
function names() {
var name = 'Rohan';
}
Since this function does not have an explicit return, I cannot access the variable name from outside of it:
names(); // undefined
name // Uncaught ReferenceError: name is not defined
names().name // Some other error
This is a really useful concept, and we refer to the inner variables as private.
A closure is a foundational concept in Javascript that lets a program use values that are inside of a scope, from outside. This allows us to protect inner values:
function dialog() {
var greeting = 'Hi ';
return {
greet: function(name) {
return greeting + name;
},
newGreeting: function(newGreeting) {
greeting = newGreeting;
}
}
}
dialog().greeting;
// Undefined
dialog().greet('Rohan');
// Hi Rohan
var ourGreetings = dialog();
ourGreetings.greet('Rohan')
// Hi Rohan
ourGreetings.newGreeting('Bye ');
ourGreetings.greet('Rohan)'
// Bye Rohan
var ourSecondGreeting = dialog();
ourSecondGreeting.greet('Rohan');
// Hi Rohan
In the function dialog, the variable greeting holds a reference to a string Hi , but we cannot directly access that string, so it cannot be modified directly. However, we can also see that the dialog function returns a new object literal, and so we can store that in a variable (in this case, ourGreetings).
That allows us to access the newGreeting and greet functions, and even lets us change the greeting.
Finally, if we were to create a second variable to hold another instance of dialog(), it would not be affected by the ourGreetings.newGreeting function because the protected variables live in a different scope.