Learning JavaScript the right way™, part 1

I’ve been thinking about writing this for a while and I’ve finally decided to bite the bullet. This is going to be very dense and terse, I’ll go deep into details whenever I feel necessary. This whole series is all about avoiding the bad parts of JavaScript and focusing on the good ones. There isn’t any lack of explanations online about how a for loop works, so I’m assuming that the reader already knows:

  • The structures of imperative programming (for, while, if, else, return, etc.)
  • The principles of Object Oriented Programming (class, instance, interface, method, etc.)
  • Simple data structures (arrays, lists, hashmaps)
  • Big-O notation on a basic level (O(1) vs O(n), etc)

The style recommendations (do’s and don’ts) are my own opinion of what makes JS code readable and maintainable.

Parts:

  1. Basic types
  2. Arrays
  3. Objects
  4. Functions and Scope
  5. Prototypes
  6. Good JS practices



Basic types

Let’s get the boring stuff out of the way first. The real fun starts in part 2.

Variables are declared using the var keyword. Without it keyword, they’re globals. The scoping rules are little bit different than most languages, more on that later. JS is a loosely typed programming language, which means that variables can be changed from any type to any other type.


var test = 123; //test is a Number
test = "abc"; //test is now a String

DON’T: change the type of a variable. It’s a major source of bugs in programs.

Numbers are IEEE-754, so technically JS only has floats. In practice, they’ll act like integers as long as they aren’t forced to become floats by adding decimals, for example. Binary operations (~, &, |, ^) delete the decimal part. Rounding errors start appearing past the 10 digits mark.

DO: avoid decimals whenever possible, rounding errors WILL bite you. 0.3 != 0.1+0.2      (!!!)

IFs will evaluate the supplied expression to decide wheter to execute the block or not. The expression is coerced into a boolean. Every variable has a boolean value. For example, an empty string is equivalent to false, but any other non-empty string is true. It’s difficult to remember all the rules, therefore:


var a = "abc";

//THIS:
if (a.length > 0){
    //do something
}

//IS BETTER THAN:
if (a){
    //do something
}

There exists two operators to compare variables: == and ===. They each have their NOT version: != and !==, respectively. == will do type coercion when the variables have different types. It’s extremely difficult to remember all the exceptions, so:

DON’T: EVER use == and !=. Use the strict comparison operator instead, ===. It will return false whenever types don’t match.

Strings are Unicode. They are immutable and passed by reference. Any string manipulation will return a new string. Performance-wise, sometimes it’s better to work on an array and convert it into a string at the end instead of doing millions of string manipulations. Attribution is by value:


var a = "abc";
var b = a;
a += "def";
//a contains "abcdef"
//b containes "abc"

They work like you’d expect in most other languages. There’s two ways to get a substring: substring(startPosition, endPosition) and substr(startPosition, length). The only difference is in the second parameter. Use substring because it matches the syntax of the array’s equivalent method: slice. A copy of the string is returned.

Regular Expressions (regex) are extremely important in JS. The JS regex engine is incredibly fast. There’s even a literal, but I recommend using the full syntax instead.


var regex1 = /^[0-9]{5}$/g; //Literal syntax
var regex2 = new RegExp("^[0-9{5}]$", "g"); //Object syntax

The “g” parameter is to make it match all occurences instead of stopping after the first one.

If you want to check if a string is correctly formatted using a regex, use the test function:


var r1 = new RegExp("^[abc]{2,3}$");
r1.test("a"); //Returns false
r1.test("ba"); //Returns true
r1.test("bbb"); //Returns true
r1.test("abaa"); //Returns false

Replacing all occurences of a substring or a pattern inside of a string is done with a regex that contains the “g” parameter.


var a = "abcdef abcdef";
var r1 = new RegExp("a");
var r2 = new RegExp("a", "g");
a.replace("a", "A"); //Returns "Abcdef abcdef"
a.replace(r1, "A"); //Returns "Abcdef abcdef"
a.replace(r2, "A"); //Returns "Abcdef Abcdef"

Advanced string replacements can be achieved by passing a lambda (more on that later) to the replace function.


var a = "abcdef abcdef abcdef abcdef";
var r1 = new RegExp("a", "g");
var count = 0;
a = a.replace(r1, function(occurence){
    count++;
    if (count % 2 === 0){
        return "Z";
    }else{
        return "Y";
    }
});
//a now contains "Ybcdef Zbcdef Ybcdef Zbcdef".

Alright, let’s explain it a bit more. Every time the regex r1 finds a match in the string, the anonymous function (a lambda) is executed with the match passed as parameter (‘occurence’, in this case). The lambda can contain any amount of logic, so it can be used for some very complex replacements. The value returned by the lambda is what will be used as the replacement.

The Date object is very simple to use.


var currentTime = new Date();
console.log(currentTime.getTime()); //UNIX Timestamp

var aDate = new Date(1988, 5, 22, 15, 20, 20); //1988-06-22 at 3:20:20 PM

The Math global object contains a lot of useful mathematical functions.

Alright, that was a lot of information at once. Feel free to post a comment below if something isn’t clear.

Click here for part 2

3 thoughts on “Learning JavaScript the right way™, part 1

  1. Excellent start. As an experienced developer I often wish for a “developer’s intro” to new languages to get me up to speed without the marketing-speak and fluff. If I had to wish for such a JS intro then it would look exactly like this. Bravo & keep it up.

  2. Pingback: Learning JavaScript the right way™, part 2 | Simon Grondin

Leave a Reply