7. Array and Object (Dictionary)#

7.1. Array#

7.1.1. Declaration and Initialization#

  • Arrays in JavaScript can be declared and initialized using square brackets [].

    let numbers = [1, 2, 3, 4, 5];
    

7.1.2. Accessing Elements#

  • Elements in an array can be accessed using square bracket notation with the index.

    console.log(numbers[0]); // Output: 1
    

7.1.3. Length Property#

  • The length property returns the number of elements in an array.

    console.log(numbers.length); // Output: 5
    

7.1.4. Adding Elements#

  • New elements can be added to the end of an array using the push() method.

    numbers.push(6);
    console.log(numbers); // Output: [1, 2, 3, 4, 5, 6]
    

7.1.5. Removing Elements#

  • Elements can be removed from the end of an array using the pop() method.

    numbers.pop();
    console.log(numbers); // Output: [1, 2, 3, 4, 5]
    

7.1.6. Iterating Over Arrays#

  • Arrays can be iterated over using loops like for loop or forEach() method.

    for (let i = 0; i < numbers.length; i++) {
      console.log(numbers[i]);
    }
    // Using forEach
    numbers.forEach(function (number) {
      console.log(number);
    });
    

7.1.7. Slicing Arrays#

  • The slice() method returns a shallow copy of a portion of an array into a new array object.

    let slicedArray = numbers.slice(2, 4);
    console.log(slicedArray); // Output: [3, 4]
    

7.1.8. Splicing Arrays:#

  • The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements in place.

    console.log(numbers); // Output: [1, 2, 3, 4, 5]
    numbers.splice(2, 1); // Removes 1 element from index 2
    console.log(numbers); // Output: [1, 2, 4, 5]
    

7.1.9. Concatenating Arrays:#

  • The concat() method is used to merge two or more arrays.

    let moreNumbers = [6, 7, 8];
    let combinedArray = numbers.concat(moreNumbers);
    console.log(combinedArray); // Output: [1, 2, 4, 5, 6, 7, 8]
    

7.1.10. Finding Elements:#

  • The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.

    console.log(numbers.indexOf(4)); // Output: 2
    

7.1.11. Checking Existence:#

  • The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate.

    console.log(numbers.includes(3)); // Output: true
    

7.1.12. Sorting Arrays:#

  • The sort() method sorts the elements of an array in place and returns the sorted array.

    numbers.sort();
    console.log(numbers); // Output: [1, 2, 4, 5]
    

7.1.13. Mapping Arrays:#

  • The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.

    let doubledNumbers = numbers.map(function (number) {
      return number * 2;
    });
    console.log(doubledNumbers); // Output: [2, 4, 8, 10]
    

7.1.14. Filtering Arrays:#

  • The filter() method creates a new array with all elements that pass the test implemented by the provided function.

    let evenNumbers = numbers.filter(function (number) {
      return number % 2 === 0;
    });
    console.log(evenNumbers); // Output: [2, 4]
    

7.1.15. Reducing Arrays:#

  • The reduce() method applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.

    let sum = numbers.reduce(function (accumulator, currentValue) {
      return accumulator + currentValue;
    }, 0);
    console.log(sum); // Output: 12 (1 + 2 + 4 + 5)
    

7.2. Object Literals (Dictionaries)#

7.2.1. Declaration and Initialization#

  • Objects in JavaScript are collections of key-value pairs, declared and initialized using curly braces {}.

    let person = {
      name: "John",
      age: 30,
      gender: "male",
    };
    

7.2.2. Accessing Properties#

  • Properties of an object can be accessed using dot notation (object.property) or bracket notation (object["property"]).

    console.log(person.name); // Output: John
    console.log(person["age"]); // Output: 30
    

7.2.3. Adding Properties#

  • New properties can be added to an object simply by assigning a value to a new key.

    person.email = "john@example.com";
    console.log(person); // Output: { name: "John", age: 30, gender: "male", email: "john@example.com" }
    

7.2.4. Removing Properties#

  • Properties can be removed from an object using the delete keyword.

    delete person.gender;
    console.log(person); // Output: { name: "John", age: 30, email: "john@example.com" }
    

7.2.5. Object Methods#

  • Objects can contain methods, which are functions associated with the object.

    let person = {
      name: "John",
      age: 30,
      greet: function () {
        console.log("Hello, my name is " + this.name);
      },
    };
    person.greet(); // Output: Hello, my name is John
    

7.2.6. Object Iteration#

  • Objects can be iterated over using for...in loop to access keys and values.

    for (let key in person) {
      console.log(key + ": " + person[key]);
    }
    // Output:
    // name: John
    // age: 30
    // email: john@example.com
    

7.2.7. Nested Objects#

  • Objects can contain other objects as properties, forming nested structures.

    let person = {
      name: "John",
      address: {
        city: "New York",
        country: "USA",
      },
    };
    console.log(person.address.city); // Output: New York
    

7.2.8. Object Constructor#

  • Objects can be created using constructor functions with the new keyword.

    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    let john = new Person("John", 30);
    console.log(john.name); // Output: John
    

7.2.9. Object Destructuring#

  • Object destructuring allows you to extract multiple properties from an object and assign them to variables.

