From 572d8f7ee27a9e8bb16dd71bd0beb23ff4dd7750 Mon Sep 17 00:00:00 2001 From: Mat Taylor Date: Fri, 14 Oct 2022 17:57:44 -0700 Subject: [PATCH] doc --- README.md | 35 ++++++++++++++++++----------------- bench.js | 2 +- objix.js | 6 +++--- test.js | 40 ++++++++++++++++++++-------------------- 4 files changed, 42 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index fe21d92..0d64093 100644 --- a/README.md +++ b/README.md @@ -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))` @@ -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 diff --git a/bench.js b/bench.js index 27603d1..e1f8298 100644 --- a/bench.js +++ b/bench.js @@ -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) diff --git a/objix.js b/objix.js index 30a9cd6..b5c17c6 100644 --- a/objix.js +++ b/objix.js @@ -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 {} } diff --git a/test.js b/test.js index 804590c..9d3e617 100644 --- a/test.js +++ b/test.js @@ -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') @@ -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') @@ -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 }