DEV Community

Cover image for You Don't Know JS: Get Started: Chapter 2 (Surveying JS) Notes
Rajat Verma
Rajat Verma

Posted on • Edited on

You Don't Know JS: Get Started: Chapter 2 (Surveying JS) Notes

Chapter 2: Surveying JS

Best way to learn JS is to practice it!

Each File is a Program

  • Almost every Web Application has a bunch of JS files.
  • In JS, every single file is its own separate program. So, if somehow one file fails, it won't affect the execution of the other files.
  • The only way multiple JS files act as a single program is by sharing their state via the "global scope".
  • Since ES6, JS started supporting Modules format.

Values

  • Fundamental unit of information in a program is Value.
  • Values come in two forms in JS: Primitive and Objects.

Strings

  • Strings are ordered collection of characters.
console.log("Hello World");
Enter fullscreen mode Exit fullscreen mode
  • In this code, Hello World is the string.
  • Strings can be defined using both Single-Quotes or Double-Quotes. The choice of which to use is yours. Just make sure to choose one and use it consistently in your program.
  • We can also use the backtick-character to define a string. However, this choice is not merely stylistic; there’s a behavioral difference as well. For example:
console.log("My name is ${ firstName }.");
// My name is ${ firstName }.

console.log('My name is ${ firstName }.');
// My name is ${ firstName }.

console.log(`My name is ${ firstName }.`);
// My name is Rajat.
Enter fullscreen mode Exit fullscreen mode
  • In the above code snippet, we assumed that we have already declared a variable named firstName with the value Rajat.
  • The use of backtick declaration to place the value of a variable in a string is known as Interpolation.

Other primitive datatypes

  • Booleans and numbers are also used in a JS program.
while (false) {
  console.log(3.141592);
}
Enter fullscreen mode Exit fullscreen mode
  • The code inside of the while loop is never executed as the condition always remains false.
  • Math.PI should be used for getting the value of mathematical PI.
  • Bigint is a primitive type that is used to store large whole numbers (larger than (2^53) - 1).
  • In addition to strings, numbers, and booleans, two other primitive values in JS programs are null and undefined. While there are many differences between them, for most parts both serve the purpose of the emptiness of a value. However, it’s safest and best to use only undefined as the single empty value.
  • Another primitive data-type is Symbol. You won’t encounter direct usage of symbols very often in typical JS programs. They’re mostly used in low-level code such as in libraries and frameworks.

Arrays And Objects

  • Besides primitives, the other value type in JS is an object value.
  • Arrays are a special type of object that’s comprised of an ordered and numerically indexed list of data. For eg:
names = [ "One", "Two", "Three", "Four" ];
names.length;
// 4
names[0];
// One
names[1];
// Two
Enter fullscreen mode Exit fullscreen mode
  • JS arrays can hold any data type, either primitive or object. Even functions are values that can be held in arrays or objects.
  • Objects are more general: an unordered, keyed collection of any various values. For eg:
name = {
  first: "Kyle",
  last: "Simpson",
  age: 39,
  specialties: ["JS", "Table Tennis"],
};
console.log(`My name is ${name.first}.`);
Enter fullscreen mode Exit fullscreen mode
  • Here, name is an object with keys like first, last, age, and specialties.
  • We can also use the following syntax to access the value of an object:
name["first"]
Enter fullscreen mode Exit fullscreen mode

Value Type Determination

  • The typeof operator tells the built-in type of value (i.e, primitive or object).
typeof 42; // number
typeof "abc"; // string
typeof true; // boolean
typeof undefined; // undefined
typeof null; // object
typeof { a: 1 }; // object
typeof [1, 2, 3]; // object
typeof function hello() {}; // function
Enter fullscreen mode Exit fullscreen mode
  • Note that typeof returns the type of null, array as an object, and function as function.

Declaring and Using Variables

  • Variables are like containers for values. There are many types of variable declaration in JS, and each one of them has its own different meanings. For eg:
var name = "Kyle";
var age;
Enter fullscreen mode Exit fullscreen mode
  • The var keyword declares a variable to be used in the program, and optionally allows initial value assignment.
  • Similarly, the let keyword can be used to declare variables as:
let name = "Kyle";
let age;
Enter fullscreen mode Exit fullscreen mode
  • let allows more limited access to the variable than var. This is called block scoping as opposed to regular or function scope.
  • Another type of declaration is using the const keyword. A variable declared using this keyword is similar to let, with the addition that it must be given a value at the moment it’s declared, and cannot be re-assigned a different value later.
