Omicron.js
Omicron (“O”) is a small JavaScript library that assists with:
- Performing differential operations on objects
- Facilitating prototypal inheritance
- Selected common tasks: browser-safe typing, functional iteration, etc.
Contents
Installation
O has no dependencies; it can be loaded straight from the source file omicron.js
, or installed via npm:
$ npm install omicron
In node, O will be available in the usual fashion:
var O = ;
In the browser, O will add a single object O
to the global window
(which can subsequently be reclaimed using O.noConflict()
).
Usage
Example: Differential history
Consider a timeline object that efficiently stores history information. The differential functions of O can be used to make this a fairly straightforward task — in the code below, look for applications of functions delta and diff in particular, as well as usage of the special NIL object within the history
array:
var O = ; { var NIL = ONIL history = {} a: 1 b: 2 b: NIL d: 4 a: NIL e: 5 e: 2718 f: 6 index = 0; O;}
Given the information preloaded into history
, we can freely traverse a Timeline
, forward and backward, and manipulate its history along the way. First let’s step forward:
var t = ;tdata; // >>> {}t; // >>> { a:1, b:2 }t; // >>> { a:1, d:4 } // History records 'b: NIL', so key 'b' was deletedt; // >>> { d:4, e:5 } // Likewise, 'a: NIL' caused key 'a' to be deletedt; // >>> { d:4, e:2.718, f:6 }t; // >>> undefined // End of the timelinetdata; // >>> { d:4, e:2.718, f:6 }
Note how the elements of history
are being used to edit the data at history[ index ]
. Note also how the special value NIL
is used to encode that the key to which it’s assigned on the source operand should be deleted as part of the edit to the subject operand.
Next we’ll head back to where we started — but first, let’s glance back into the timeline to see how its contents have changed now that we’re positioned at the front end:
thistory; // >>> [ // { a:NIL, b:NIL }, // { b:2, d:NIL }, // { a:1, e:NIL }, // { e:5, f:NIL }, // { d:4, e:2.718, f:6 } // ]
The data is different, but it still records the exact same information. This is because the history elements are relative, and our perspective has changed after having moved forward
four times — whereas the object initially contained the information needed to step forward in the timeline, viewing the timeline now from index = 4
, its elements instead contain the information needed to step back to the original empty object at index = 0
.
Traversing backward now:
t; // >>> { d:4, e:5 }t; // >>> { a:1, d:4 }t; // >>> { a:1, b:2 }t; // >>> {}t; // >>> undefined // Beginning of the timeline
And since we’ve gone back to where we started, the timeline elements will have transformed themselves to look just like they originally did:
thistory; // >>> [ // {}, // { a:1, b:2 }, // { b:NIL, d:4 }, // { a:NIL, e:5 }, // { e:2.718, f:6 } // ]
Next, let’s try push
ing a new element into the middle of the history:
t; // >>> { a:1, b:2 }t; // >>> { a:1, d:4 }t; // >>> 4 (the new length; `push` drops any forward elements)tdata; // >>> { a:1, b:2, c:3, d:4 } thistory; // >>> [ // { a:NIL, b:NIL }, // { b:2, d:NIL }, // { b:NIL, c:NIL }, // { a:1, b:2, c:3, d:4 } // ]
And finally, let’s replace
an element, and examine its result and effects on the timeline:
t; // >>> { a:1, d:4 } thistory; // >>> [ // { a:NIL, b:NIL }, // { b:2, d:NIL }, // { a:1, d:4 }, // <---------- index // { b:2, c:3 } // ] t;// >>> { a:1, b:NIL, d:4 } thistory; // >>> [ // { a:NIL, b:NIL }, // { a:1, b:2, d:NIL }, // { a:4, b:3, d:1 }, // <----- index // { a:1, b:2, c:3, d:4 } // ]
Calling replace
instates the new element at index
, adjusts the elements ahead and behind of the current index
to reflect the new differentials, and returns the delta of the new element applied against the old element.
API
- Object manipulation and differentiation
- Inheritance
- Typing and inspection
- Iteration
- Array/object composition
- Meta / Miscellaneous
Object manipulation and differentiation
edit
O
Performs a differential operation across multiple objects.
By default, edit
returns the first object-typed argument as subject
, to which the contents of each subsequent source
operand are copied, in order. Optionally the first argument may be either a Boolean deep
, or a whitespace-delimited flags
string containing any of the following keywords:
-
deep
: If asource
property is an object or array, a structured clone is created onsubject
. -
own
: Excludessource
properties filtered byObject.hasOwnProperty
. -
all
: Includessource
properties withundefined
orNIL
values. -
delta
: Returns an anti-delta object reflecting the changes made tosubject
, or if multiplesource
operands are provided, an array of anti-deltas. The anti-delta is comprised of those properties ofsubject
displaced by theedit
operation, along with keys that did not exist onsubject
prior to theedit
operation. This can be used to record a relativistic history for an object: immediately applying a returned anti-delta array in reverse order usingedit('deep', subject, ...)
revertssubject
to its original condition (see example below). -
immutable
: Leavessubject
unchanged. Useful, for example, when accompanied by thedelta
andabsolute
flags to produce a “diff” object. -
absolute
: Processes against all properties insubject
for eachsource
, including those not contained insource
.
Contains techniques and influences from the deep-cloning procedure of jQuery.extend, with which edit
also retains a compatible interface.
Alias: extend
O;// { a:1, b:[ 'alpha', 'beta' ] } O;// { a:1, b:[ 'alpha', 'beta', 'charlie' ] } O;// { a:1, b:[ undefined, 'bravo', 'charlie' ] }
var NIL = ONIL original edits object deltas reversion; original = a: 1 b: '2' c: d: 3 e: 4 g: 0 1 ;edits = a: "uno" a: "un" b: "deux" c: d: "III" e: "IV" a: NIL f: "Foo" b: "dos" g: undefined "une" ; object = O;// { b: "dos",// c: {// d: "III",// e: "IV"// },// f: "Foo",// g: [ 0, "une" ] } deltas = Oedit;// [ { a: 1 },// { a: "uno", b: "2" },// { c: { d: 3, e: 4 } },// { a: "un", f: NIL },// { b: "deux", g: [ undefined, 1 ] } ] reversion = Oedit;// { a: 1,// b: "2",// c: {// d: 3,// e: 4// },// g: [ 0, 1 ] } O; // >>> true
See also: clone, delta, diff, assign
clone
O
The deep all
specialization of edit
: creates a new object or array and deeply copies properties from all source
operands.
var subject = a:1 b: 'alpha' 'beta' c: d:1 object = O; subject === object; // >>> falsesubjectb === objectb; // >>> falsesubjectb0 === objectb0; // >>> truesubjectc === objectc; // >>> falsesubjectcd === objectcd; // >>> true
See also: edit
delta
O
The deep delta
specialization of edit
: deeply copies each source
operand into subject
, and returns the anti-delta of the operation. In the case of multiple source
operands, an array of anti-deltas is returned.
The returned anti-delta object records the displaced values of properties of subject
updated or deleted as a result of the operation, and — using the NIL
entity — the prior nonexistence of properties that were added to subject
as a result of the operation. Performing a successive delta
or deep-edit
operation on subject
, this time providing the anti-delta returned by the first operation as the source
for the second operation, causes subject
to be restored to its original condition.
For any plain-objects subject
and object
, delta
asserts that the following function will always evaluate to true
:
{ var clone = O delta = O edit = O; return O && O;}
Example
var NIL = ONIL subject = a:1 b: 'alpha' 'beta' c: d:1 object = b: undefined 'bravo' 'charlie' c: d:NIL e:2 delta = O; subject; // >>> { a:1, b:[ 'alpha', 'bravo', 'charlie' ], c:{ e:2 } }delta; // >>> { b:[ undefined, 'beta', NIL ], c:{ d:1, e:NIL } } O; // >>> { a:1, b:[ 'alpha', 'beta' ], c:{ d:1 } }
diff
O
The deep absolute immutable delta
specialization of edit
: performs a deep comparison of each source
operand against subject
, and returns an absolute anti-delta, or in the case of multiple source
operands, an array of absolute anti-deltas. Unlike the delta
function, diff
leaves subject
unaffected.
For any plain objects subject
and object
, diff
asserts that the following function will always evaluate to true
:
{ var diff = O edit = O; return O;}
Example
var subject = a:1 b: 'alpha' 'beta' c: d:1 object = b: 'alpha' 'bravo' c: e:2 ; O; // >>> { a:1, b:[ undefined, 'beta' ], c:{ d:1, e:NIL } }
assign
O
Performs batch assignments of values to one or more keys of an object.
O;// { a:1, b:1, c:2, d:2, e:2, f:2, g:3, h:3, i:3 } O;// { a:1, b:1, c:2 } O;// { a: 42, b: 42, c: 42 } O;// { a: 'a', b: 'b', c: 'c' }
alias
O
Within object
, copies a value from one key to one or more other keys.
O;// { a:1, b:1, c:2, d:2, e:2, f:2, g:3, h:3, i:3 } var object = { /* ... */ } { /* ... */ };O;object;
Return to: Object manipulation and differentiation < API < top
Inheritance
create
Object.create
, or partial shim.
inherit
O
Properly arranges the prototypal inheritance relation between a child
constructor and a parent
constructor, additionally copies any “static” properties of parent
to child
, and returns the child
.
-
child
andparent
are constructor functions. -
properties
: (optional) an object containing properties to be added to the prototype ofchild
. -
statics
: (optional) is an object containing properties to be added tochild
itself.
{}Animalprototype { return 'om nom nom';}; O; {}Birdoviparous = true;Birdprototype { return 'tweet';}; O; {}Chickenprototype { return 'cluck';}; Chickenoviparous; // truevar c = ;c; // "om nom nom"c; // "cluck"
getPrototypeOf
Object.getPrototypeOf
, or partial shim.
Return to: Inheritance < API < top
Typing and inspection
type
Otype object
Returns the lowercase type string as derived from toString
.
isNumber
O
Returns true
if number
is a valid numeric value.
isArray
O
Returns true
if array
is a proper Array
.
isError
O
Returns true
if e
is an Error
.
isPlainObject
O
Returns false
for non-objects, null
, arrays, constructed objects, the global object, and DOM nodes (a near-identical port from jQuery).
The
isPlainObject
test is especially useful for deep-cloning routines, like those employed in theedit
/extend
family of functions, which pass over objects that may carry some state hidden in a constructor or similar, which cannot be cloned.
isEmpty
O
Returns a boolean indicating whether the object or array at object
contains any members. For an Object
type, if andPrototype
evaluates to true
, then object
must also be empty throughout its prototype chain.
isEqual
O
Performs a deep equality test between two objects.
var subject = a:1 b: 'alpha' 'beta' c: d:1 ; O;// >>> trueO;// >>> true O;// >>> trueO;// >>> false
has
O
Retrieves the value at the location indicated by the provided path
string inside a nested object object
.
var object = a: b:42 ;O; // >>> trueO; // >>> trueO; // >>> false
lookup
O
Retrieves the value at the location indicated by the provided path
string inside a nested object object
.
var object = a: b:42 ;O; // >>> { b:42 }O; // >>> 42O; // >>> undefined
Return to: Typing and inspection < API < top
Iteration
each
O
Functional iterator with jQuery-style callback signature of key, value, object
.
O;O;
forEach
O
Functional iterator with ES5-style callback signature of value, key, object
. If available, delegates to the native Array.prototype.forEach
when appropriate.
O;O;
Return to: Iteration < API < top
Array/Object composition
flatten
O
array
:Array
Returns an array that contains the extracted elements of any nested arrays within array
.
indexOf
O
array
:Array
sought
: var- [
startIndex = 0
] : number
Searches for the sought
element within array
, beginning at startIndex
, and returns its index. Returns -1
if the element is not found.
unique
Alias: uniq
O
array
:Array
Returns an array that is the set of unduplicated elements of array
.
keys
O
Returns an object’s keys in an ordered string array.
invert
O
For an array
whose values are unique key strings, this returns an object that is a key-value inversion of array
.
Return to: Array/Object composition < API < top
Meta / Miscellaneous
env
Environment variables.
server
:true
if the environment conforms to the CommonJS module system (e.g., node.js).client
:true
in the case of awindow
ed environment (e.g. browser).debug
:false
. Changing this has no built-in effect. May be coded against by dependent libraries for their own purposes.
noConflict
Returns control of the global O
property to its original value.
regexp
An object in which to store regular expressions for reuse.
NIL
ONIL
NIL
is a special object used only for its unique reference. Whereas the null
entity connotes “no object”, and the undefined
value connotes “no value”, when encountered as a property value of some object, the NIL
reference specifically implies “no existence” of a corresponding property on some other related object.
The prime example is its use within edit and the related differential operation functions, where, within a given operand, a property whose value is set to NIL
indicates the absence of or intent to delete the corresponding property on an associated operand.
noop
A reusable function that returns undefined
.
getThis
A reusable function that returns this
.
thunk
O
Returns a lazy evaluator function that closes over and returns the provided object
argument.
hasOwn
Object.prototype.hasOwnProperty
toString
Object.prototype.toString
slice
Array.prototype.slice
trim
String.prototype.trim
, or shim.
randomHex
O
Returns a random hex string of arbitrary length
valueFunction
O
Cyclically references a function’s output as its own valueOf
property.
Return to: Meta / Miscellaneous < API < top
About this project
Return to: top