plain-immutable
Version:
Make plain json data(array and object) immutable
118 lines (97 loc) • 5.3 kB
Markdown
Make plain json data(array and object) immutable
=================================
It's using `Object.freeze()` and `Object.defineProperty()` to achieve immutability. See compatible on [compat-table](https://kangax.github.io/compat-table/es5/)(shortly IE9+).
Should only work for json data, not function, date and other user-defined/third-party-defined object. In short, it could be the replacement of `array([])` and `plain object({})`.
### Example
```js
import immutable from 'plain-immutable';
const arr = immutable([1, 2, { a: 'b' }]);
arr[0] = -1; // it will throw
arr[2].a = 'c'; // it will throw too even you want to change the nested object
console.log(arr[2].a);// b
console.log(JSON.stringify(arr));// [1,2,{"a":"b"}]
const mArr = arr.set(0, -1);
console.log(arr[0]);// 1
console.log(mArr[0]);// -1
```
### Static Methods
#### immutable(value)
*Alias immutable.fromJSON(), immutable.fromJS()*
Make the value immutable, only for array and plain object. If you pass a literal value(string, number or boolean) or other types, It will do nothing and return itself. The value will be deeply made immutable, no copy.
```js
import immutable from 'plain-immutable';
const arr = [{ a: 1 }];
const arr1 = immutable(arr);
console.log(arr === arr1);// true
```
#### isImmutable(value: any)
*Alias immutable.isImmutable()*
True if the value is an immutable array or object.
```js
import immutable, {isImmutable} from 'plain-immutable';
console.log(immutable.isImmutable(1)); // false
console.log(isImmutable(1)); // false
console.log(isImmutable(true)); // false
console.log(isImmutable('a')); // false
console.log(isImmutable({})); // false
console.log(isImmutable([])); // false
console.log(isImmutable(Object.create(null))); // false
console.log(isImmutable(immutable({}))); // true
console.log(isImmutable(immutable([]))); // true
console.log(isImmutable(immutable(Object.create(null)))); // true
```
### Additional Instace Methods
These methods are applied to both immutable object and immutable array. So make sure that your object don't have these properties.
#### .set(key: string, value: json|function)
Same like `.setIn(key, value)`, but only allow string type key
#### .setIn(keyPath: string|array, value: json|function)
Return a new immutable copy having set the value at leaf key of key path. If any key in the path is not existent, create a plain object at that key. You can pass a function(setter) which will be used to generate new value at the leaf key.
```js
const obj = immutable({ a: 1, nums: [] });
const obj1 = obj.set('a', 2); // {a: 2, nums: []}
const obj2 = obj.setIn(['nums'], nums => nums.push(1)); // {a: 1, nums: [1]}
```
#### .remove(key: string)
*Alias .delete()*
Same like `.removeIn(key)`, but only allow string type key
#### .removeIn(keyPath: string|array)
*Alias .deleteIn()*
Return a new immutable copy having removed the value at leaf key of key path. If any key in the path is not existent, nothing will be changed.
```js
const obj = immutable({ a: 1, nums: [1] });
const obj1 = obj.remove('a'); // {nums: [1]}
const obj2 = obj.removeIn(['nums', 0]); // {a: 1, nums: []}
```
#### .merge(strategy?: boolean|function, value: json)
Return a new immutable copy having merged with the value by the strategy. Strategy is used to deal conflicts(same key but different values). There are three types of strategy:
* false(or not specified): Old value will be overwriten
* true: Deeply merge if the two values are with same type(array or object)
* function: Called a merger with `(prev, next, key)=>any`. It will be invoked on each conflicted key.
```js
const arr = immutable([1, { a: 2, b: 3 }]);
console.log(arr.merge([-1, { c: 4 }])); // [-1, {c: 4}]
console.log(arr.merge(true, [-1, { c: 4 }])); // [-1, {a: 2, b: 3, c: 4}]
console.log(immutable([1, 2]).merge((p, n) => p + n, [2, 3])); // [3, 5]
```
#### .mutable()
*Alias .asMutable()*
Return a mutable copy. That is to say the return value is normal plain object or array. You can use `=`(assign operator) to set new key or value, and all methods will be restored to original behavior(like `arr.push()` will return new length other than new immutable array).
You should know that `.mutable()` will not make nested object(array) mutable.
```js
const arr = immutable([1, 2, 3]);
const arr1 = arr.mutable();
arr1[0] = -1;
console.log(arr1); // [-1, 2, 3]
```
### Array
Since array has a lot of methods like `push` and `slice`. Some are mutation operations while some are not.
For non-mutation methods that doesn't surely return literal value like `slice`, they are replaced to return immutable value. These methods are `slice`, `concat`, `map`, `reduce`, `reduceRight`, `filter`.
For mutation methods like `push`, they are replaced to return a new immutable copy other than their orignal returns. These methods are `push`, `pop`, `shift`, `unshift`, `fill`, `sort`, `splice`, `reverse`, `copyWithin`.
If any of these methods doesn't exist, no replacement for that method exists too.
```js
const arr = immutable([1, 2, 3]);
const newArr = arr.push(4); // [1, 2, 3, 4]
```
### License
Licensed under MIT
Copyright (c) 2017 [Tian Jian](https://github.com/tianjianchn)