Primitive types

  • string
  • number
  • bigInt
  • boolean
  • undefined
  • null
  • symbol

Numbers

In JS, numbers are always 64-bit Floating Point!! Therefor precision exist to avoid overflow:

  • Integer precision: int are accurate within the scope (Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER)
  • Floating-point imprecision: Because numbers are binary floats, decimals like 0.1 cannot be represented accurately. So float point arithmetic is not always precise.
    1
    console.log(0.1 + 0.2 === 0.3)//false
    So how to fix this?
  • One way to fix integer precision is using bigInt:

    To create bigInt we simply add n after the number, or we use explicit conversion:

    1
    2
    3
    let n = BigInt(11111); 
    //to avoid precision, make sure the number in the parenthsis is within the safe range
    let m = 11111n;
  • To fix float point imprecision, we can use integer arithmetic and scale down:
    1
    2
    let n = (1 + 2)/10;
    console.log(n === 0.3); //true
  • However, when precision really matters, we usually use libraries for large/decimal numbers, especially in finance or science backgrounds:
    • decimals.js
    • bigNumbers.js
    • big.js

NAN and Infinity

NaN is a JavaScript reserved word indicating that a number is not a legal number.
like 100/"a" === NAN

Infinity/-Infinity is the value JavaScript will return if you calculate a number outside the largest possible number.
like 1/0 or 1/Infinity


String

Numbers and String

  1. When we use + between a numeric string and a number, or two numeric strings, the result will be concatenation.
1
2
console.log(10 + 20 + "30");
// The result is not 102030, but 3030.
  1. Js will try to convert strings to numbers in all numeric operations, other than +.
1
2
console.log("1" + "3" / 3);
// The result is not 1, but 11, as it is actually "1" + 1

Embedding into a string

In python to do this is easy:

1
2
3
4
5
6
name = "Ian"
print(f"my name is {name}")
print("my name is {}".format(name))
print("my name is %s" % (name))

## all the outputs are the string: my name is Ian

So it shouldn’t be difficult in js as well, we simply use template literals or string concatenation:

1
2
3
const name = "Ian"
console.log(`my name is ${name}`+ `and my age is ${10 + 11}` )
console.log("my name is" + name)

Tip: For declaring a string in js, we can use ``(backticks), “” ‘’(single or double quotes). But when to use them is a problem. Here is the rules.

We use ``(backticks) when:

  • We want to use template literals, use internal function calls or calculations.
  • We want to declare a string with multiple lines
    1
    2
    3
    const multiLine = `first line
    second line
    third line`
    And we use quotes when:
  • We just want simple, static string
  • We need consistency in JSON(JSON requires double quotes "")

However, the best practice is to use double quotes unless we need special features.


String as Object

Although string is a primitive object, when using in-built properties, js will wrap the sting in a String object.
Here are some of the thing we can do with string.

  • Length of a string: string.length to get the length of the string
  • Indexing: string[index] to get a specific character
  • Check substring: They all returns true or false
    • string.includes(substring)
    • string.startsWtih(substring)
    • string.endsWith(substring)
  • Slicing: string.slice(index1, index2)
  • Changing case: string.toUpperCase(), string.toLowerCase()
  • String Object Methods

Arrays

There are some characteristics that a js array have:

  • Dynamic size: A js array have no fixed size, the resizing is done automatically.
  • Ordered and Zero indexed: The elements in the array are ordered according to their index, which starts at 1. Unlike a hashmap in Java, you always know which element is at the specific index.
  • Heterogeneous: Unlike in Java, when we initialize an array or arraylist, we must define the datatype it stores. In JS, the array can store different datatypes(numbers, strings, objects and other arrays).
  • Arrays are special objects: In JS, arrays are seen as special objects, so when we use typeof() on an array, the result is object. We can use Array.isArray() to determine if the variable is an array.

Syntax: const array = ["item1", "item2", "item3"];

Important tips: We usually use const to declare an array, but const doesn’t mean the elements in the array cannot be changed, but the reference to the array cannot be changed!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const a; //Syntax error, must initialize the array when using const
const b = [1, 2, 3];
const b = [4, 5, 6]; //Syntax error, reassigning a const array is not allowed
b[0] = 4; //Changing elements are allowed
b.push(5); //adding elements are allowed
b.pop()// deleting element is allowed
***
## Declaring a variable

There are three keywords to declare a variable in js, `let`, `const`, and `var`.

