|
| 1 | +// how to make an object singleton/ how to declare an object with the help of constructor. |
| 2 | +// -> singleton class is a class which has only one object, which is created when the class is loaded for the first time. This object is then shared globally. |
| 3 | +// -> singleton class is used when we want to restrict object creation of a class from outside. |
| 4 | +// -> singleton class is used when we want to create a single object of a class and want to share it globally. |
| 5 | +// -> In JS, we can create a singleton class by using a constructor function and a private variable. |
| 6 | +// -> we can also use a factory function to create a singleton class. |
| 7 | + |
| 8 | +// 1. Demonstrating two ways to create an object in JavaScript |
| 9 | +// ---------------------------------------------------------- |
| 10 | + |
| 11 | +// 1.1 Using Object Literal |
| 12 | +// Here, we declare an object `user1` using an object literal syntax. It includes properties like `name`, `age` and a method `work()` |
| 13 | +// `work()` is a function that logs a message using `this` keyword, which refers to the object itself. |
| 14 | +let user1 = { |
| 15 | + name: "John", // Property holding the user's name |
| 16 | + age: 25, // Property holding the user's age |
| 17 | + work() { |
| 18 | + // Method representing a function of the object |
| 19 | + console.log("I am working and here is my data :", this); |
| 20 | + }, |
| 21 | +}; |
| 22 | + |
| 23 | +// Printing the `user1` object to the console |
| 24 | +console.log(user1); // Output: { name: 'John', age: 25, work: [Function: work] } |
| 25 | + |
| 26 | +// Calling the `work` method of `user1`. Here, `this` inside `work()` refers to `user1` object |
| 27 | +user1.work(); // Output: I am working and here is my data : { name: 'John', age: 25, work: [Function: work] } |
| 28 | + |
| 29 | +// ---------------------------------------------------------- |
| 30 | + |
| 31 | +// 1.2 Using Constructor Function (ES5) |
| 32 | +// We define a class-like structure using a function to simulate a constructor. |
| 33 | +// This function is used to create objects with properties like `name` and `age`. |
| 34 | +class UserClass { |
| 35 | + constructor(name, age) { |
| 36 | + this.name = name; // Property for name |
| 37 | + this.age = age; // Property for age |
| 38 | + } |
| 39 | +} |
| 40 | +// OR we can use a regular function instead of a class to create the object. |
| 41 | +function UserFunction(name, age) { |
| 42 | + this.name = name; // Property for name |
| 43 | + this.age = age; // Property for age |
| 44 | +} |
| 45 | +// Creating a new object of `UserClass` using the `new` keyword. |
| 46 | +let userObj = new UserClass("Jane", 30); |
| 47 | +console.log(userObj); // Output: UserClass { name: 'Jane', age: 30 } |
| 48 | + |
| 49 | +// 1.3 Another way of declaring objects without using a class |
| 50 | +// Here, we are using `new Object()` to create an empty object. |
| 51 | +// This is still an object, but lacks properties or methods initially. |
| 52 | +const tinderUser = new Object(); // This is a singleton object |
| 53 | +console.log(tinderUser); // Output: {} -> Empty object |
| 54 | + |
| 55 | +// 1.4 A simpler way of declaring an object |
| 56 | +// Using the object literal syntax to declare an empty object. |
| 57 | +const tinderUser1 = {}; // This is a non-singleton object |
| 58 | +console.log(tinderUser1); // Output: {} -> Empty object |
| 59 | + |
| 60 | +// ---------------------------------------------------------- |
| 61 | + |
| 62 | +// Example 2: Creating Objects Inside an Object and Accessing Them |
| 63 | +// ---------------------------------------------------------- |
| 64 | + |
| 65 | +// We are creating a nested object inside `regularUser`, where the `fullname` property |
| 66 | +// is itself an object containing `userFullname` which further holds `first` and `last` name. |
| 67 | +const regularUser = { |
| 68 | + email: "some@gmail.com", // Property holding the user's email |
| 69 | + fullname: { |
| 70 | + // Nested object holding user full name |
| 71 | + userFullname: { |
| 72 | + // Another object for full name details |
| 73 | + first: "John", // Property holding first name |
| 74 | + last: "Doe", // Property holding last name |
| 75 | + }, |
| 76 | + }, |
| 77 | +}; |
| 78 | + |
| 79 | +// Accessing the `fullname` object from the `regularUser` object |
| 80 | +console.log(regularUser.fullname); // Output: { userFullname: { first: 'John', last: 'Doe' } } |
| 81 | +// Accessing the `userFullname` object from `fullname` |
| 82 | +console.log(regularUser.fullname.userFullname); // Output: { first: 'John', last: 'Doe' } |
| 83 | + |
| 84 | +// ---------------------------------------------------------- |
| 85 | + |
| 86 | +// Example 3: Combining Multiple Objects |
| 87 | +// ---------------------------------------------------------- |
| 88 | + |
| 89 | +// Declaring two separate objects `obj1` and `obj2`. |
| 90 | +const obj1 = { 1: "a", 2: "b" }; // Object with two key-value pairs |
| 91 | +const obj2 = { 3: "c", 4: "d" }; // Object with two key-value pairs |
| 92 | + |
| 93 | +// Using an object literal to combine `obj1` and `obj2` inside `obj3`. |
| 94 | +// Here, `obj1` and `obj2` are placed as properties within `obj3`, not merged. |
| 95 | +const obj3 = { obj1, obj2 }; |
| 96 | +console.log(obj3); |
| 97 | +// Output: { obj1: { '1': 'a', '2': 'b' }, obj2: { '3': 'c', '4': 'd' } } |
| 98 | + |
| 99 | +// Correct way to combine two objects using the spread operator |
| 100 | +// The spread operator (`...`) is used to copy the properties from `obj1` and `obj2` into a new object. |
| 101 | +const obj11 = { 1: "a", 2: "b" }; // Object with two key-value pairs |
| 102 | +const obj12 = { 3: "c", 4: "d" }; // Object with two key-value pairs |
| 103 | +const obj13 = { ...obj11, ...obj12 }; // Merging both objects into a new object `obj13` |
| 104 | +console.log(obj13); |
| 105 | +// Output: { '1': 'a', '2': 'b', '3': 'c', '4': 'd' } |
| 106 | + |
| 107 | +// Another way to combine objects using `Object.assign()` |
| 108 | +// `Object.assign(target, source)` copies all properties from `source` to `target`, modifying the target. |
| 109 | +const target = { 1: "a", 2: "b" }; // Target object |
| 110 | +const source = { 2: "c", 4: "d" }; // Source object |
| 111 | +const returnedTarget = Object.assign(target, source); |
| 112 | +console.log(target); // Output: { '1': 'a', '2': 'c', '4': 'd' } |
| 113 | +console.log(source); // Output: { '2': 'c', '4': 'd' } |
| 114 | +console.log(returnedTarget); // Output: { '1': 'a', '2': 'c', '4': 'd' } |
| 115 | +console.log(returnedTarget == target); // true - since `returnedTarget` is the same as `target` |
| 116 | + |
| 117 | +// ---------------------------------------------------------- |
| 118 | + |
| 119 | +// Creating a New Object Using `Object.assign()` |
| 120 | +// `Object.assign({}, target1, source1)` creates a new object instead of modifying the target. |
| 121 | +const target1 = { 1: "a", 2: "b" }; // Original target object |
| 122 | +const source1 = { 2: "c", 4: "d" }; // Source object |
| 123 | +const returnedTarget1 = Object.assign({}, target1, source1); |
| 124 | +console.log(target1); // Output: { '1': 'a', '2': 'b' } |
| 125 | +console.log(source1); // Output: { '2': 'c', '4': 'd' } |
| 126 | +console.log(returnedTarget1); // Output: { '1': 'a', '2': 'c', '4': 'd' } |
| 127 | +console.log(returnedTarget1 == target1); // false - since `returnedTarget1` is a new object |
| 128 | + |
| 129 | +// ---------------------------------------------------------- |
| 130 | + |
| 131 | +// Explanation of differences between `Object.assign()` usages: |
| 132 | + |
| 133 | +// 1. Modifying an Existing Object: |
| 134 | +// `Object.assign(target, source)` modifies the existing `target` object. |
| 135 | +// If there are overlapping properties in the `source`, they overwrite those in the `target`. |
| 136 | + |
| 137 | +// 2. Creating a New Object: |
| 138 | +// `Object.assign({}, target1, source1)` creates a new object, combining properties from `target1` and `source1`. |
| 139 | +// This way, the original `target1` remains unchanged. |
| 140 | + |
| 141 | +// Use the first method to update an existing object. |
| 142 | +// Use the second method to create a new object without altering the original. |
| 143 | + |
| 144 | +// ---------------------------------------------------------- |
| 145 | + |
| 146 | +// Example of working with an array of objects |
| 147 | +// When data comes from a database, it often comes in the form of an array of objects. |
| 148 | +const people = [ |
| 149 | + // 'people' is an array containing three objects, each representing a person. |
| 150 | + { id: 1, name: "John", age: 30 }, // First object representing John |
| 151 | + { id: 2, name: "Jane", age: 25 }, // Second object representing Jane |
| 152 | + { id: 3, name: "Bob", age: 40 }, // Third object representing Bob |
| 153 | +]; |
| 154 | +console.log(people[1].name); // Output: Jane - accessing the `name` property of the second object in the `people` array |
| 155 | + |
| 156 | +// ---------------------------------------------------------- |
| 157 | + |
| 158 | +// Demonstrating Object Methods: `Object.keys`, `Object.values`, and `Object.entries` |
| 159 | +console.log(Object.keys(user1)); // Output: [ 'name', 'age', 'work' ] - Array of property names (keys) of `user1` |
| 160 | +console.log(Object.values(user1)); // Output: [ 'John', 25, [Function: work] ] - Array of property values of `user1` |
| 161 | +console.log(Object.keys(user1).length); // Output: 3 - Number of properties in `user1` |
| 162 | +console.log(Object.values(user1).length); // Output: 3 - Number of values in `user1` |
| 163 | +console.log(Object.keys(user1).length == Object.values(user1).length); // Output: true - Both lengths are equal |
| 164 | +console.log(Object.entries(user1)); // Output: [ [ 'name', 'John' ], [ 'age', 25 ], [ 'work', [Function: work] ] ] |
| 165 | +console.log(Object.entries(user1).length); // Output: 3 - Number of entries in `user1` (each entry is a [key, value] pair) |
| 166 | +console.log(user1.hasOwnProperty("work")); // Output: true - Checking if `work` is a property of `user1` |
| 167 | +console.log(user1.hasOwnProperty("email")); // Output: false - Checking if `email` is a property of `user1` |
| 168 | + |
| 169 | +// ---------------------------------------------------------- |
| 170 | + |
| 171 | +// Example of Iterating Over Objects in JavaScript using `Object.keys`, `Object.values`, and `for...in` |
| 172 | + |
| 173 | +// Object with student scores. |
| 174 | +const studentScores = { |
| 175 | + Alice: 85, |
| 176 | + Bob: 92, |
| 177 | + Charlie: 88, |
| 178 | + Diana: 79, |
| 179 | +}; |
| 180 | + |
| 181 | +// Example 1: Using `Object.keys` and `Object.values` to iterate |
| 182 | +console.log("Using Object.keys and Object.values:"); |
| 183 | + |
| 184 | +// Step 1: Get an array of all student names (keys) |
| 185 | +const names = Object.keys(studentScores); // ['Alice', 'Bob', 'Charlie', 'Diana'] |
| 186 | + |
| 187 | +// Step 2: Get an array of all scores (values) |
| 188 | +const scores = Object.values(studentScores); // [85, 92, 88, 79] |
| 189 | + |
| 190 | +// Step 3: Loop through the names and print each name with the corresponding score |
| 191 | +// Using `forEach` to iterate over the names array and print corresponding score using index |
| 192 | +names.forEach((name, index) => { |
| 193 | + console.log(`${name}: ${scores[index]}`); |
| 194 | + // Output: |
| 195 | + // Alice: 85 |
| 196 | + // Bob: 92 |
| 197 | + // Charlie: 88 |
| 198 | + // Diana: 79 |
| 199 | +}); |
| 200 | + |
| 201 | +// Step 4: Calculate the total of all scores |
| 202 | +const total = scores.reduce((sum, score) => sum + score, 0); // Sum all the scores |
| 203 | +// 85 + 92 + 88 + 79 = 344 |
| 204 | + |
| 205 | +// Step 5: Calculate the average score |
| 206 | +const average = total / scores.length; // 344 / 4 = 86 |
| 207 | +console.log(`Average Score: ${average}`); // Output: Average Score: 86 |
| 208 | + |
| 209 | +// Example 2: Using a Traditional Loop (for...in) |
| 210 | +console.log("\nUsing a Traditional Loop:"); |
| 211 | + |
| 212 | +// Step 1: Initialize variables to calculate total and count |
| 213 | +let totalScore = 0; // To store the sum of scores |
| 214 | +let count = 0; // To count the number of students |
| 215 | + |
| 216 | +// Step 2: Use a `for...in` loop to iterate through the object |
| 217 | +for (const name in studentScores) { |
| 218 | + // Check if the property belongs directly to the object (not inherited from the prototype) |
| 219 | + if (studentScores.hasOwnProperty(name)) { |
| 220 | + // Step 3: Print the name and score |
| 221 | + console.log(`${name}: ${studentScores[name]}`); |
| 222 | + // Output: |
| 223 | + // Alice: 85 |
| 224 | + // Bob: 92 |
| 225 | + // Charlie: 88 |
| 226 | + // Diana: 79 |
| 227 | + |
| 228 | + // Step 4: Add the score to the total |
| 229 | + totalScore += studentScores[name]; |
| 230 | + |
| 231 | + // Step 5: Increment the count of students |
| 232 | + count++; |
| 233 | + } |
| 234 | +} |
| 235 | + |
| 236 | +// Step 6: Calculate the average score |
| 237 | +const avgScore = totalScore / count; // 344 / 4 = 86 |
| 238 | +console.log(`Average Score: ${avgScore}`); // Output: Average Score: 86 |
0 commit comments