obj.mjs provides tools for manipulating JS objects in weird ways.
import * as o from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/obj.mjs'
Links: source; test/example.
Signature: (tar, src) => tar
.
Similar to Object.assign
. Differences:
- Much faster.
- Exactly two parameters, not variadic.
- Sanity-checked:
Similar to #patch
but doesn't check for inherited and non-enumerable properties. Simpler, dumber, faster.
Links: source; test/example.
Signature: (tar, src) => tar
.
Similar to Object.assign
. Differences:
- Much faster.
- Takes only two args.
- Sanity-checked:
When overriding inherited and non-enumerable properties is desirable, use #assign
.
Links: source; test/example.
Superclass for classes representing a "struct" / "model" / "record". Also see #StructLax
. Features:
-
Supports property declarations, with validation/transformation functions.
-
Can be instantiated or mutated from any struct (any dict-like object).
-
Assigns and checks all declared properties when instantiating via
new
. Ignores undeclared properties. -
Assigns and checks all declared properties when mutating via
.mut
with a non-nil argument. Ignores undeclared properties. -
When mutating an existing struct via
.mut
, supports calling method.mut
on existing property values which implement #the. This allows deep/recursive mutation. -
Uses regular JS properties. Does not use getters/setters, proxies, private properties, non-enumerable properties, symbols, or anything else "strange". Declared properties are simply assigned via
=
.
Performance characteristics:
-
The cost of instantiating or mutating depends only on declared properties, not on provided properties.
-
When the number of declared properties is similar to the number of provided properties, this tends to be slightly slower than
Object.assign
or #assign
. -
When the number of declared properties is significantly smaller than the number of provided properties, this tends to be faster than the aforementioned assignment functions.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/lang.mjs'
import * as o from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/obj.mjs'
class Person extends o.Struct {
static spec = {
id: l.reqFin,
name: l.reqStr,
}
}
// Fails the type check.
new Person({id: 10})
/* Uncaught TypeError: invalid property "name" */
// Fails the type check.
new Person({name: `Mira`})
/* Uncaught TypeError: invalid property "id" */
// Satisfies the type check.
new Person({id: 10, name: `Mira`})
/* Person { id: 10, name: "Mira" } */
// Ignores undeclared properties.
new Person({id: 10, name: `Mira`, slug: `mira`, gender: `female`})
/* Person { id: 10, name: "Mira" } */
Links: source; test/example.
Superclass for classes representing a "struct" / "model" / "record". Subclass of #Struct
with added support for undeclared properties.
Differences from #Struct
:
-
When instantiating via
new
or mutating via.mut
, in addition to assigning and checking all declared properties, this also copies any undeclared properties present in the source data.-
Behaves similarly to #
patch
, and differently fromObject.assign
or #assign
. Avoids accidentally shadowing inherited or non-enumerable properties. -
Just like with declared properties, copying undeclared properties supports deep/recursive mutation by calling
.mut
on any existing property values that implement #the.
-
-
Measurably worse performance.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/lang.mjs'
import * as o from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/obj.mjs'
class Person extends o.StructLax {
static spec = {
id: l.reqFin,
name: l.reqStr,
}
}
// Fails the type check.
new Person({id: 10})
/* Uncaught TypeError: invalid property "name" */
// Fails the type check.
new Person({name: `Mira`})
/* Uncaught TypeError: invalid property "id" */
// Satisfies the type check.
new Person({id: 10, name: `Mira`})
/* Person { id: 10, name: "Mira" } */
// Assigns undeclared properties in addition to declared properties.
new Person({id: 10, name: `Mira`, slug: `mira`, gender: `female`})
/* Person { id: 10, name: "Mira", slug: "mira", gender: "female" } */
Links: source; test/example.
Takes a class and hacks its prototype, converting all non-inherited getters to lazy/memoizing versions of themselves that only execute once. The resulting value replaces the getter. Inherited getters are unaffected.
import * as o from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/obj.mjs'
class Bucket {
static {o.memGet(this)}
get one() {return new o.StructLax()}
get two() {return new o.StructLax()}
}
const ref = new Bucket()
// Bucket {}
ref.one.three = 30
ref
// Bucket { one: Struct { three: 30 } }
ref.two.four = 40
ref
// Bucket { one: Struct { three: 30 }, two: Struct { four: 40 } }
The following APIs are exported but undocumented. Check obj.mjs.
function isObjKey
function reqObjKey
function isMut
function reqMut
class StructType
class StructTypeLax
function MixMain
class Strict
class BlankStaticPh
class StrictStaticPh
class MakerPh
class Dyn
class TypedDyn
class WeakTag
class MemTag
class Cache
class WeakCache
class StaticCache
class StaticWeakCache
class MixinCache
class DedupMixinCache
const parentNodeKey
function MixChild
class MixChildCache
function MixChildCon
class MixChildConCache
function pub
function priv
function final
function getter
function setter
function getSet