@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at upstream/main 164 lines 4.8 kB view raw
1@title JavaScript Object and Array 2@group javascript 3 4This document describes the behaviors of Object and Array in JavaScript, and 5a specific approach to their use which produces basically reasonable language 6behavior. 7 8= Primitives = 9 10JavaScript has two native datatype primitives, Object and Array. Both are 11classes, so you can use `new` to instantiate new objects and arrays: 12 13 COUNTEREXAMPLE 14 var a = new Array(); // Not preferred. 15 var o = new Object(); 16 17However, **you should prefer the shorthand notation** because it's more concise: 18 19 lang=js 20 var a = []; // Preferred. 21 var o = {}; 22 23(A possible exception to this rule is if you want to use the allocation behavior 24of the Array constructor, but you almost certainly don't.) 25 26The language relationship between Object and Array is somewhat tricky. Object 27and Array are both classes, but "object" is also a primitive type. Object is 28//also// the base class of all classes. 29 30 lang=js 31 typeof Object; // "function" 32 typeof Array; // "function" 33 typeof {}; // "object" 34 typeof []; // "object" 35 36 var a = [], o = {}; 37 o instanceof Object; // true 38 o instanceof Array; // false 39 a instanceof Object; // true 40 a instanceof Array; // true 41 42 43= Objects are Maps, Arrays are Lists = 44 45PHP has a single `array` datatype which behaves like as both map and a list, 46and a common mistake is to treat JavaScript arrays (or objects) in the same way. 47**Don't do this.** It sort of works until it doesn't. Instead, learn how 48JavaScript's native datatypes work and use them properly. 49 50In JavaScript, you should think of Objects as maps ("dictionaries") and Arrays 51as lists ("vectors"). 52 53You store keys-value pairs in a map, and store ordered values in a list. So, 54store key-value pairs in Objects. 55 56 var o = { // Good, an object is a map. 57 name: 'Hubert', 58 species: 'zebra' 59 }; 60 61 o.paws = 4; 62 63 o['numberOfEars'] = 2; 64 65 console.log(o.name); 66 console.log(o.paws); 67 console.log(o.numberOfEars); 68 69...and store ordered values in Arrays. 70 71 var a = [1, 2, 3]; // Good, an array is a list. 72 a.push(4); 73 74Don't store key-value pairs in Arrays and don't expect Objects to be ordered. 75 76 COUNTEREXAMPLE 77 var a = []; 78 a['name'] = 'Hubert'; // No! Don't do this! 79 80Technically, both work because Arrays //are// Objects and you think everything 81is fine and dandy, but it won't do what you want and will burn you. For example, 82using `.length` will play tricks on you. 83 84In short, trust me: 85 86* use `[]` only to create a stack of consecutive elements numerically indexed 87* use `{}` to create associative maps ("associative arrays") 88 89= Iterating over Maps and Lists = 90 91Iterate over a map like this: 92 93 lang=js 94 for (var k in object) { 95 f(object[k]); 96 } 97 98NOTE: There's some hasOwnProperty nonsense being omitted here, see below. 99 100Iterate over a list like this: 101 102 lang=js 103 for (var ii = 0; ii < list.length; ii++) { 104 f(list[ii]); 105 } 106 107NOTE: There's some sparse array nonsense being omitted here, see below. 108 109If you try to use `for (var k in ...)` syntax to iterate over an Array, you'll 110pick up a whole pile of keys you didn't intend to and it won't work. If you try 111to use `for (var ii = 0; ...)` syntax to iterate over an Object, it won't work 112at all. 113 114If you consistently treat Arrays as lists and Objects as maps and use the 115corresponding iterators, everything will pretty much always work in a reasonable 116way. 117 118= hasOwnProperty() = 119 120An issue with this model is that if you write stuff to Object.prototype, it will 121show up every time you use enumeration `for`: 122 123 COUNTEREXAMPLE 124 var o = {}; 125 Object.prototype.duck = "quack"; 126 for (var k in o) { 127 console.log(o[k]); // Logs "quack" 128 } 129 130There are two ways to avoid this: 131 132 - test that `k` exists on `o` by calling `o.hasOwnProperty(k)` in every 133 single loop everywhere in your program and only use libraries which also do 134 this and never forget to do it ever; or 135 - don't write to Object.prototype. 136 137Of these, the first option is terrible garbage. Go with the second option. 138 139= Sparse Arrays = 140 141Another wrench in this mess is that Arrays aren't precisely like lists, because 142they do have indexes and may be sparse: 143 144 var a = []; 145 a[2] = 1; 146 console.log(a); // [undefined, undefined, 1] 147 148The correct way to deal with this is: 149 150 for (var ii = 0; ii < list.length; ii++) { 151 if (list[ii] == undefined) { 152 continue; 153 } 154 f(list[ii]); 155 } 156 157Avoid sparse arrays if possible. 158 159= Ordered Maps = 160 161If you need an ordered map, you need to have a map for key-value associations 162and a list for key order. Don't try to build an ordered map using one Object or 163one Array. This generally applies for other complicated datatypes, as well; you 164need to build them out of more than one primitive.