const myBirthday = true;
let age = 39;
if (myBirthday) {
  age = age + 1;
  // OK!
  myBirthday = false; // Error!
}
Enter fullscreen mode Exit fullscreen mode

Tip: If you stick to using const only with primitive values, you avoid any confusion of re-assignment (not allowed) vs. mutation (allowed)! That’s the safest and best way to use const .

Functions

  • In JS, the term function takes the broader meaning of a Procedure. A procedure is a collection of statements that can be invoked one or more times, maybe provided some inputs, and may give back one or more outputs. A function declaration in JS looks like this:
function greetHello(name) {
  const msg = `Hello ${name}`;
  return msg;
}
Enter fullscreen mode Exit fullscreen mode
  • This function is a statement and not an expression. The association between the identifier greetHello and the function value happens during the compile phase of the code before that code is executed.
  • A function expression can be defined as:
// let awesomeFunction = ..
// const awesomeFunction = ..
var awesomeFunction = function (coolThings) {
  // ..
  return amazingStuff;
};
Enter fullscreen mode Exit fullscreen mode
  • This function is an expression that is assigned to the variable awesomeFunction. Contrary to a function statement, a function expression is not associated with its identifier until that statement during runtime.
  • In JS, functions are a special type of object. They are treated as Values.
  • A function may or may not have a parameter.
  • Functions can also return values. You can only return a single value, but if you want to return multiple values, then you can wrap up them into a single object/array.
  • Since functions are values, they can be assigned as properties on objects:
var whatToSay = {
  greeting() {
    console.log("Hello!");
  },
  question() {
    console.log("What's your name?");
  },
  answer() {
    console.log("My name is Kyle.");
  },
};
whatToSay.greeting();
// Hello!
Enter fullscreen mode Exit fullscreen mode

Comparisions

  • == is generally referred to as the loose-equality operator.
  • === equality comparison is often described as, “checking both the value and the type”. For eg:
3 === 3.0 // true
null === null // true
3 === "3" // false
Enter fullscreen mode Exit fullscreen mode
  • === disallows any sort of type conversion (aka, “coercion”) in its comparison, where other JS comparisons do allow coercion.
  • The === operator is designed to lie in two cases of special values: NaN and -0. Consider:
NaN === NaN; // false
0 === -0; // true
Enter fullscreen mode Exit fullscreen mode
  • In the first case, it says that an occurrence of NaN is not equal to any other occurrences of NaN. In the case of -0, the === operator lies and says it’s equal to the regular 0 value.
  • So, for such comparisions involving NaN use the Number.isNaN(..) utility, and For -0 comparison, use the Object.is(..) utility.
  • The Object.is(..) utility can also be used for NaN comparisons. It is a really-really-strict comparison!
  • Object values comparision is even more complicated:
[ 1, 2, 3 ] === [ 1, 2, 3 ];  // false
{ a: 42 } === { a: 42 }       // false
(x => x * 2) === (x => x * 2) // false
Enter fullscreen mode Exit fullscreen mode
  • The === operator uses identity equality for object values.
  • In JS, all object values are held by reference, are assigned and passed by reference-copy, and are compared by reference (identity) equality.
var x = [ 1, 2, 3 ];
// assignment is by reference-copy, so
// y references the *same* array as x,
// not another copy of it.
var y = x;
y === x;            // true
y === [ 1, 2, 3 ];  // false
x === [ 1, 2, 3 ];  // false
Enter fullscreen mode Exit fullscreen mode
  • JS doesn’t provide structural equality comparison because it’s almost intractable to handle all the corner cases!

Coercive Comparisons

  • Coercion means a value of one type being converted to its respective representation in another type.
  • The == operator performs an equality comparison similarly to how the === performs it. In fact, both operators consider the type of values being compared. And if the comparison is between the same value type, both == and === do exactly the same thing, no difference whatsoever. If the value types being compared are different, the == differs from === in that it allows coercion before the comparison.
  • Instead of “loose equality,” the == operator should be described as “coercive equality”. Consider the following examples:
42 == "42";
1 == true;
Enter fullscreen mode Exit fullscreen mode
  • In both cases, the value types are different so coercion is applied and once they are of the same type then only the values are compared.
  • The relational comparison operators (>, <, >=, <=) also work like == operator. For eg:
