DEV Community

azu
azu

Posted on

3 2

Get immutable versions of Array methods

Have you ever thought about immutable version of Array.prototype methods?
For example, Array.prototype.push return a new Array instead of number of items.

I've created immutable-array-prototype package.

Why immutable?

ECMAScript Array has some mutable methods.

Mutable vs Immutable

For example, Redux require Immutable Update on your Store implementation.

Object.assign or object spread({ ...object }) can realize immutable updating for Object. But, immutale updating on Array is difficult.

Of course, Immutable.js is useful. But Immutable.js is very large library.

So, I want to get minimal and easy to use library.

@immutable-array/prototype

@immutable-array/prototype includes immutable version of theses Array.prototype methods.

npm install @immutable-array/prototype
Enter fullscreen mode Exit fullscreen mode

Or, If you want to a single method, you can use a method as independent package.

npm install @immutable-array/pop
npm install @immutable-array/push
npm install @immutable-array/shift
npm install @immutable-array/unshift
npm install @immutable-array/sort
npm install @immutable-array/reverse
npm install @immutable-array/fill
npm install @immutable-array/splice
npm install @immutable-array/copy-within
Enter fullscreen mode Exit fullscreen mode

Example

This library provide same API and behavior without first argument.

import {
  sort,
  unshift,
  push,
  fill,
  splice,
  pop,
  reverse,
  copyWithin,
  shift
} from '@immutable-array/prototype';
describe('prototype', () => {
  it('shift', () => {
    assert.deepStrictEqual(shift(['a', 'b', 'c', 'd', 'e']), [
      'b',
      'c',
      'd',
      'e'
    ]);
  });
  it('unshift', () => {
    assert.deepStrictEqual(unshift(['a', 'b', 'c', 'd', 'e'], 'x'), [
      'x',
      'a',
      'b',
      'c',
      'd',
      'e'
    ]);
  });
  it('pop', () => {
    assert.deepStrictEqual(pop(['a', 'b', 'c', 'd', 'e']), [
      'a',
      'b',
      'c',
      'd'
    ]);
  });
  it('push', () => {
    assert.deepStrictEqual(push(['a', 'b', 'c', 'd', 'e'], 'x'), [
      'a',
      'b',
      'c',
      'd',
      'e',
      'x'
    ]);
  });
  it('splice', () => {
    assert.deepStrictEqual(splice(['a', 'b', 'c', 'd', 'e'], 0, 1, 'x'), [
      'x',
      'b',
      'c',
      'd',
      'e'
    ]);
  });
  it('sort', () => {
    assert.deepStrictEqual(sort(['e', 'a', 'c', 'b', 'd']), [
      'a',
      'b',
      'c',
      'd',
      'e'
    ]);
  });
  it('reverse', () => {
    assert.deepStrictEqual(reverse(['a', 'b', 'c', 'd', 'e']), [
      'e',
      'd',
      'c',
      'b',
      'a'
    ]);
  });
  it('fill', () => {
    assert.deepStrictEqual(fill(new Array(5), 'x'), ['x', 'x', 'x', 'x', 'x']);
  });
  it('copyWithin', () => {
    assert.deepStrictEqual(copyWithin(['a', 'b', 'c', 'd', 'e'], 0, 3, 4), [
      'd',
      'b',
      'c',
      'd',
      'e'
    ]);
  });
});
Enter fullscreen mode Exit fullscreen mode

Use Case

Faao that is GitHub Issue application use @immutable-array/prototype for creating domain model.
Faao apply DDD/CQRS pattern using Almin. Immutable domain model help to work application in safety.

Policy

@immutable-array/prototype has a support policy.

Do

  • Provide immutable version of Array.prototype method
  • Provide each method as an module
    • For exaple, import push from "@immutable-array/push"
    • All prototype method: import { push } from "@immutable-array/prototype"
  • ECMAScript compatible API without first arguments

For example, @immutable-array/* method should return same result with native API.

import { splice } from '@immutable-array/splice';
var array = [1, 2, 3];
// immutable
var resultArray = splice(array, -1, 1, 'x');
// native
array.splice(-1, 1, 'x');
assert.deepStrictEqual(array, resultArray);
Enter fullscreen mode Exit fullscreen mode

Do not

  • Should not add non-standard method in ECMAScript
    • For example, It does not provide update, delete, merge methods.
  • Each method should not depended on other method

Finally

Pull requests and stars are always welcome :)

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (1)

Collapse
 
prodigalknight profile image
RevanProdigalKnight • Edited

pop, push, shift, unshift, and splice are not, and never were intended to be, immutable methods. The intended use of these is to allow JavaScript arrays to emulate a Stack or Queue object without needing to actually define a separate object in the language. Notably, pop, shift, and splice return the element(s) removed from the array, if any, so that they can be used in certain kinds of loops, i.e.:

const arr = [1, 2, 3, 4, 5];

while (arr.length > 0) {
  const element = arr.pop();

  if (element % 2 === 0) {
    arr.push(element + 1);
  }
}

Now, this is a rather simplistic example, but when trying to navigate the layers of a tree in a dynamic fashion (rather than using recursion), the pattern becomes very useful:

const nodes = [node];

while (nodes.length > 0) {
  const n = nodes.pop();

  /* do something with the node */

  if (node.hasChildren()) {
    nodes.push(...node.getChildren());
  }
}

Your immutable replacements for this would not be usable in this case as they are now.

I would suggest that your immutable replacements for these functions return an array consisting of the new array in the first element and then what the result of the non-immutable original function would be in the second element, e.g.:

import { pop } from '@immutable-array/pop';
import { push } from '@immutable-array/push';
const arr = [1, 2, 3, 4, 5];

const popResult = pop(arr);

console.log(popResult); // [[1, 2, 3, 4], 5]

const pushResult = push(arr, 6);

console.log(pushResult); // [[1, 2, 3, 4, 5, 6], 6]

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Instrument, monitor, fix: a hands-on debugging session

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️