* Only variables declared with `var` are **hoisted** (safe to log it before declaration):
```javascript
console.log(x);
var x = 10;
console.log(x);
// The results in console would be:
// undefined(not error!)
// 10
console.log(y);
let y = 100;
console.log(y); // not shown!
// if you use let or const to do this, the first console.log will give an error message and stop the execution:
// Uncaught ReferenceError: Cannot access 'rr' before initialization
  • Variables declared with var always have Global Scope:
    1
    2
    3
    4
    5
    6
    7
    {
    var x = 100;
    console.log(x); //This call is within the block scope and should give 100
    }
    console.log(x); //This call is outside of the block, it should give 100
    // since x is declared with var, hence x has global scope
    // and can be called outside of the block
  • Variables declared with let and const have Block Scope:
    1
    2
    3
    4
    {
    let x = 100;
    }
    console.log(x);// Gives and error: Uncaught ReferenceError: x is not defined
  • Variables declared with var can be redeclared:
    1
    2
    3
    var x = 100;
    var x = 20;
    // since x has global scope, redeclaring it would reassign its value
  • Variable declared with let or const can’t be redeclared:
    1
    2
    3
    let x = 100;
    let x = 10;
    //Gives and error: Uncaught SyntaxError: Identifier 'x' has already been declared
  • The variable must be assigned a value when using const to declare it, and changing its value is not allowed.
    1
    2
    3
    4
    const x;
    const y = 100;
    y -= 1;
    // Not allowed!!!

Objects and JSON

JS objects are very much like dictionaries in python, it is fundamentally a collection of key-value pairs.

Tip: comparing two objects (with == or ===) always returns false!

Syntax:

1
2
3
4
5
let obj = {
firstProperty: "I'm a string",
secondProperty: 99,
thirdProperty: false,
}

So what can we put in a JS object as value?

  1. primitive types
  2. arrays
  3. objects
  4. functions
  5. other object references

    To create a js object, the key is {}. You can create an empty object and add properties later.

    1
    2
    let obj = {};
    obj.name = "object"

Access object properties

There are two ways to access the properties of an object:

  • let value = objectName.propertyName;
    
    1
    2
    * ```javascript
    let value = objectName["propertyName"];

JSON

JSON is usually used as text messages between systems, and be read/written by many languages(python, C++, java…), It is very similar to a js object, but there are certain rules on the format:

  • Keys must be in ""
  • Values can only be: string, number, boolean, null, array, or another JSON object.
  • No comments, no functions and no undefined

We can parse JSON into a js object and stringify js object into JSON:

1
2
3
4
5
let obj = {
name: "Ian",
university: "Monash"
};
let objJson = JSON.stringify(obj);

object => JSON: JSON.stringify(obj)

1
2
let objstr = {"name": "Ian", "university": "Monash"};
let obj = JSON.parse(objstr)

JSON => object: JSON.parse(objstr)

Object Constructors, new and this

If you have learned Java or other languages that supports OOP(Object-Oriented Programming), you may be familiarized with the concept of constructor.

In general, constructors are special methods(functions) we use to create new objects, they serve as object prototypes.

1
2
3
4
5
6
7
function Men(name, age){
this.name = name;
this.age = age;
this.gender = "male";
}
const ian = new Men("Ian", 20)
console.log(ian) //result is an object

In this context, new keyword creates a new object, and this points to the newly created object. It is just like adding properties to an object, we simply use obj.propertyName = value syntax.

Tip: The prototype constructor(mentioned above) does not support arrow function syntax, as in ES6, arrow functions are not thisbinding. Using prototype constructors are usually not recommended after ES6, as we have specific constructor keyword in class to do that.

Difference between objects and arrays

  • objects use {} while arrays use [] when initializing
  • objects use named index while arrays support numbered index

    JS does not support associative arrays like hashmaps. So when use named indexes, js will redefine the array into object:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    const a = [1, 2, 3];
    console.log(a.length); // gives 3
    a["name"] = "Ian";
    a["age"] = 20;
    a["gender"] = "male";
    console.log(a.length); //still 3
    console.log(a[0]); // gives 1
    console.log(a[3]); //gives undefined
    console.log(a.name); //gives Ian

    Arrays are special objects, when it is redefined it stops behaving like an array.

    Which means you can no longer use number index or .length on it.


Type conversion

typeof, instanceof

To check the datatypes of a variable is easy, we usually use typeof, instanceof operator.

Primitive types

1
2
3
4
5
6
7
8
9
10
11
12
typeof 42;        // "number"
typeof "hi"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof Symbol(); // "symbol"
typeof 10n; // "bigint"