let { name, age } = person;
console.log(name); // Output: John
console.log(age); // Output: 30
const person = {
  firstName: "John",
  lastName: "Doe",
  age: 30,
  hobbies: ["music", "movies", "sports"],
  address: {
    street: "50 main st",
    city: "Boston",
    state: "MA",
  },
};

const {
  firstName,
  lastName,
  address: { city },
} = person;
console.log(city); // Boston

7.2.10. Transfer to JSON#

const person = {
  firstName: "John",
  lastName: "Doe",
  age: 30,
  hobbies: ["music", "movies", "sports"],
  address: {
    street: "50 main st",
    city: "Boston",
    state: "MA",
  },
};

const personJSON = JSON.stringify(person);
console.log(personJSON); //{"firstName":"John","lastName":"Doe","age":30,"hobbies":["music","movies","sports"],"address":{"street":"50 main st","city":"Boston","state":"MA"}}

7.3. JavaScript Classes#

  • JavaScript classes are a blueprint for creating objects with predefined properties and methods. They were introduced in ES6 (ECMAScript 2015) to provide a cleaner and more intuitive syntax for working with object-oriented programming compared to traditional constructor functions and prototypes.

  • Classes simplify the process of creating multiple objects with similar properties and behaviors. They use a combination of the class keyword, constructors, and methods to define and manipulate object instances.

7.3.1. Key Concepts#

  • Class Definition: Use the class keyword followed by the class name. Inside the class, you define a constructor method to initialize new instances.

  • Constructor Method: A special method that is automatically called when a new instance of the class is created.

  • Methods: Functions defined inside a class to perform actions on the object. They can access the object’s properties using this.

  • Prototype Properties: Properties defined on the prototype of a class that are shared across all instances.

  • Overriding Properties: Instance properties can override prototype properties by assigning new values directly to the instance.

7.3.2. Demo Code#

class Rabbit {
constructor(type) {
this.type = type;
}

speak(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
}
}
let killerRabbit = new Rabbit("killer");
let blackRabbit = new Rabbit("black");
killerRabbit.speak('hi');
// → The killer rabbit says 'hi'
blackRabbit.speak('no');
// → The black rabbit says 'no'

Rabbit.prototype.teeth = "small";
console.log(killerRabbit.teeth);
// → small
killerRabbit.teeth = "long, sharp, and bloody";
console.log(killerRabbit.teeth);
// → long, sharp, and bloody
console.log(blackRabbit.teeth);
// → small
console.log(Rabbit.prototype.teeth);
// → small

7.4. Exercises#

7.4.1. Flattening#

Use the reduce method in combination with the concat method to “flatten” an array of arrays into a single array that has all the elements of the original arrays.

// Recursive function to flatten an array of arrays with multiple nesting levels
function flattenArray(arr) {
  return arr.reduce((acc, curr) => {
    // Check if the current element is an array
    if (Array.isArray(curr)) {
      // Recursively flatten the nested array
      return acc.concat(flattenArray(curr));
    } else {
      // If it's not an array, concatenate the element
      return acc.concat(curr);
    }
  }, []);
}

// Example usage with nested arrays
const arrayOfArrays = [[1, [2, [3,4], 45]], [3, 4], [5, 6]];
console.log(flattenArray(arrayOfArrays)); //[1, 2, 3, 4, 45, 3, 4, 5, 6]

7.4.2. Your own loop#

Write a higher-order function loop that provides something like a for loop statement. It takes a value, a test function, an update function, and a body function. Each iteration, it first runs the test function on the current loop value and stops if that returns false. Then it calls the body function, giving it the current value. Finally, it calls the update function to create a new value and starts from the beginning.

function loop(value, test, update, body) {
  // Use a while loop to perform the looping mechanism
  while (test(value)) {
    // Call the body function with the current value
    body(value);
    // Update the value for the next iteration
    value = update(value);
  }
}

// Example usage
// This example starts with a value of 5, continues while the value is greater than 0,
// prints the current value, and decrements the value by 1 each iteration.

loop(
  5,                      // Initial value
  n => n > 0,             // Test function: continue if n > 0
  n => n - 1,             // Update function: decrement n by 1
  console.log             // Body function: print the current value
);

// Output:
// 5
// 4
// 3
// 2
// 1

7.4.3. Everything#

Analogous to the some method, arrays also have an every method.** This one returns true when the given function returns true for every element in the array.** In a way, some is a version of the || operator that acts on arrays, and every is like the && operator.

Implement every as a function that takes an array and a predicate function as parameters. Write two versions, one using a loop and one using the some method.

// Implementation Using a Loop
function everyLoop(array,predicate){
    for(let element of array){
        if(!predicate(element)){
            return false;
        }
    }
    return true;
}

// Example usage:
console.log(everyLoop([1, 2, 3, 4], n => n > 0)); // Output: true
console.log(everyLoop([1, 2, 3, -4], n => n > 0)); // Output: false


// Implementation Using the some Method
function everySome(array, predicate) {
  return !array.some(element => !predicate(element));
}

// Example usage:
console.log(everySome([1, 2, 3, 4], n => n > 0)); // Output: true
console.log(everySome([1, 2, 3, -4], n => n > 0)); // Output: false