var arr = ["1", "10", "100", "1000"];
for (let i = 0; i < arr.length && arr[i] < 500; i++) {
  // will run 3 times
}
Enter fullscreen mode Exit fullscreen mode
  • These relational operators typically use numeric comparisons, except in the case where both values being compared are already strings; in this case, they use the alphabetical (dictionary-like) comparison of the strings:
var x = "10";
var y = "9";
x < y;      // true, watch out!
Enter fullscreen mode Exit fullscreen mode

How We Organize in JS

  • Two of the most used patterns are classes and modules.

Classes

  • A class in a program is a definition of a type of custom data structure that includes both data and behaviors that operate on that data.
class Page {
  constructor(text) {
    this.text = text;
  }
  print() {
    console.log(this.text);
  }
}

class Notebook {
  constructor() {
    this.pages = [];
  }
  addPage(text) {
    var page = new Page(text);
    this.pages.push(page);
  }
  print() {
    for (let page of this.pages) {
      page.print();
    }
  }
}

var mathNotes = new Notebook();
mathNotes.addPage("Arithmetic: + - * / ...");
mathNotes.addPage("Trigonometry: sin cos tan ...");
mathNotes.print();

// Arithmetic: + - * / ...
// Trigonometry: sin cos tan ...
Enter fullscreen mode Exit fullscreen mode
  • In Page class, the data text is stored in property this.text and the behavior is print().
  • In Notebook class, the data pages is an array of Page instances and the behaviours are print() and addPage(..).

Class Inheritance

class Publication {
  constructor(title, author, pubDate) {
    this.title = title;
    this.author = author;
    this.pubDate = pubDate;
  }
  print() {
    console.log(`
Title: ${this.title}
By: ${this.author}
${this.pubDate}
`);
  }
}
Enter fullscreen mode Exit fullscreen mode
  • This Publication class defines a set of common behavior that any publication might need.
class Book extends Publication {
  constructor(bookDetails) {
    super(bookDetails.title, bookDetails.author, bookDetails.publishedOn);
    this.publisher = bookDetails.publisher;
    this.ISBN = bookDetails.ISBN;
  }
  print() {
    super.print();
    console.log(`
Publisher: ${this.publisher}
ISBN: ${this.ISBN}
`);
  }
}
Enter fullscreen mode Exit fullscreen mode
  • The Book class uses the extends clause to extend the general definition of Publication to include additional behavior. This behavior is called Inheritance.

Modules

  • The Modules pattern have the same goal i.e. to group data and behavior, but it has certain differences from classes. An example of classic-modules is:
function Publication(title, author, pubDate) {
  var publicAPI = {
    print() {
      console.log(`
Title: ${title}
By: ${author}
${pubDate}
`);
    },
  };
  return publicAPI;
}

function Book(bookDetails) {
  var pub = Publication(
    bookDetails.title,
    bookDetails.author,
    bookDetails.publishedOn
  );
  var publicAPI = {
    print() {
      pub.print();
      console.log(`
Publisher: ${bookDetails.publisher}
ISBN: ${bookDetails.ISBN}
`);
    },
  };
  return publicAPI;
}
Enter fullscreen mode Exit fullscreen mode
  • The class form stores methods and data on an object instance, which must be accessed with the this. prefix. With modules, the methods and data are accessed as identifier variables in scope, without any this. prefix.

ES Modules

  • ESMs are always file-based; one file, one module.
  • They have to be exported from one file to be used in another.

That's it for this chapter. I will be back with the notes of the next chapter.

Till then, Happy Coding!

If you enjoyed reading these notes or have any suggestions or doubts, then do let me know your views in the comments.
In case you want to connect with me, follow the links below:

LinkedIn | GitHub | Twitter

Top comments (4)

Collapse
 
rajat2502 profile image
Rajat Verma

These are the notes of Chapter 2 of YDKJS: Get Started. The notes of the Chapter are here: dev.to/rajat2502/you-don-t-know-js...

If you want to read the complete chapter, book, or series, please head over to their repository:
github.com/getify/You-Dont-Know-JS

Collapse
 
kushagrarora17 profile image
Kushagr Arora

Nice work!

Collapse
 
rajat2502 profile image
Rajat Verma

Thanks Kushagra 😊

Collapse
 
rajat2502 profile image
Rajat Verma