typeof null; // "object" (quirk!)
null === null; // true ✅ best way to check

typeof NaN; // "number" (yes, NaN is still a number!)
Number.isNaN(NaN); // true ✅ best way to check

Objects and Array

1
2
3
4
5
6
7
8
typeof {};             // "object"
typeof []; // "object" (so not helpful)

Array.isArray([]); // true ✅ best way to check for arrays

({}) instanceof Object; // true
[] instanceof Array; // true
[] instanceof Object; // true

Functions and Classes

1
2
3
4
5
6
typeof function(){};   // "function"
typeof class MyClass{}; // "function"

function MyClass(){}
new MyClass() instanceof MyClass; // true

Type conversion

  • Numbers
    • Number()
    • parseFloat()
    • parseInt()
    • Unary +:
      1
      2
      3
      4
      5
      6
      7
      8
      let x = "1";
      let y = + x; //y is a number

      let a = "string";
      let b = + a; // b is still a number but its value is NaN

      // "= +" is the unary +, it will convert the result into number
      //if the result can't be converted into a number, it will just return NaN
  • String
    • String()
    • toString()

Functions

  • Syntax:

    1
    2
    3
    4
    function functionName(p1, p2, p3) {
    //function body
    console.log("body");
    }
  • Invoking a function
    functionName(p1, p2, p3) (a simple () would do)

  • Return:

    • return ends the execution(lines after return will be omitted).
    • By default, the function will return undefined if the return is missing.
    • You can ONLY omit the return and the bracket{} if the function is a single statement:
    1
    2
    3
    4
    5
    6
    7
    let adding = (a,b) => a + b;

    let complexFunc = (p1, p2, p3) => {
    console.log("body");
    return("execution ends");
    }
    //The best practice is to keep the return and brackets at any case.

Anonymous Function

Usually when a function is passed in as a parameter(especially when we use event listener), we write them as anonymous function:

1
2
3
4
5
6
7
(function(){
alert("hello");
});

textBox.addEventListener("keydown", function (event) {
console.log(`You pressed "${event.key}".`);
});

However, after ES6, we now usually use arrow function instead.


Arrow functions

All arrow functions are anonymous. However, we can still reuse them just like an ordinary function when we assign a variable to them:

1
2
3
4
5
6
7
let arrowFunc = (a, b) => {
a * b;
}

textBox.addEventListener("keydown", (event) => {
console.log(`You pressed "${event.key}".`);
});

Events

Events are interactions of hardware or software with the website, and are used as a signal for certain action to be taken. Most commonly used events could be mouse click or keys pressed.

There are many events that can be triggered. See the list of events.


Event Listeners

DOM objects can fire events when they have addEventListener() method, the syntax is:

1
element.addEventListener(eventType, handler, options);

Where:

  • element → the DOM element you want to listen on.
  • eventType → a string like “click”, “keydown”, “mouseover”, etc.
  • handler → the function to run when the event happens. (this is where arrow and anonymous function comes in)
  • options → (optional) object or boolean for extra settings like { once: true }.

    Tip: you can add multiple event listeners to one element, they will be executed in the order you add them.

For large, complex programs, it is more efficient to remove the event listener if not needed. To do so, we use removeEventListener() method:

1
2
element.remomveEventListener(eventType, handler);
// must pass in the EXACT reference as the addEventListener.

Event Handler Properties

Other way to trigger event is using event handler properties:

1
2
3
4
5
element.onclick = () => {};

function handler() {};
element.onmouseenter = handler;
// basically it is on + event

Key difference: you can only attack one event to the element, unlike event listeners.

You can also use inline event handlers:

1
<button onclick="bgChange()">Press me</button>
1
function byChange() {};

However, this is NOT RECOMMENDED! Referencing JS function in html file makes the program harder to read. Do not use this!


Event Objects

Sometimes we want to know something about the event itself, like for keydown event we want to know which key the user pressed. This is where the event object comes in.

Usually in the event handler, we pass in a parameter named e evt, this is the event object. The event object is passed automatically to the event handler, and provides information about the event itself.

1
2
3
4
5
6
element.addEventListener(
click, (e) => {
console.log(e);
// doing so we can get the event object of this click event
}
);

Event object have some common properties, like:

  • event.type: get the type of the event like click, keydown
  • event.target: get the element that triggered the event. (the element)
  • event.currentTarget: get the element the event is currently attached to.