Skip to content

Commit

Permalink
doc
Browse files Browse the repository at this point in the history
  • Loading branch information
Mat Taylor authored and Mat Taylor committed Oct 15, 2022
1 parent 23c9846 commit 572d8f7
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 41 deletions.
35 changes: 18 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@ A dangerously convienient, high performance, zero dependency, lightweight utilit

The functions are non enumerable and include copies of Object class methods and Array prototype methods that are applied to the values of the object as well others inspired by lodash and some extras to delete keys, clean entries, stringify, compare, split and join objects as well as logging, iterating, type checking, and trapping and observing updates.

The methods are highly optimised with zero copy operations where possible. There is however very limited type checking to guard against unwanted side effects. When combined with the faster startup times for using prototypes, performance in most cases is signifantly faster than lodash equivalents. (eg `ob.map(fn)` can be up to 50% faster than `_.mapValues(ob, fn)` when working with small objects according to simple ops/sec [benchmarks](bench.js)

### Ops/sec (iters: 1000, heats: 10 size: 10)

| Function | Objix | Lodash | % Imp | % Err |
| -------- | ------- | ------ | ------- | ----- |
| Map | 2495.9 | 1702.7 | 46.58 | 42.64 |
| Filter | 1096.4 | 94 | 1066.38 | 13.69 |
| Find | 13985.6 | 3564.7 | 292.34 | 72.58 |
| KeyBy | 5492.2 | 2762.3 | 98.83 | 57.02 |
| Equals | 784.4 | 475.3 | 65.03 | 18.98 |
| Clone | 997.5 | 941.3 | 5.97 | 15.83 |
| Some | 2920.1 | 2024.6 | 44.23 | 37.38 |
| Every | 5084.8 | 3236.8 | 57.09 | 41.47 |
The methods are highly optimised with zero copy operations where possible. There is however very limited type checking to guard against unwanted side effects. When combined with the faster startup times for using prototypes, performance in most cases is signifantly faster than lodash equivalents. (eg `ob.map(fn)` is typically over 60% faster than `_.mapValues(ob, fn)` when working with small objects according to simple ops/sec [benchmarks](bench.js)

### Ops/sec (iters: 1000, heats: 100 size: 10)

| (index) | vanilla | lodash | objix | % Inc | % Err |
| ------- | -------- | -------- | -------- | ------ | ----- |
| Map | 1084.23 | 4215.8 | 6941.94 | 64.66 | 15.07 |
| Filter | 1566.3 | 1201.28 | 1457.21 | 21.3 | 6.82 |
| Find | 17400.43 | 26744.94 | 75851.68 | 183.61 | 27.38 |
| KeyBy | | 6361.6 | 9369.4 | 47.28 | 20.64 |
| Equals | 1446.42 | 1355.97 | 1851.67 | 36.56 | 8.96 |
| Clone | 8007.95 | 2069.4 | 6111.26 | 195.32 | 10.09 |
| Deep | | 1414.29 | 2536.6 | 79.36 | 11.61 |
| Some | 5864.38 | 3942.79 | 6598.18 | 67.35 | 12.51 |
| Every | 24470.23 | 8003.35 | 11248.07 | 40.54 | 15.06 |

**NOTE:** Messing with Object prototypes may have unintended consequences in larger applications, on the upside however just think of all the fun key strokes you could save by typing something like
`ob.map(fun)` instead of `for (let key in Object.keys(ob) ob[key] = fun(ob[key], key))`
Expand Down Expand Up @@ -60,12 +61,12 @@ Most of these function return objects including those modifying `this` and so ca

### Function Aliases

All functions documented below are also callable with a '\_' prefix to the function name.
All functions documented below are also callable with a '\_\_' prefix to the function name.
This can help ensure that the function is availble and not overwritten by other object property assignments.

```javascript
{ a: 1 }.size() == { a: 1 }._size() //true
{ a: 1 }.find(v => v) == { a: 1 }._find(v => v) //true
{ a: 1 }.size() == { a: 1 }.__size() //true
{ a: 1 }.find(v => v) == { a: 1 }.__find(v => v) //true
```

### Exported Functions
Expand Down
2 changes: 1 addition & 1 deletion bench.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,6 @@ function report(title, ob) {
const d1 = new Date()
const d2 = new Date()
const testOb = { }
testOb.deep = { a: { b: [ 1,2,3,d1, { c: 0, d: d2 }], e:1, f:2, g: 3, h: 4, i: 5, j: 6}}
//testOb.deep = { a: { b: [ 1,2,3,d1, { c: 0, d: d2 }], e:1, f:2, g: 3, h: 4, i: 5, j: 6}}
for (let i=1; i <= oSize; i++) testOb['k'+i] = i
report(`Ops/sec (iters: ${iters}, heats: ${heats} size: ${oSize})`, testOb)
6 changes: 3 additions & 3 deletions objix.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ P.trap = function(f, e, ...p) {
})
}

for (let f of K(P)) if (f[0] != '_') {
[f, '__'+f].map(f => Object.defineProperty(P, f, { enumerable: false, value: P[f] }))
try { module.exports[f] = (o, ...args) => o['__'+f](...args) } catch {}
for (let p of K(P)) if (p[0] != '_') {
[p, '__'+p].map(f => Object.defineProperty(P, f, { enumerable: false, value: P[p] }))
try { module.exports[p] = (o, ...args) => o['__'+p](...args) } catch {}
}
40 changes: 20 additions & 20 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ let o3 = { a: 2, b: 2, c: 3}
let o4 = { a: 2, b: 2, c: 3, d: 4}

console.assert(o1.equals({a: 1}), 'Equals')
console.assert(o1._equals({a: 1}), '_Equals')
console.assert(o1.__equals({a: 1}), '_Equals')
console.assert(!o1.equals({a: 2}), '!Equals')

console.assert({a:1}.equals({a: 1}), 'Equals')
Expand All @@ -26,65 +26,65 @@ console.assert(!'string'.equals(''), '!Equals (String)')


console.assert(o2.contains(o1), 'Contains')
console.assert(o2._contains(o1), '_Contains')
console.assert(o2.__contains(o1), '_Contains')
console.assert(!o1.contains(o2), '!Contains')

console.assert(o1.map(_ => _+1).a === 2, 'Map')
console.assert(o1._map(_ => _+1).a === 2, '_Map')
console.assert(o1.__map(_ => _+1).a === 2, '_Map')
console.assert(o1.map(_ => _+1).a != o1.a, '!Map')

//console.assert(o1.apply(_ => _-1) && o1.a === 0, 'Apply')

console.assert(o2.find(_ => _ > 1) === 'b', 'Find')
console.assert(o2._find(_ => _ > 1) === 'b', '_Find')
console.assert(o2.__find(_ => _ > 1) === 'b', '_Find')
console.assert(!o2.find(_ => _ > 3), '!Find')

console.assert(o3.filter(_ => _ < 3).equals({ a: 2, b: 2 }), 'Filter')
console.assert(o3._filter(_ => _ < 3).equals({ a: 2, b: 2 }), '_Filter')
console.assert(o3.__filter(_ => _ < 3).equals({ a: 2, b: 2 }), '_Filter')
console.assert(o3.filter(_ => _ < 0).equals({}), '!Filter')

console.assert({a:1,b:2}.common({b:2,c:3}).equals({b:2}), 'Common')
console.assert({a:1,b:2}._common({b:2,c:3}).equals({b:2}), '_Common')
console.assert({a:1,b:2}.__common({b:2,c:3}).equals({b:2}), '_Common')
console.assert({a:1,b:2}.common({b:3}).equals({}), '!Common')

console.assert({a:1}.size() == 1, 'Size')
console.assert({a:1}._size() == 1, '_Size')
console.assert({a:1}.__size() == 1, '_Size')
console.assert(!{}.size(), '!Size')

console.assert(o3.assign({d:4}).equals(o4) && o3.equals(o4), 'Assign')
console.assert(o3._assign({d:4}).equals(o4) && o3.equals(o4), '_Assign')
console.assert(o3.__assign({d:4}).equals(o4) && o3.equals(o4), '_Assign')

//console.assert(o3.patch({d:4}) && o3.equals(o4), 'Patch')
//console.assert(o3._patch({d:4}) && o3.equals(o4), '_Patch')
//console.assert(o3.__patch({d:4}) && o3.equals(o4), '_Patch')

console.assert(o3.delete('d','c','b') && o3.equals({a:2}), 'Delete')
console.assert(o3._delete('d','c','b') && o3.equals({a:2}), '_Delete')
console.assert(o3.__delete('d','c','b') && o3.equals({a:2}), '_Delete')
console.assert(o3.delete('d','c','b') && !o3.equals({d:2}), '!Delete')

console.assert(o4.clone().equals(o4), 'Clone 1', o4)
let c0 = {a:1, b:{c:{d:1}}}.clone(-1)
console.assert(c0.equals({a:1,b:{c:{ d:1}}}, -1), 'Clone 2', c0)
console.assert(o4._clone().equals(o4), '_Clone')
console.assert(o4.__clone().equals(o4), '_Clone')

console.assert(o4.clone() != o4, '!Clone', o4)

console.assert({a:1}.join({a:2}).a[1] == 2, 'Join')
console.assert({a:1}._join({a:2}).a[1] == 2, '_Join')
console.assert({a:1}.__join({a:2}).a[1] == 2, '_Join')

console.assert({a: [1,2]}.split(), 'Split')
console.assert({a: [1,2]}._split(), '_Split')
console.assert({a: [1,2]}.__split(), '_Split')

let r = {a: 1}.flatMap((k,v) => [[k+1, v+1],[k+2, v+2]])
console.assert(r.equals({a1: 2, a2: 3}), 'FlatMap', r)

let _r = {a: 1}._flatMap((k,v) => [[k+1, v+1],[k+2, v+2]])
let _r = {a: 1}.__flatMap((k,v) => [[k+1, v+1],[k+2, v+2]])
console.assert(_r.equals({a1: 2, a2: 3}), '_FlatMap', _r)

console.assert({a: 0, b: 2, c: null}.clean().equals({b:2}), 'Clean')
console.assert({a: 0, b: 2, c: null}._clean().equals({b:2}), '_Clean')
console.assert({a: 0, b: 2, c: null}.__clean().equals({b:2}), '_Clean')

console.assert([].is(Array), 'isArray')
console.assert([]._is(Array), '_isArray')
console.assert([].__is(Array), '_isArray')
console.assert(!{}.is(Array), '!isArray')

console.assert({a:1, b:1}.equals({a:1, b:[1]}), 'Equals Array')
Expand All @@ -93,20 +93,20 @@ console.assert({a:1, b:[1,2]}.equals({a:1, b:[1,2]}, true), 'Deep Equals Array')
console.assert(!{a:1, b:{c:1}}.equals({a:1, b:{c:2}}, true), '!Deep Equals Object')
console.assert({a:1, b:{c:1}}.equals({a:1, b:{c:1}}, true), 'Deep Equals Object')
console.assert({a:1, b:[{c:1}, {c:2}]}.equals({a:1, b:[{c:1}, {c:2}]}, -1), 'Deep Equals Mixed')
console.assert({a:1, b:[{c:1}, {c:2}]}._equals({a:1, b:[{c:1}, {c:2}]}, -1), '_Deep Equals Mixed')
console.assert({a:1, b:[{c:1}, {c:2}]}.__equals({a:1, b:[{c:1}, {c:2}]}, -1), '_Deep Equals Mixed')

console.assert({a:1, b:2}.some(v => v > 1), 'Some')
console.assert({a:1, b:2}._some(v => v > 1), '_Some')
console.assert({a:1, b:2}.__some(v => v > 1), '_Some')
console.assert(!{a:1, b:2}.some(v => v > 2),'!Some')

console.assert({a:1, b:2}.every(v => v > 0), 'Every')
console.assert({a:1, b:2}._every(v => v > 0), '_Every')
console.assert({a:1, b:2}.__every(v => v > 0), '_Every')
console.assert(!{a:1, b:2}.every(v => v > 1),'!Every')

let x = {}.keyBy([{ a: 'o1' }, { a: 'o2' }, { a: 'o2', b: 1 }], 'a')
console.assert(x.equals({ o1: { a: 'o1' }, o2: [ { a: 'o2', b: 1 }, { a: 'o2' } ]}, -1), 'KeyBy')

let _x = {}._keyBy([{ a: 'o1' }, { a: 'o2' }, { a: 'o2', b: 1 }], 'a')
let _x = {}.__keyBy([{ a: 'o1' }, { a: 'o2' }, { a: 'o2', b: 1 }], 'a')
console.assert(x.equals({ o1: { a: 'o1' }, o2: [ { a: 'o2', b: 1 }, { a: 'o2' } ]}, -1), '_KeyBy')

let _y = { a: 1, b: 2 }
Expand Down

0 comments on commit 572d8f7

Please sign in to comment.