|
| 1 | +**Table of Content** |
| 2 | + |
| 3 | +- [Value Comparison Operators](#value-comparison-operators) |
| 4 | + - [Comparing Objects in JavaScript](#comparing-objects-in-javascript) |
| 5 | + - [Referential Equality](#referential-equality) |
| 6 | + - [Manual Comparision](#manual-comparision) |
| 7 | + - [Shallow Equality](#shallow-equality) |
| 8 | + - [Deep Equality](#deep-equality) |
| 9 | + |
| 10 | +# Value Comparison Operators |
| 11 | + |
| 12 | +When we have to compare two values in JavaScript, we use comparison operators provided by default in JavaScript. When we compare twovalues, a `boolean (true or false)` value is returned. |
| 13 | + |
| 14 | +There are eight comparision operators in JavaScript. |
| 15 | + |
| 16 | +- `>` : greater than - Returns `true` if the operand on the left is greater than on the right of the operand. |
| 17 | + |
| 18 | +```js |
| 19 | +let result = 40 > 60; |
| 20 | +console.log(result); //OUTPUT: false |
| 21 | +``` |
| 22 | + |
| 23 | +- `<` : less than - Returns `true` is the operand on the left is less than the operand on the right. |
| 24 | + |
| 25 | +```js |
| 26 | +let result = 40 < 60; |
| 27 | +console.log(result); //OUTPUT: true |
| 28 | +``` |
| 29 | + |
| 30 | +- `>=` : greater than or equal to - Returns `true` if the oeprand on the left is greater or equal to the operand on right. |
| 31 | + |
| 32 | +```js |
| 33 | +let result1 = 20 >= 10; |
| 34 | +let result2 = 10 >= 10; |
| 35 | + |
| 36 | +console.log(result1); //OUTPUT: true |
| 37 | +cosnole.log(result2); //OUTPUT: true |
| 38 | +``` |
| 39 | + |
| 40 | +- `<=` : less than or equal to - Returns `true` if the operand on the left is less than or equal to the operand on the right. |
| 41 | + |
| 42 | +```js |
| 43 | +let result = 40 <= 60; |
| 44 | +console.log(result); //OUTPUT: true |
| 45 | +``` |
| 46 | + |
| 47 | +- `==` : equal to - Returns `true` if the operand on the left is equal to the operand on the right. |
| 48 | + |
| 49 | +```js |
| 50 | +let result = 4 == "4"; |
| 51 | +console.log(result); //OUTPUT: true |
| 52 | +``` |
| 53 | + |
| 54 | +`==` operators converts both of our values into a common data type and returns true if both operands are equal in value. |
| 55 | + |
| 56 | +- `===` : strictly equal to - returns `true` if the operand on the left is strictly equal to the operand on the right. |
| 57 | + |
| 58 | +```js |
| 59 | +let result = 4 === "4"; |
| 60 | +console.log(result); //OUTPUT: false |
| 61 | +``` |
| 62 | + |
| 63 | +`===` operators do not convert the operands into same data type and hence only returns `true` id both the operands are equal in values and also of same data type. |
| 64 | + |
| 65 | +- `!=` : not equal to - returns `true` if the operand on the left is not equal to the operand on the right. |
| 66 | + |
| 67 | +```js |
| 68 | +let result = 4 != "4"; |
| 69 | +console.log(result); //OUTPUT: false |
| 70 | +``` |
| 71 | + |
| 72 | +- `!==` : strict not equal to - returns `true` if the operand on the left is strictly not equal to the operand on the right. |
| 73 | + |
| 74 | +```js |
| 75 | +let result = 4 !== "4"; |
| 76 | +console.log(result); //OUTPUT: true |
| 77 | +``` |
| 78 | + |
| 79 | +**Equal Operator (==) vs Strict Equal Operator (===)** |
| 80 | + |
| 81 | +| Equal Operator (==) | Strict Equal Operator (===) | |
| 82 | +| --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | |
| 83 | +| Converts the operands to same data type before comparision. | Does not convert the operands to same data type before comparison. | |
| 84 | +| Returns `true` if both values are equal irrespective of their data type. | Returns `true` only if both the values and the data type of the operands are same. | |
| 85 | +| Example: As `undefined` and `null` are losely equal, `undefined` == `null` returns as `true`. | Example: As `undefined` and `null` are strictly not equal, `undefined` === `null` returns as `false`. | |
| 86 | + |
| 87 | +## Comparing Objects in JavaScript |
| 88 | + |
| 89 | +Comparing Object in JavaScript is difficult than comparing primitive data types since objects are structured data. JavaScript essentially provides us three ways to compare values: |
| 90 | + |
| 91 | +- Strict Equality Operator (===) |
| 92 | +- Loose Equality Operator (==) |
| 93 | +- `Object.is()` function |
| 94 | + |
| 95 | +### Referential Equality |
| 96 | + |
| 97 | +When we compare objects using any of the above operator, it only returns `true` if the comapred value refers to the same object instance. This is called `referential equality`. |
| 98 | + |
| 99 | +```js |
| 100 | +const hero1 = { |
| 101 | + name: "Spider Man", |
| 102 | +}; |
| 103 | + |
| 104 | +const hero2 = { |
| 105 | + name: "Spider Man", |
| 106 | +}; |
| 107 | + |
| 108 | +console.log(hero1 === hero1); // OUTPUT: true |
| 109 | +console.log(hero1 === hero2); // OUTPUT: false |
| 110 | + |
| 111 | +console.log(hero1 == hero1); // OUTPUT: true |
| 112 | +console.log(hero1 == hero2); // OUTPUT: false |
| 113 | + |
| 114 | +console.log(Object.is(hero1, hero1)); // OUTPUT: true |
| 115 | +console.log(Object.is(hero1, hero2)); // OUTPUT: false |
| 116 | +``` |
| 117 | + |
| 118 | +Here, `hero1 === hero1` evaluates to `true` because both operands points to the same object instance `hero1` however `hero1 === hero2`returns `false` because `hero1` and `hero2` are two different object instances although both objects have the same property `name` with the same value of `Spider Man`. |
| 119 | + |
| 120 | +Hence, `Referential Equality` is used when we want to compare the object references, rather than their content (property and value). |
| 121 | + |
| 122 | +### Manual Comparision |
| 123 | + |
| 124 | +We can compare the contents in the object simply by accessing the properties and comparing them manually. |
| 125 | + |
| 126 | +```js |
| 127 | +function isUserSame(obj1, obj2) { |
| 128 | + return obj1.fullName === obj2.fullName; |
| 129 | +} |
| 130 | + |
| 131 | +const user1 = { |
| 132 | + fullName: "Prabesh Thapa"; |
| 133 | +} |
| 134 | + |
| 135 | +const user2 = { |
| 136 | + fullName: "Prabesh Thapa"; |
| 137 | +} |
| 138 | + |
| 139 | +const user1 = { |
| 140 | + fullName: "Laxmi Thapa"; |
| 141 | +} |
| 142 | + |
| 143 | +console.log(isUserSame(user1, user2)); //OUTPUT: true |
| 144 | +console.log(isUserSame(user1, user3)); //OUTPUT: false |
| 145 | +``` |
| 146 | + |
| 147 | +Manual comparision is the best possible way to to compare the properties of simple objects but it isn't convenient when we have to deal with bigger objects. This is where we can use `Shallow Equality`. |
| 148 | + |
| 149 | +### Shallow Equality |
| 150 | + |
| 151 | +We can get the list of properties in both the objects using the `Object.keys()` method and later check the properties values for equality. |
| 152 | + |
| 153 | +```js |
| 154 | +function isUserSame(obj1, obj2) { |
| 155 | + const keys1 = Object.keys(obj1); |
| 156 | + const keys2 = Object.keys(obj2); |
| 157 | + |
| 158 | + console.log(keys1); //OUTPUT: ["firstName", "lastName", "age"] |
| 159 | + console.log(keys2); //OUTPUT: ["firstName", "lastName", "age"] |
| 160 | + |
| 161 | + if (keys1.length !== keys2.length) { |
| 162 | + return false; |
| 163 | + } |
| 164 | + |
| 165 | + for (let key of keys1) { |
| 166 | + if (obj1[key] !== obj2[key]) { |
| 167 | + return false; |
| 168 | + } |
| 169 | + } |
| 170 | + return true; |
| 171 | +} |
| 172 | + |
| 173 | +const user1 = { |
| 174 | + firstName: "Prabesh", |
| 175 | + lastName: "Thapa", |
| 176 | + age: 23, |
| 177 | +}; |
| 178 | + |
| 179 | +const user2 = { |
| 180 | + firstName: "Prabesh", |
| 181 | + lastName: "Thapa", |
| 182 | + age: 23, |
| 183 | +}; |
| 184 | + |
| 185 | +const user3 = { |
| 186 | + firstName: "Laxmi", |
| 187 | + lastName: "Thapa", |
| 188 | + age: 21, |
| 189 | +}; |
| 190 | + |
| 191 | +console.log(isUserSame(user1, user2)); //OUTPUT: true |
| 192 | +console.log(isUserSame(user1, user3)); //OUTPUT: false |
| 193 | +``` |
| 194 | + |
| 195 | +Inside the function, `keys1` and `keys2` are arrays containg the property names of `obj1` and `obj2`. Here, `isUserSame(user1, user2)` returns `true` because both `user1` and `user2` have the same properties with same values. |
| 196 | + |
| 197 | +**Shallow Equality doesn't work so well with nested objects however.** |
| 198 | + |
| 199 | +```js |
| 200 | +const user1 = { |
| 201 | + firstName: "Prabesh", |
| 202 | + lastName: "Thapa", |
| 203 | + age: 23, |
| 204 | + address: { |
| 205 | + city: "Pokhara", |
| 206 | + }, |
| 207 | +}; |
| 208 | + |
| 209 | +const user2 = { |
| 210 | + firstName: "Prabesh", |
| 211 | + lastName: "Thapa", |
| 212 | + age: 23, |
| 213 | + address: { |
| 214 | + city: "Pokhara", |
| 215 | + }, |
| 216 | +}; |
| 217 | + |
| 218 | +console.log(isUserSame(user1, user2)); //OUTPUT: false |
| 219 | +``` |
| 220 | + |
| 221 | +Interestingly, although `user1` and `user2` both have same properties and values, shallow equality returns `false`. This is because, the nested object `user1.address` and `user2.address` are different object instances, hence shallow equality considers them to be not equal. |
| 222 | + |
| 223 | +This problem can fortunately be solved with `Deep Equality`. |
| 224 | + |
| 225 | +### Deep Equality |
| 226 | + |
| 227 | +Deep equality is similar to shallow equality but with one major difference. During the comparision, a recursive check is performed on the nested objects. |
| 228 | + |
| 229 | +```js |
| 230 | +function deepEqual(obj1, obj2) { |
| 231 | + const keys1 = Object.keys(obj1); |
| 232 | + const keys2 = Object.keys(obj2); |
| 233 | + |
| 234 | + if (keys1.length !== keys2.length) return false; |
| 235 | + |
| 236 | + for (const key of keys1) { |
| 237 | + const val1 = obj1[key]; |
| 238 | + const val2 = obj2[key]; |
| 239 | + const areObjects = isObject(val1) && isObject(val2); |
| 240 | + |
| 241 | + if ( |
| 242 | + (areObjects && !deepEqual(val1, val2)) || |
| 243 | + (!areObjects && val1 !== val2) |
| 244 | + ) { |
| 245 | + return false; |
| 246 | + } |
| 247 | + } |
| 248 | + return true; |
| 249 | +} |
| 250 | + |
| 251 | +function isObject(obj) { |
| 252 | + return (obj != null) & (typeof obj === "object"); |
| 253 | +} |
| 254 | +``` |
| 255 | + |
| 256 | +The `isObject` function checks if an object is not `null` or `undefined`, and if its type is `object`, returning a boolean value accordingly. |
| 257 | + |
| 258 | +The `deepEqual` function takes two objects as input and recursively compares their properties and values to determine if they are deeply equal (i.e., if they have the same properties with the same values). |
| 259 | + |
| 260 | +To do this, it first gets an array of the keys of each object using `Object.keys()`. If the length of these arrays is not the same, the function immediately returns false. |
| 261 | + |
| 262 | +Then, for each key in the `keys1` array, the function gets the corresponding values from both objects (val1 and val2) and checks if they are both objects using the `isObject` function. If they are, the function recursively calls `deepEqual` on these nested objects to determine if they are equal. If they are not both objects, the function checks if their values are equal using the `!==` operator. |
| 263 | + |
| 264 | +If any of the comparisons in the for loop fail, the function immediately returns false. If all of the comparisons pass, the function returns true. |
| 265 | + |
| 266 | +```js |
| 267 | +const user1 = { |
| 268 | + firstName: "Prabesh", |
| 269 | + lastName: "Thapa", |
| 270 | + age: 23, |
| 271 | + address: { |
| 272 | + city: "Pokhara", |
| 273 | + }, |
| 274 | +}; |
| 275 | + |
| 276 | +const user2 = { |
| 277 | + firstName: "Prabesh", |
| 278 | + lastName: "Thapa", |
| 279 | + age: 23, |
| 280 | + address: { |
| 281 | + city: "Pokhara", |
| 282 | + }, |
| 283 | +}; |
| 284 | + |
| 285 | +console.log(deepEqual(user1, user2)); //OUTPUT: true |
| 286 | +``` |
| 287 | + |
| 288 | +Here, deep equality function correctly determines that both `user1` and `user2` have same properties and values, including the nested objects. |
| 289 | + |
| 290 | +**Summary:** |
| 291 | + |
| 292 | +- Referential equality using `==`, `===` and `Object.is()` checks whether the operands are the instance of same object. |
| 293 | +- We can also manually compare the values of properties in the object by accessing the properties of those objects. |
| 294 | +- We use shallow equality when the objects to be compared have a lot of properties or if the object is determined at the runtime. |
| 295 | +- We use deep equality check if the compared objects have nested objects. |
0 commit comments