npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

IObject

v0.7.2

Published

Immutable Object

Downloads

280

Readme

IObject

An Immutable Object that looks, behaves (and IS) a standard JavaScript Object but with immutable properties.

Upon creation from an existing object, all immediate (not from prototype) enumerable properties are transferred to the IObject.

For immutable arrays, see IArray

Why

One of the cornerstones of functional programming is immutable data structures. Using immutable data structures insures to the author and other programmers that once they have a handle to an object, it won't change beneath their feet. This is important for reasoning about code. It aids with testing, debugging and refactoring. It provides a much faster way to determine if state has changed. And it helps you write pure functions.

Native objects are an extremely popular data structure in most JavaScript programs. But they are far from immutable. One can simply assign values via myObject.foo = 100.

Some libraries exist that provide immutable objects, such as Mori or Immutable - but they are large opinionated libraries that expose a completely different API.

IObject provides an Immutable object only, and is very light.

wc -l IObject.js
110 IObject.js

103 lines in the source file, much of which is comments and the universal module definition. IObject.min.js is currently just 817 bytes.

How

IObject extends Object and adds the non-enumerable set function for setting values (top level and deep values). Because of this approach, IObject appears and behaves just like an object literal with the exception of how you set values.

Note: By default the object does not block standard setting of values. You may set IObject.freeze to either SHALLOW or DEEP to block standard setting of values. 'SHALLOW' only blocks top-level setting of values, whereas DEEP freezes all objects at all levels within the IObject. It is recommended that you set IObject.freeze to DEEP during development to ensure you are not inadvertently setting object values directly.

API

IObject is a standard JavaScript Object and hence inherits all properties and methods of Object. In addition, it has a set function for setting top-level and deep values within the structure.

constructor

Create a new IObject simply by calling the IObject() function. You may optionally use the new keyword, but it makes no difference. You may also pass in an initialization object, whose properties will be copied to the new IObject.

var a = IObject()		// creates a new empty IObject
var b = new IObject()	// Same as above - just stylistic difference
var c = IObject({ a: 1, b: 2, c: 3}) // init IObject with these properties
var d = c.a + c.b + c.c		// d = 6

set(<String> name, value) => IObject

Set the property indicated by name to value. The name is interpreted as a "dotted path" to allow the setting of "deep properties" within the IObject.

IObject.freeze = "DEEP"		// disallow modifying IObject or anything inside
var a = IObject()			// create new empty IObject
console.log(a)				// { }
a.foo = "bar"				// does not effect a. still { }

Notice that setting values directly does not take effect. IObject is immutable and so does not allow changes. You must use set which returns a new IObject with the change in place:

var a = IObject()			// create new empty IObject
var b = a.set("foo","bar")	// creates a NEW IObject with "foo" set to "bar"
console.log(a)				// a = { }
console.log(b)				// b = { "foo": "bar" }

Now lets looks at deep properties - i.e. properties not at the top level of the IObject, but properties on other objects that are stored within an IObject.

var user = IObject({ id: 123, name: "glenn" }) // two top-level properties
user = user.set("address",  // setting object property for "address"
	{ street: "123 Main St.", city: "Yokohama", country: "Japan" })

// We access deep properties just as we would in a standard object
log(user.address.country)	// Japan

// But we set them via the set() call using dotted path string which returns
// the new IObject with the changed property
user = user.set("address.city", "Fujisawa")
log(user.address.city)	// Fujisawa

Note:

Child objects within IObject are "shallow cloned" when their properties are changed, retaining the immutable nature of IObject. When this occurs, child objects are converted to IObject themselves. This is generally desired behavior, but be aware of it. Objects that are not changed are not converted.

One place this may bite you is in an Array. Standard JavaScript Array objects are mutable - if you place one into an IObject and then attempt to change it via set, the array will be converted into an IObject which is probably not intended:

var user = IObject({name: "Glenn", favs: [ 2, 7, 26 ]})
log(user.favs.join(","))  // "2,7,26" as expected
user = user.set("favs.1", 5)
log(user.favs.join(","))  // TypeError: user.favs.join is not a function

If you wish to use an array as part of an immutable data structure, use the IArray - which is immutable, and can be used within an IObject as expected:

var user = IObject({name: "Glenn", favs: IArray([ 2, 7, 26 ])})
log(user.favs.join(","))  // "2,7,26" as expected
user = user.set("favs.1", 5)
log(user.favs.join(","))  // "2,5,26"

License

See the LICENSE file for license rights and limitations (MIT).