@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
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.