mirror of
				https://github.com/Brandon-Rozek/website.git
				synced 2025-10-31 13:51:13 +00:00 
			
		
		
		
	New post
This commit is contained in:
		
							parent
							
								
									8198ffdb9b
								
							
						
					
					
						commit
						6d2b22eef8
					
				
					 1 changed files with 160 additions and 0 deletions
				
			
		
							
								
								
									
										160
									
								
								content/blog/cursed-knowledge-javascript-arrays-are-objects.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								content/blog/cursed-knowledge-javascript-arrays-are-objects.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,160 @@ | |||
| --- | ||||
| title: "Cursed Knowledge: Javascript Arrays Are Objects" | ||||
| date: 2025-09-01T09:47:01-04:00 | ||||
| draft: false | ||||
| tags: [] | ||||
| math: true | ||||
| medium_enabled: false | ||||
| --- | ||||
| 
 | ||||
| My friend Ethan recently wrote a blog post on [cursed commands](https://emar10.dev/posts/cursed-commands-part-1/). Chris shared with me that Immich has a page on their site called [cursed knowledge](https://immich.app/cursed-knowledge/), and it looks like this has started a trend. I've seen my fair share of the dark arts in programming, so I'll hop on and share what I know about JavaScript arrays. | ||||
| 
 | ||||
| JavaScript arrays are [*exotic objects*](https://262.ecma-international.org/#sec-array-exotic-objects) according to the ECMAScript specification. Therefore, they may lead to unintuitive behavior if we think of these arrays as C-like. | ||||
| 
 | ||||
| Let's play around. | ||||
| 
 | ||||
| ### Concept 1: JavaScript arrays are not continguous | ||||
| 
 | ||||
| First, consider the following array: | ||||
| 
 | ||||
| ```javascript | ||||
| let x = [0, 1, 2]; | ||||
| ``` | ||||
| 
 | ||||
| As one might expect, `x.length` is equal to `3`. To tell whether or not an index is in an array, we can use the `in` operator. | ||||
| 
 | ||||
| ```javascript | ||||
| 3 in x // Evaluates to false | ||||
| ``` | ||||
| 
 | ||||
| If we try to access the 3rd index, the result will evaluate to `undefined`. | ||||
| 
 | ||||
| ```javascript | ||||
| x[3] // Evaluates to undefined | ||||
| ``` | ||||
| 
 | ||||
| Now let's assign an element to the 4th index. Keep in mind that we're skipping over the 3rd one. | ||||
| 
 | ||||
| ```javascript | ||||
| x[4] = 4; | ||||
| ``` | ||||
| 
 | ||||
| Now when we check our `length` property, it'll say that our array is now of size `5`. | ||||
| 
 | ||||
| ```javascript | ||||
| x.length // Evaluates to 5 | ||||
| ``` | ||||
| 
 | ||||
| However, the 3rd index still does not exist | ||||
| 
 | ||||
| ```javascript | ||||
| 3 in x // Evaluates to false | ||||
| ``` | ||||
| 
 | ||||
| ### Concept 2: Explicit vs Implicit `undefined` | ||||
| 
 | ||||
| Recall that `x[3]` evaluates to `undefined`. What happens when we set the value explicitly? | ||||
| 
 | ||||
| ```javascript | ||||
| x[3] = undefined; | ||||
| 3 in x // Evaluates to true | ||||
| ``` | ||||
| 
 | ||||
| So there is a difference on whether we have explicitly set an index to `undefined`! This distinction is not always used. For example, our trusty for-of loop does not care. | ||||
| 
 | ||||
| ```javascript | ||||
| x = [0, 1, 2]; | ||||
| x[4] = 4; | ||||
| for (a of x) { | ||||
|     console.log(a) | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Will print out | ||||
| 
 | ||||
| ``` | ||||
| 0 | ||||
| 1 | ||||
| 2 | ||||
| undefined | ||||
| 4 | ||||
| ``` | ||||
| 
 | ||||
| ### Concept 3: Indices are actually strings | ||||
| 
 | ||||
| Given that we have a length property and that we've been indexing with numeric keys, it must mean that arrays have numeric indices. Right? | ||||
| 
 | ||||
| ``` | ||||
| "0" in ["a", "b"] // Evaluates to true | ||||
| ``` | ||||
| 
 | ||||
| Okay, it looks like there's some conversion magic that's happening behind the scenes here. The ECMAScript specification says that an array index must be strictly less than $2^{32}$. So what happens if it is not? | ||||
| 
 | ||||
| ```javascript | ||||
| let x = [0]; | ||||
| x[4294967296] = true | ||||
| x // Evaluates to [ 0, '4294967296': true ] | ||||
| ``` | ||||
| 
 | ||||
| It looks like it no longer gets treated as an array item, but instead treats it as an arbitrary key-value pair. Why stop there, this must mean that we can store any sort of arbitrary data in our array. | ||||
| 
 | ||||
| ```javascript | ||||
| x.name = "Brandon" | ||||
| x // Evaluates to [ 0, '4294967296': true, name: 'Brandon' ] | ||||
| ``` | ||||
| 
 | ||||
| ### Viewing arrays as objects | ||||
| 
 | ||||
| Now everything starts to make more sense when we think of these arrays as objects. | ||||
| 
 | ||||
| ```javscript | ||||
| let x = [0, 1, 2]; | ||||
| x[4] = 4; | ||||
| ``` | ||||
| 
 | ||||
| Internally, this corresponds to the object: | ||||
| 
 | ||||
| ```javascript | ||||
| { | ||||
|     "0": 0, | ||||
|     "1": 1, | ||||
|     "2": 2, | ||||
|     "4": 4 | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| From this object, we can see that the keys are strings and that the 3rd key is not in the object. Now let's see what happens when we explicitly set `x[5] = undefined`. | ||||
| 
 | ||||
| ```javascript | ||||
| { | ||||
|   "0": 0, | ||||
|   "1": 1, | ||||
|   "2": 2, | ||||
|   "4": 4, | ||||
|   "5": undefined | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| The 5th key is now in our object and it's set to an undefined value. We also get an undefined value when we try to retrieve a value of a key that is not in our object. | ||||
| 
 | ||||
| The length of our array is the highest "numeric" key within our object (subject to the size limit). When we iterate over our array using `for-of`, we're iterating from `"0"` to our length. | ||||
| 
 | ||||
| ```javascript | ||||
| for (a of x) { | ||||
|     console.log(a); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Is the same as: | ||||
| 
 | ||||
| ```javascript | ||||
| console.log(x[0]); | ||||
| console.log(x[1]); | ||||
| console.log(x[2]); | ||||
| console.log(x[3]); | ||||
| console.log(x[4]); | ||||
| console.log(x[5]); | ||||
| ``` | ||||
| 
 | ||||
| That's an exotic object for you. | ||||
| 
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue