A JavaScript Primer
Node.js is just JavaScript on the server. The language syntax and tools you are used to with coding JavaScript on the browser will work verbatim on the server. Node.js has additional tools that are only available on the server, but the language and syntax again are the same. I'm assuming you have a general understanding of the basic JavaScript syntax, but I will introduce JavaScript to you with a very brief primer on the language just in case.
In general, JavaScript is a fairly simple language when it comes to syntax, and you only need to know a few important elements.
Declaring variables
The most basic thing you can do in pretty much any programming language is declare a variable. Unlike most other languages, JavaScript is a dynamically typed language, which means when you declare a variable, its value can be of any type and can change during the course of its lifetime. However, in contrast, a strongly typed language dictates that a variable defined as a type of string must always be a string and must always have a value of a string.
To declare a variable in JavaScript, simply use the var
keyword before your variable name:
var myVariable; // declaring a variable with no value var myOtherVariable = 'Hello!'; var myFirstName = "Jason"; var myLastName = "Krol"; //note that strings can use ' or " interchangeably var myFullName = myFirstName + ' ' + myLastName; // => Jason Krol // addition with strings will concatenate var someNumber = 1, anotherNumber = 25; /* note that you can declare multiple variables separated with commas */ var total = someNumber + anotherNumber; // => 26 // addition with numbers will perform Math whatIfIForgetVar = "uh oh";
As you can see in the preceding code snippet, there are a number of options available when declaring variables. JavaScript is pretty forgiving for the most part, as you can use single and double quotes interchangeably (although not recommended) as long as they match. You can declare every variable using a var
keyword per line, or you can separate a list of multiple variables with a comma using a single var
. While not mandatory, it's expected that every line of code in JavaScript ends with a semicolon (;
). Without a semicolon, the code will still work, but it may produce unwanted results.
A quick gotcha is in there with the whatIfIForgetVar
variable. Without the var
keyword, the variable is still defined, however its scope is set globally. This is bad as it can clash with another globally scoped variable of the same name! JavaScript follows function-level scoping, which is somewhat different from other languages.
Always define your variables using the var
keyword, and pay attention to the function that variables are being defined in. With the preceding sample code, we actually never defined a function and just started writing code. This means that without a base function to execute in, the code itself will actually belong to the global window object. Generally, it is considered a bad practice to ever write code directly against a global scope like this.
Declaring functions
Using the same var
keyword, you can define functions in the same way as variables. The only difference is that you use the function signature to define your function:
function sayHello() { console.log('Hello!'); } // or var sayHello = function() { console.log('Hello!'); }
Both methods are almost identical in the preceding sample code. The first method is the most common way to define a function; however, you can use the var
keyword if you want to treat your function like a variable (that is, pass it as a parameter to another function and so on).
You will then call your named function by simply using the function (or variable) name, followed by open and close parentheses:
sayHello();
This function will simply log the Hello!
string. Functions can accept any number of parameters and can return any value (or not). Functions can be called from within other functions. Functions can also be passed as parameters to other functions:
var doWork = function(val) { var half = val / 2; // do more work... } var someValue = 20; doWork(someValue); var fullName = function(firstName, lastName) { return firstName + ' ' + lastName; } console.log(fullName('Jason', 'Krol')); // => Jason Krol var getFirstName = function() { return 'Jason'; } var getLastName = function() { return 'Krol'; } // accepting functions as parameters to be called later: function findFullName(firstName, lastName) { var fname = firstName(); var lname = lastName(); console.log(fname + ' ' + lname); } findFullName(getFirstName, getLastName); // => Jason Krol
Declaring objects
Creating an empty object in JavaScript is one of the easiest things you can do:
var myObject = {}; // that's it!
By simply using the open and close braces, { }
, you have created a brand new object. Using this new object, you can assign any properties or methods you want:
var person = {}; person.firstName = 'Jason'; // properties person.lastName = 'Krol'; person.fullName = function() { // methods return this.firstName + ' ' + this.lastName; } person.colors = ['red', 'blue', 'green']; // array property
You can see in the preceding code that we defined a basic object called person
and assigned it some properties and a function. It's important to note the use of the this
keyword in the fullName
function. The this
keyword refers to the object that the function is assigned to.
// define properties during declaration var book = { title: 'Web Development with MongoDB and NodeJS', author: 'Jason Krol', publisher: 'Packt Publishing' }; console.log(book.title); // => Web Development with MongoDB and NodeJS book.pageCount = 150; // add new properties
Here, we instantiated a new object called book
but defined some properties at the same time. We added another property a little later.
Objects can be nested with infinite possibilities, as shown in the following code:
var jason = { name: 'Jason Krol' }; var book = { title: 'Web Development with MongoDB and NodeJS', publisher: 'Packt Publishing', author: jason }; console.log(book.author.name); // => Jason Krol
Functions are objects
In JavaScript, functions are considered first-class citizens. What this means is that a function by itself is an object, so it can be treated as such and extended with properties and additional functions. Here, we will take a standard function (in this case, myFunction
). We will assign this function a property (timesRun
), just like we would for any other object during its execution, and show how you can refer to that property later:
var myFunction = function() { if(this.timesRun) this.timesRun += 1; else this.timesRun = 1; // do some actual work console.log(this.timesRun); } myFunction(); // => 1; myFunction(); // => 2; myFunction(); // => 3; console.log(myFunction.timesRun); // => undefined
Note the last line where we tried to log the timesRun
property of myFunction
but received undefined
in the output. This is because the property is privately scoped to the function so it is only visible from within the function (that is, only visible to the code executing inside the function).
Anonymous functions and callbacks
Often, you will need to use a temporary function that you don't necessarily want to declare ahead of time. In this type of a scenario, you can use an anonymous function, which is simply a function that is declared at the time you need it (this function isn't assigned to a variable, so it has no way of being referenced to later). The most common use of anonymous functions is when they are defined as a parameter to another function (most notably when used as a callback).
One of the most common places to use an anonymous function (which also acts as a callback even if you didn't realize it) is with setTimeout
or setInterval
. These are two standard JavaScript functions that will execute code after a specified delay (in milliseconds) or repeat the execution of code every specified delay. Here is an example of one of them, setTimeout,
using an anonymous inline function:
console.log('Hello...'); setTimeout(function() { console.log('World!'); }, 5000); // => Hello... // (5000 milliseconds i.e. 5 second delay) // => World!
You can see that the anonymous function was passed as the first parameter to setTimeout
because setTimeout
expects a function. You can, if you so desire, declare the function ahead of time as a variable and pass that to setTimeout
instead of the inline anonymous function:
var sayWorld = function() { console.log('World!'); } setTimeout(sayWorld, 5000); // (5 second delay) // => World!
The anonymous function just acts as a clean inline disposable function.
Callbacks are important because one of the most powerful (and confusing) features of JavaScript is that it's asynchronous. This means that every line executes sequentially, but it doesn't wait around for code that might be taking longer than it should (even if by design). Consider the following idea: you want to call two functions sequentially; however, the first function may take a while (maybe it makes a network call, or performs a long loop). What happens if the second function is executed before the first is finished? The answer lies in the following code:
var someValue; var myFunction = function(){ // change someValue eafter 5 seconds setTimeout(function() { someValue = someValue / 2; }, 5000); } someValue = 100; myFunction(); console.log(someValue); // => 100
When your code executes myFunction
, it will actually wait 5 seconds before it divides the someValue
variable in half. However, console.log
on the following line of the function call will execute immediately after. This is contrary to our desired effect, which is to have the console.log
show the value of someValue
after the work on it has been performed via myFunction
. The solution to this is to use a callback. An anonymous function will be passed to myFunction
and will only be executed once myFunction
has actually finished execution:
var someValue; var myFunction = function(callback){ // change someValue after 5 seconds setTimeout(function() { someValue = someValue / 2; callback(someValue); }, 5000); } someValue = 100; myFunction(function() { console.log(someValue); }); // => 50
Arrays
Arrays work the same way in JavaScript as they do in pretty much any other language. They are zero indexed, and you can declare a variable as an empty array or prepopulated array. You can manipulate the items in an array, and arrays are not fixed in length:
var favFoods = ['pizza', 'cheeseburgers', 'french fries']; var stuff = []; // empty array var moreStuff = new Array(); // empty array var firstFood = favFoods[0]; // => pizza // array functions: favFoods.push('salad'); // add new item // => ['pizza', 'cheeseburgers', 'french fries', 'salad'] favFoods.pop(); // remove the last item // => ['pizza', 'cheeseburgers', 'french fries'] var first = favFoods.shift(); // remove the first item // => first = 'pizza'; // => favFoods = ['cheeseburgers', 'french fries']
Conditions and comparison operators
The most common condition statement you will write in JavaScript is the if
statement. All block-level code that follows an if
statement should be wrapped in {
and }
. This rule extends to pretty much all code structures in JavaScript. In an if
statement, any value greater or less than zero, not null, and not undefined equates to "truthy". 0, null, undefined, or an empty string equates to "falsey".
There are a number of comparison operators available, and understanding the difference among these will matter when it comes to a random bug that you spend way too much time trying to figure out because you had ==
instead of ===
:
var x = 5; == equal to x == 5 true, x == '5' true, x == 8 false === exactly equal x === 5 true, x === '5' false != not equal to x != 6 true, x != '5' false !== not equal to exactly >, <, >=, <= greater than, less than, greater than or equal to, less than or equal to
The main difference to understand is that ==
and !=
are type indifferent. So, an integer of 5
is equal to a string of '5'
. However, ===
and !===
are type specific. So, a string of '5'
is not equal to an integer of 5
(when compared using ===
):
if(1 === 1) doWork(); var myVar = 1; if(myVar > 0) { myVar = myVar * 2; doWork(myVar); } else doWork(0); if (myVar === 0) { doWork(); } else if (myVar > 0 && myVar < 10) { // && is AND var val = doNothing(); if (val || myVar === 5) { // || is OR lastMinuteCleanup(); } } else { var errorcode = abort(); if (!errorcode) { // ! is NOT console.log('There was an error!'); } }
Flow
The basic control of flow within JavaScript is going to be handled by if
statements and any number of looping control flow statements available. A basic example of for
loop is as follows:
var myVar = 0; for(var i = 0; i < 100; i += 1) { myVar = i; console.log(myVar); } // => 1 2 3 4 5 6 7 8 ... 100
Additional loops are available in JavaScript as follows:
var x = 0; do { x += 1; console.log(x); } while (x < 100); // => 1 2 3 4 5 6 7 8 ... 100 while (x > 90) { x -= 1; console.log(x); } // => 99 98 97 96 95 94 93 92 91 90
JSON
JSON, or JavaScript Object Notation, is the standard syntax used when dealing with data in JavaScript as well as most other languages and web services. The basic premise of JSON is that it looks exactly like a standard JavaScript object with a few strict exceptions:
- JSON is pure text. There are no datatypes with properties; that is, date values are stored as strings and so on.
- All names and string values must be in double quotes.
- There can be no functions as properties.
Let's take a quick look at a pretty standard JSON object:
{ title: 'This is the title', description: 'Here is where the description would be', 'page-count': 150, authors: [ { name: 'John Smith' }, { name: 'Jane Doe' }, { name: 'Andrea Johnson' } ], id: '1234-567-89012345' }
If you are familiar at all with XML, JSON is somewhat similar, except it is much easier to read and make sense out of. As described best by the ECMA, JSON is a text format that facilitates structured data interchange between all programming languages.