bugfix: Node REPL to follow along: https://repljs.com

Objects

Objects are used to store keyed collections of Data. There are two ways to declare an object:

let user = new Object(); // object constructor syntax
let user = {}; // object literal syntax

We can assign properties like this:

/*Object Literal Syntax*/
let user = {        // an object
	name: "Vassil", // by key "name" store value "Vassil"
	age:30          // by key "age" store value 30
};

and access them using one of two notations:

alert(user.name); // "Vassil"
alert(user.age); // 30
 
//We can also use bracket syntax
alert(user[name]); // "Vassil"

We can add or remove properties after the object declaration

user.isAdmin = true; // object now has 3 properties
delete user.age // object now has name and isAdmin properties

We can use object constructor syntax:

// Define a constructor function 
function User(name, age){
	this.name = name; 
	this.age = age; 
}
 
let user1 = new User('James', 64);
let user2 = new User('Jane', 34);

object constructor syntax allows us to add some methods

function User(name, age){
	this.name = name; 
	this.age = age; 
}
 
// Add a method to the prototype
User.prototype.greet = function() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};
 
let user1 = new User('James', 64);
let user2 = new User('Jane', 34);
 
user1.greet() // Hello my name is James and I am 64 years old.

Object methods, “this”

let user = {        // an object
	name: "Vassil", // by key "name" store value "Vassil"
	age:30          // by key "age" store value 30
 
	sayHi(){
		// "this" is the "current object"
		alert(this.name)
	}
};
 
user.sayHi(); // Vassil
let user = {        // an object
	name: "Vassil", // by key "name" store value "Vassil"
	age:30          // by key "age" store value 30
 
	sayHi(){
		// "this" is the "current object"
		alert(user.name)
	}
};
 
//If we decide to copy `user` to another variable, e.g. `admin = user` and overwrite `user` with something else, then it will access the wrong object. 
let admin = user; 
user = null; // overwrite user to make it obvious
admin.sayHi(); // TypeError: Cannot read property 'name' of null

Classes

class User {
    constructor(name, lastname) {
        this.name = name; // Internal property
        this.lastname = lastname
    }
    // Getter for name
    get name() {
        return this.name;
    }
    // Setter for name
    set name(value) {
        if (typeof value === 'string' && value.length > 0) {
            this._name = value;
        } else {
            console.error('Invalid name');
        }
    }
    //String method -> returns a print of this object so that you can see it
}
 
let user = new User('Alice');
console.log(user.name); // Output: Alice
 
user.name = 'Bob';
console.log(user.name); // Output: Bob
 
user.name = ''; // Invalid name
console.log(user.name); // Output: Bob
 
// In JavaScript, the use of an underscore (`_`) before a property name is a common convention to indicate that the property is intended to be private or for internal use only. This is a naming convention and not an enforced privacy mechanism by the language itself.
//

Linked List

// Define a class Node to represent a node in the linked list
// class Node {
//     constructor(val) {
//         this.val = val; // Assign val to the node
//         this.next = null; // Initialize the next pointer to null
//     }
// }
 
// Define a class LinkedList to represent the singly linked list
class LinkedList {
    constructor() {
        this.head = null; // Initialize the head of the list to null
    }
 
    // Function to insert a new node at the beginning of the list
    insert(val) {
        let newNode = new Node(val); // Create a new node with the given val
        newNode.next = this.head; // Point the new node's next to the current head
        this.head = newNode; // Update the head of the list to the new node
    }
 
    // Function to insert a new node after a given node (prev_node)
    insertAfter(prev_node, val) {
        if (prev_node === null) {
            console.log("The given previous node must be in LinkedList.");
            return;
        }
        let newNode = new Node(val); // Create a new node with the given val
        newNode.next = prev_node.next; // Update the new node's next to prev_node's next
        prev_node.next = newNode; // Update prev_node's next to the new node
    }
 
    // Function to delete the first occurrence of a key in the list
    delete(key) {
        let temp = this.head, prev = null;
        // If the head node holds the key to be deleted
        if (temp !== null && temp.val === key) {
            this.head = temp.next; // Change the head of the list
            return;
        }
        // Search for the key to be deleted
        while (temp !== null && temp.val !== key) {
            prev = temp; // Keep track of the previous node
            temp = temp.next; // Move to the next node
        }
        // If key was not present in the list
        if (temp === null) return;
        // Unlink the node from the list
        prev.next = temp.next;
    }
 
    // Function to search for a key in the list. Returns true if found, otherwise false
    search(key) {
        let current = this.head; // Initialize current to head
        while (current !== null) {
            if (current.val === key) // If the key is found, return true
                return true;
            current = current.next; // Move to the next node
        }
        return false; // Key not found, return false
    }
}
 
// Create an instance of LinkedList
let list = new LinkedList();
 
// Insert nodes into the list
list.insert(1);
list.insert(2);
list.insert(3);
 
// Search for a key in the list and log the result
console.log("Search 2:", list.search(2)); // true
 
// Delete a node with a specific key from the list
list.delete(2);
 
// Search again for the key in the list and log the result
console.log("Search 2:", list.search(2)); // false