1 | # scour.js
|
2 |
|
3 |
|
4 |
|
5 | > Traverse objects and arrays immutably
|
6 |
|
7 | Scour is a general-purpose library for dealing with JSON trees.<br>
|
8 | As a simple utility with a broad purpose, it can be used to solve many problems. Use it to:
|
9 |
|
10 | - Manage your [Redux] datastore.
|
11 | - Provide a model layer to access data in your single-page app. [→](#models)
|
12 | - Navigate a large JSON tree easily.
|
13 | - Rejoice in having a lightweight alternative to [Immutable.js]. ([Compare](docs/comparison.md))
|
14 |
|
15 | [![Status](https://travis-ci.org/rstacruz/scour.svg?branch=master)](https://travis-ci.org/rstacruz/scour "See test builds")
|
16 |
|
17 | ## Install
|
18 |
|
19 | ```sh
|
20 | npm install --save-exact scourjs
|
21 | ```
|
22 |
|
23 | ```js
|
24 | window.scour // non commonjs
|
25 | const scour = require('scourjs') // commonjs/node
|
26 | import scour from 'scourjs' // es6 modules
|
27 | ```
|
28 |
|
29 | ## Features
|
30 |
|
31 | Calling `scour(object)` returns a wrapper that you can use to traverse `object`.
|
32 | Use [get()](#get) to retrieve values.
|
33 |
|
34 | ```js
|
35 | data =
|
36 | { users:
|
37 | { 1: { name: 'john' },
|
38 | 2: { name: 'shane', confirmed: true },
|
39 | 3: { name: 'barry', confirmed: true } } }
|
40 | ```
|
41 |
|
42 | ```js
|
43 | scour(data).get('users', '1', 'name') // => 'john'
|
44 | ```
|
45 |
|
46 | ### Traversal
|
47 | Use [go()](#go) to dig into the structure. It will return another `scour`
|
48 | wrapper scoped to that object.
|
49 |
|
50 | ```js
|
51 | data =
|
52 | { users:
|
53 | { admins:
|
54 | { bob: { logged_in: true },
|
55 | sue: { logged_in: false } } } }
|
56 | ```
|
57 |
|
58 | ```js
|
59 | users = scour(data).go('users') // => [scour (admins)]
|
60 | admins = scour(data).go('users', 'admins') // => [scour (bob, sue)]
|
61 |
|
62 | admins.go('bob').get('logged_in') // => true
|
63 | ```
|
64 |
|
65 | ### Chaining
|
66 |
|
67 | `scour()` provides a wrapper that can be used to chain methods. This is inspired by [Underscore] and [Lodash].
|
68 |
|
69 | ```js
|
70 | scour(data)
|
71 | .go('users')
|
72 | .filter({ admin: true })
|
73 | .value
|
74 | ```
|
75 |
|
76 | [Underscore]: http://underscorejs.org/
|
77 | [Lodash]: http://lodash.com/
|
78 |
|
79 |
|
80 | ### Immutable modifications
|
81 |
|
82 | Use [set()](#set) to update values. Scout treats all data as immutable, so this
|
83 | doesn't modify your original `data`, but gets you a new one with the
|
84 | modifications made.
|
85 |
|
86 | ```js
|
87 | data = scour(data)
|
88 | .set(['users', '1', 'updated_at'], +new Date())
|
89 | .value
|
90 |
|
91 | // => { users:
|
92 | // { 1: { name: 'john', updated_at: 1450667171188 },
|
93 | // 2: { name: 'shane', confirmed: true },
|
94 | // 3: { name: 'barry', confirmed: true } } }
|
95 | ```
|
96 |
|
97 | ### Advanced traversing
|
98 |
|
99 | Use [filter()] to filter results with advanced querying.
|
100 |
|
101 | ```js
|
102 | users = scour(data).go('users')
|
103 |
|
104 | users
|
105 | .filter({ confirmed: true })
|
106 | .at(0)
|
107 | .get('name') // => 'shane'
|
108 | ```
|
109 |
|
110 | ### Models
|
111 |
|
112 | Use [use()](#use) to add your own methods to certain keypaths. This makes them behave like models. See [a detailed example](docs/extensions_example.md) of this.
|
113 |
|
114 | ##### Sample data
|
115 |
|
116 |
|
117 |
|
118 | ```js
|
119 | data =
|
120 | { artists:
|
121 | { 1: { first_name: 'Louie', last_name: 'Armstrong' },
|
122 | 2: { first_name: 'Miles', last_name: 'Davis' } } }
|
123 | ```
|
124 |
|
125 | ##### Your models
|
126 |
|
127 |
|
128 |
|
129 | ```js
|
130 | Root = {
|
131 | artists () { return this.go('artists') }
|
132 | }
|
133 |
|
134 | Artist = {
|
135 | fullname () {
|
136 | return this.get('first_name') + ' ' + this.get('last_name')
|
137 | }
|
138 | }
|
139 | ```
|
140 |
|
141 | ##### Using with scour
|
142 |
|
143 |
|
144 |
|
145 | ```js
|
146 | db = scour(data)
|
147 | .use({
|
148 | '': Root,
|
149 | 'artists.*': Artist
|
150 | })
|
151 |
|
152 | db.artists().find({ name: 'Miles' }).fullname()
|
153 | //=> 'Miles Davis'
|
154 | ```
|
155 |
|
156 | ## API
|
157 |
|
158 |
|
159 |
|
160 | ### scour
|
161 |
|
162 | > `scour(object)`
|
163 |
|
164 | Returns a scour instance wrapping `object`.
|
165 |
|
166 | ```js
|
167 | scour(obj)
|
168 | ```
|
169 |
|
170 | It can be called on any Object or Array. (In fact, it can be called on
|
171 | anything, but is only generally useful for Objects and Arrays.)
|
172 |
|
173 | ```js
|
174 | data = { menu: { visible: true, position: 'left' } }
|
175 | scour(data).get('menu.visible')
|
176 |
|
177 | list = [ { id: 2 }, { id: 5 }, { id: 12 } ]
|
178 | scour(list).get('0.id')
|
179 | ```
|
180 |
|
181 | __Chaining__:
|
182 | You can use it to start method chains. In fact, the intended use is to keep
|
183 | your root [scour] object around, and chain from this.
|
184 |
|
185 | ```js
|
186 | db = scour({ menu: { visible: true, position: 'left' } })
|
187 |
|
188 | // Elsewhere:
|
189 | menu = db.go('menu')
|
190 | menu.get('visible')
|
191 | ```
|
192 |
|
193 | __Properties__:
|
194 | It the [root], [value] and [keypath] properties.
|
195 |
|
196 | ```js
|
197 | s = scour(obj)
|
198 | s.root // => [scour object]
|
199 | s.value // => raw data (that is, `obj`)
|
200 | s.keypath // => string array
|
201 | ```
|
202 |
|
203 | __Accessing the value:__
|
204 | You can access the raw data using [value].
|
205 |
|
206 | ```js
|
207 | db = scour(data)
|
208 | db.value // => same as `data`
|
209 | db.go('users').value // => same as `data.users`
|
210 | ```
|
211 |
|
212 | ## Attributes
|
213 |
|
214 | These attributes are available to [scour] instances.
|
215 |
|
216 | ### value
|
217 |
|
218 | > `value`
|
219 |
|
220 | The raw value being wrapped. You can use this to terminate a chained call.
|
221 |
|
222 | ```js
|
223 | users =
|
224 | [ { name: 'john', admin: true },
|
225 | { name: 'kyle', admin: false } ]
|
226 |
|
227 | scour(users)
|
228 | .filter({ admin: true })
|
229 | .value
|
230 | // => [ { name: 'john', admin: true } ]
|
231 |
|
232 | ```
|
233 |
|
234 | ### root
|
235 |
|
236 | > `root`
|
237 |
|
238 | A reference to the root [scour] instance.
|
239 | Everytime you traverse using [go()], a new [scour] object is spawned that's
|
240 | scoped to a keypath. Each of these [scour] objects have a `root` attribute
|
241 | that's a reference to the top-level [scour] object.
|
242 |
|
243 | ```js
|
244 | db = scour(...)
|
245 |
|
246 | photos = db.go('photos')
|
247 | photos.root // => same as `db`
|
248 | ```
|
249 |
|
250 | This allows you to return to the root when needed.
|
251 |
|
252 | ```js
|
253 | db = scour(...)
|
254 | artist = db.go('artists', '9328')
|
255 | artist.root.go('albums').find({ artist_id: artist.get('id') })
|
256 | ```
|
257 |
|
258 | ### keypath
|
259 |
|
260 | > `keypath`
|
261 |
|
262 | An array of strings representing each step in how deep the current scope is
|
263 | relative to the root. Each time you traverse using [go()], a new [scour]
|
264 | object is spawned.
|
265 |
|
266 | ```js
|
267 | db = scour(...)
|
268 |
|
269 | users = db.go('users')
|
270 | users.keypath // => ['users']
|
271 |
|
272 | admins = users.go('admins')
|
273 | admins.keypath // => ['users', 'admins']
|
274 |
|
275 | user = admins.go('23')
|
276 | user.keypath // => ['users', 'admins', '23']
|
277 |
|
278 | ```
|
279 |
|
280 | ## Traversal methods
|
281 |
|
282 | For traversing. All these methods return [scour] instances,
|
283 | making them suitable for chaining.
|
284 |
|
285 | ### go
|
286 |
|
287 | > `go(keypath...)`
|
288 |
|
289 | Navigates down to a given `keypath`. Always returns a [scour] instance.
|
290 |
|
291 | ```js
|
292 | data =
|
293 | { users:
|
294 | { 12: { name: 'steve', last: 'jobs' },
|
295 | 23: { name: 'bill', last: 'gates' } } }
|
296 |
|
297 | scour(data).go('users') // => [scour (users)]
|
298 | scour(data).go('users', '12') // => [scour (name, last)]
|
299 | scour(data).go('users', '12').get('name') // => 'steve'
|
300 | ```
|
301 |
|
302 | __Dot notation:__
|
303 | Keypaths can be given in dot notation or as an array. These statements are
|
304 | equivalent.
|
305 |
|
306 | ```js
|
307 | scour(data).go('users.12')
|
308 | scour(data).go('users', '12')
|
309 | scour(data).go(['users', '12'])
|
310 | ```
|
311 |
|
312 | __Non-objects:__
|
313 | If you use it on a non-object or non-array value, it will still be
|
314 | returned as a [scour] instance. This is not likely what you want; use
|
315 | [get()] instead.
|
316 |
|
317 | ```js
|
318 | attr = scour(data).go('users', '12', 'name')
|
319 | attr // => [scour object]
|
320 | attr.value // => 'steve'
|
321 | attr.keypath // => ['users', '12', 'name']
|
322 | ```
|
323 |
|
324 | ### at
|
325 |
|
326 | > `at(index)`
|
327 |
|
328 | Returns the item at `index`. This differs from `go` as this searches by
|
329 | index, not by key.
|
330 |
|
331 | ```js
|
332 | users =
|
333 | { 12: { name: 'steve' },
|
334 | 23: { name: 'bill' } }
|
335 |
|
336 | scour(users).at(0) // => [scour { name: 'steve' }]
|
337 | scour(users).get(12) // => [scour { name: 'steve' }]
|
338 |
|
339 | ```
|
340 |
|
341 | ### filter
|
342 |
|
343 | > `filter(conditions)`
|
344 |
|
345 | Sifts through the values and returns a set that matches given
|
346 | `conditions`. Supports functions, simple objects, and MongoDB-style
|
347 | queries.
|
348 |
|
349 | [query-ops]: https://docs.mongodb.org/manual/reference/operator/query/
|
350 |
|
351 | ```js
|
352 | scour(data).filter({ name: 'john' })
|
353 | scour(data).filter({ name: { $in: ['moe', 'larry'] })
|
354 | ```
|
355 |
|
356 | MongoDB-style queries are supported as provided by [sift.js]. For
|
357 | reference, see [MongoDB Query Operators][query-ops].
|
358 |
|
359 | ```js
|
360 | scour(products).filter({ price: { $gt: 200 })
|
361 | scour(articles).filter({ published_at: { $not: null }})
|
362 | ```
|
363 |
|
364 | ### find
|
365 |
|
366 | > `find(conditions)`
|
367 |
|
368 | Returns the first value that matches `conditions`. Supports MongoDB-style
|
369 | queries. For reference, see [MongoDB Query Operators][query-ops]. Also
|
370 | see [filter()], as this is functionally-equivalent to the first result of
|
371 | `filter()`.
|
372 |
|
373 | [query-ops]: https://docs.mongodb.org/manual/reference/operator/query/
|
374 |
|
375 | ```js
|
376 | scour(data).find({ name: 'john' })
|
377 | scour(data).find({ name: { $in: ['moe', 'larry'] })
|
378 | ```
|
379 |
|
380 | ### first
|
381 |
|
382 | > `first()`
|
383 |
|
384 | Returns the first result as a [scour]-wrapped object. This is equivalent
|
385 | to [at(0)](#at).
|
386 |
|
387 | ### last
|
388 |
|
389 | > `last()`
|
390 |
|
391 | Returns the first result as a [scour]-wrapped object. This is equivalent
|
392 | to `at(len() - 1)`: see [at()] and [len()].
|
393 |
|
394 | ## Reading methods
|
395 |
|
396 | For retrieving data.
|
397 |
|
398 | ### get
|
399 |
|
400 | > `get(keypath...)`
|
401 |
|
402 | Returns data in a given `keypath`.
|
403 |
|
404 | ```js
|
405 | data =
|
406 | { users:
|
407 | { 12: { name: 'steve' },
|
408 | 23: { name: 'bill' } } }
|
409 |
|
410 | scour(data).get('users') // => same as data.users
|
411 | scour(data).go('users').value // => same as data.users
|
412 | ```
|
413 |
|
414 | __Dot notation:__
|
415 | Like [go()], the `keypath` can be given in dot notation.
|
416 |
|
417 | ```js
|
418 | scour(data).get('books.featured.name')
|
419 | scour(data).get('books', 'featured', 'name')
|
420 | ```
|
421 |
|
422 | ### len
|
423 |
|
424 | > `len()`
|
425 |
|
426 | Returns the length of the object or array. For objects, it returns the
|
427 | number of keys.
|
428 |
|
429 | ```js
|
430 | users =
|
431 | { 12: { name: 'steve' },
|
432 | 23: { name: 'bill' } }
|
433 |
|
434 | names = scour(users).len() // => 2
|
435 |
|
436 | ```
|
437 |
|
438 | ### toArray
|
439 |
|
440 | > `toArray()`
|
441 |
|
442 | Returns an array. If the the value is an object, it returns the values of
|
443 | that object.
|
444 |
|
445 | ```js
|
446 | users =
|
447 | { 12: { name: 'steve' },
|
448 | 23: { name: 'bill' } }
|
449 |
|
450 | names = scour(users).toArray()
|
451 | // => [ {name: 'steve'}, {name: 'bill'} ]
|
452 |
|
453 | ```
|
454 |
|
455 | ### values
|
456 |
|
457 | > `values()`
|
458 |
|
459 | Alias for `toArray()`.
|
460 |
|
461 | ### keys
|
462 |
|
463 | > `keys()`
|
464 |
|
465 | Returns keys. If the value is an array, this returns the array's indices.
|
466 |
|
467 | ## Writing methods
|
468 |
|
469 | These are methods for modifying an object/array tree immutably.
|
470 | Note that all these functions are immutable--it will not modify existing
|
471 | data, but rather spawn new objects with the modifications done on them.
|
472 |
|
473 | ### set
|
474 |
|
475 | > `set(keypath, value)`
|
476 |
|
477 | Sets values immutably. Returns a copy of the same object ([scour]-wrapped)
|
478 | with the modifications applied.
|
479 |
|
480 | ```js
|
481 | data = { bob: { name: 'Bob' } }
|
482 | db = scour(data)
|
483 | db.set([ 'bob', 'name' ], 'Robert')
|
484 | // db.value == { bob: { name: 'Robert' } }
|
485 | ```
|
486 |
|
487 | __Immutability:__
|
488 | This is an immutable function, and will return a new object. It won't
|
489 | modify your original object.
|
490 |
|
491 | ```js
|
492 | profile = scour({ name: 'John' })
|
493 | profile2 = profile.set('email', 'john@gmail.com')
|
494 |
|
495 | profile.value // => { name: 'John' }
|
496 | profile2.value // => { name: 'John', email: 'john@gmail.com' }
|
497 | ```
|
498 |
|
499 | __Using within a scope:__
|
500 | Be aware that using all writing methods ([set()], [del()], [extend()]) on
|
501 | scoped objects (ie, made with [go()]) will spawn a new [root] object. If
|
502 | you're keeping a reference to the root object, you'll need to update it
|
503 | accordingly.
|
504 |
|
505 | ```js
|
506 | db = scour(data)
|
507 | book = db.go('book')
|
508 | book.root === db // correct so far
|
509 |
|
510 | book = book.set('title', 'IQ84')
|
511 | book = book.del('sale_price')
|
512 | book.root !== db // `root` has been updated
|
513 | ```
|
514 |
|
515 | __Dot notation:__
|
516 | Like [go()] and [get()], the keypath can be given in dot notation or an
|
517 | array.
|
518 |
|
519 | ```js
|
520 | scour(data).set('menu.left.visible', true)
|
521 | scour(data).set(['menu', 'left', 'visible'], true)
|
522 | ```
|
523 |
|
524 | ### del
|
525 |
|
526 | > `del(keypath)`
|
527 |
|
528 | Deletes values immutably. Returns a copy of the same object
|
529 | ([scour]-wrapped) with the modifications applied.
|
530 |
|
531 | Like [set()], the keypath can be given in dot notation or an
|
532 | array.
|
533 |
|
534 | ```js
|
535 | scour(data).del('menu.left.visible')
|
536 | scour(data).del(['menu', 'left', 'visible'])
|
537 | ```
|
538 |
|
539 | See [set()] for more information on working with immutables.
|
540 |
|
541 | ### extend
|
542 |
|
543 | > `extend(objects...)`
|
544 |
|
545 | Extends the data with more values. Returns a [scour]-wrapped object. Only
|
546 | supports objects; arrays and non-objects will return undefined. Just like
|
547 | [Object.assign], you may pass multiple objects to the parameters.
|
548 |
|
549 | ```js
|
550 | data = { a: 1, b: 2 }
|
551 | data2 = scour(data).extend({ c: 3 })
|
552 | ```
|
553 |
|
554 | ```js
|
555 | data2 // => [scour { a: 1, b: 2, c: 3 }]
|
556 | data2.value // => { a: 1, b: 2, c: 3 }
|
557 | ```
|
558 |
|
559 | See [set()] for more information on working with immutables.
|
560 |
|
561 | ## Utility methods
|
562 |
|
563 | For stuff.
|
564 |
|
565 | ### use
|
566 |
|
567 | > `use(extensions)`
|
568 |
|
569 | Extends functionality for certain keypaths with custom methods.
|
570 | See [Extensions example] for examples.
|
571 |
|
572 | ```js
|
573 | data =
|
574 | { users:
|
575 | { 12: { name: 'steve', surname: 'jobs' },
|
576 | 23: { name: 'bill', surname: 'gates' } } }
|
577 |
|
578 | extensions = {
|
579 | 'users.*': {
|
580 | fullname () {
|
581 | return this.get('name') + ' ' + this.get('surname')
|
582 | }
|
583 | }
|
584 | }
|
585 |
|
586 | scour(data)
|
587 | .use(extensions)
|
588 | .get('users', 12)
|
589 | .fullname() // => 'bill gates'
|
590 | ```
|
591 |
|
592 | __Extensions format:__
|
593 | The parameter `extension` is an object, with keys being keypath globs, and
|
594 | values being properties to be extended.
|
595 |
|
596 | ```js
|
597 | .use({
|
598 | 'books.*': { ... },
|
599 | 'authors.*': { ... },
|
600 | 'publishers.*': { ... }
|
601 | })
|
602 | ```
|
603 |
|
604 | __Extending root:__
|
605 | To bind properties to the root method, use an empty string as the keypath.
|
606 |
|
607 | ```js
|
608 | .use({
|
609 | '': {
|
610 | users() { return this.go('users') },
|
611 | authors() { return this.go('authors') }
|
612 | }
|
613 | })
|
614 | ```
|
615 |
|
616 | __Keypath filtering:__
|
617 | You can use glob-like `*` and `**` to match parts of a keypath. A `*` will
|
618 | match any one segment, and `**` will match one or many segments. Here are
|
619 | some examples:
|
620 |
|
621 | - `users.*` - will match `users.1`, but not `users.1.photos`
|
622 | - `users.**` - will match `users.1.photos`
|
623 | - `users.*.photos` - will match `users.1.photos`
|
624 | - `**` will match anything
|
625 |
|
626 | __When using outside root:__
|
627 | Any extensions in a scoped object (ie, made with [go()]) will be used relative
|
628 | to it. For instance, if you define an extension to `admins.*` inside
|
629 | `.go('users')`, it will affect `users.
|
630 |
|
631 | ```js
|
632 | data = { users: { john: { } }
|
633 | db = scour(data)
|
634 |
|
635 | users = db.go('users')
|
636 | .use({ '*': { hasName () { return !!this.get('name') } })
|
637 |
|
638 | users.go('john').hasName() // works
|
639 | ```
|
640 |
|
641 | While this is supported, it is *not* recommended: these extensions will not
|
642 | propagate back to the root, and any objects taken from the root will not
|
643 | have those extensions applied to them.
|
644 |
|
645 | ```js
|
646 | users.go('john').hasName() // works
|
647 | db.go('users.john').hasName() // doesn't work
|
648 | ```
|
649 |
|
650 | ### toJSON
|
651 |
|
652 | > `toJSON()`
|
653 |
|
654 | Returns the value for serialization. This allows `JSON.stringify()` to
|
655 | work with `scour`-wrapped objects. The name of this method is a bit
|
656 | confusing, as it doesn't actually return a JSON string — but I'm afraid
|
657 | that it's the way that the JavaScript API for [JSON.stringify] works.
|
658 |
|
659 | [JSON.stringify]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON%28%29_behavior
|
660 |
|
661 | ## Iteration methods
|
662 |
|
663 | For traversing.
|
664 |
|
665 | ### forEach
|
666 |
|
667 | > `forEach(function(item, key))`
|
668 |
|
669 | Loops through each item. Supports both arrays and objects. The `item`s
|
670 | passed to the function will be returned as a [scour] instance.
|
671 |
|
672 | ```js
|
673 | users =
|
674 | { 12: { name: 'steve' },
|
675 | 23: { name: 'bill' } }
|
676 |
|
677 | scour(users).each((user, key) => {
|
678 | console.log(user.get('name'))
|
679 | })
|
680 | ```
|
681 |
|
682 | The values passed onto the function are:
|
683 |
|
684 | - `item` - the value; always a scour object.
|
685 | - `key` - the key.
|
686 |
|
687 | The value being passed onto the function is going to be a [scour] object.
|
688 | Use `item.value` or `this` to access the raw values.
|
689 |
|
690 | ### each
|
691 |
|
692 | > `each(fn)`
|
693 |
|
694 | Alias for [forEach](#foreach).
|
695 |
|
696 | ### map
|
697 |
|
698 | > `map(function(item, key))`
|
699 |
|
700 | Loops through each item and returns an array based on the iterator's
|
701 | return values. Supports both arrays and objects. The `item`s passed to
|
702 | the function will be returned as a [scour] instance.
|
703 |
|
704 | ```js
|
705 | users =
|
706 | { 12: { name: 'steve' },
|
707 | 23: { name: 'bill' } }
|
708 |
|
709 | names = scour(users).map((user, key) => user.get('name'))
|
710 | // => [ 'steve', 'bill' ]
|
711 |
|
712 | ```
|
713 |
|
714 | ## Utility functions
|
715 |
|
716 | These are utilities that don't need a wrapped object.
|
717 |
|
718 | ### scour.set
|
719 |
|
720 | > `scour.set(object, keypath, value)`
|
721 |
|
722 | Sets a `keypath` into an `object` immutably.
|
723 |
|
724 | ```js
|
725 | data = { users: { bob: { name: 'john' } } }
|
726 |
|
727 | result = set(data, ['users', 'bob', 'name'], 'robert')
|
728 | // => { users: { bob: { name: 'robert' } } }
|
729 | ```
|
730 |
|
731 | This is also available as `require('scourjs/utilities/set')`.
|
732 |
|
733 | ### scour.del
|
734 |
|
735 | > `scour.del(object, keypath)`
|
736 |
|
737 | Deletes a `keypath` from an `object` immutably.
|
738 |
|
739 | ```js
|
740 | data = { users: { bob: { name: 'robert' } } }
|
741 | result = del(data, ['users', 'bob', 'name'])
|
742 |
|
743 | // => { users: { bob: {} } }
|
744 | ```
|
745 |
|
746 | This is also available as `require('scourjs/utilities/del')`.
|
747 |
|
748 | ### scour.each
|
749 |
|
750 | > `scour.each(iterable, fn)`
|
751 |
|
752 | Iterates through `iterable`, either an object or an array. This is an
|
753 | implementation of `Array.forEach` that also works for objects.
|
754 |
|
755 | This is also available as `require('scourjs/utilities/each')`.
|
756 |
|
757 | ### scour.map
|
758 |
|
759 | > `scour.map(iterable, fn)`
|
760 |
|
761 | Works like Array#map, but also works on objects.
|
762 |
|
763 | This is also available as `require('scourjs/utilities/map')`.
|
764 |
|
765 |
|
766 | [at()]: #at
|
767 | [filter()]: #filter
|
768 | [get()]: #get
|
769 | [go()]: #go
|
770 | [keypath]: #keypath
|
771 | [len()]: #len
|
772 | [root]: #root
|
773 | [scour]: #scour
|
774 | [set()]: #set
|
775 | [value]: #value
|
776 | [use()]: #use
|
777 |
|
778 | [Object.assign]: https://devdocs.io/javascript/global_objects/object/assign
|
779 | [sift.js]: https://www.npmjs.com/package/sift
|
780 | [Redux]: http://rackt.github.io/redux
|
781 | [Immutable.js]: http://facebook.github.io/immutable-js/
|
782 |
|
783 | ## Thanks
|
784 |
|
785 | **scour** © 2015+, Rico Sta. Cruz. Released under the [MIT] License.<br>
|
786 | Authored and maintained by Rico Sta. Cruz with help from contributors ([list][contributors]).
|
787 |
|
788 | > [ricostacruz.com](http://ricostacruz.com) ·
|
789 | > GitHub [@rstacruz](https://github.com/rstacruz) ·
|
790 | > Twitter [@rstacruz](https://twitter.com/rstacruz)
|
791 |
|
792 | [MIT]: http://mit-license.org/
|
793 | [contributors]: http://github.com/rstacruz/scour/contributors
|