ds-algo-study
Version:
Just experimenting with publishing a package
286 lines (225 loc) • 5.98 kB
Markdown
## Clone an object
clone(x)
Can clone any primitive type, array, and object.
If x has a function clone, this function will be invoked to clone the object.
>param {} x
>return {} clone
```js
export function clone(x) {
const type = typeof x;
// immutable primitive types
if (
type === "number" ||
type === "string" ||
type === "boolean" ||
x === null ||
x === undefined
) {
return x;
}
// use clone function of the object when available
if (typeof x.clone === "function") {
return x.clone();
}
// array
if (Array.isArray(x)) {
return x.map(function (value) {
return clone(value);
});
}
if (x instanceof Date) return new Date(x.valueOf());
// object
return mapObject(x, clone);
}
```
## Apply map to all properties of an object
>param {Object} object
>param {function} callback
>return {Object} Returns a copy of the object with mapped properties
```js
export function mapObject(object, callback) {
const clone = {};
for (const key in object) {
if (hasOwnProperty(object, key)) {
clone[key] = callback(object[key]);
}
}
return clone;
}
```
## Extend object a with the properties of object b
>param {Object} a
>param {Object} b
>return {Object} a
```js
export function extend(a, b) {
for (const prop in b) {
if (hasOwnProperty(b, prop)) {
a[prop] = b[prop];
}
}
return a;
}
```
## Deep test equality of all fields in two pairs of arrays or objects.
Compares values and functions strictly (ie. 2 is not the same as '2').
>param {Array | Object} a
>param {Array | Object} b
>returns {boolean}
```js
export function deepStrictEqual(a, b) {
let prop, i, len;
if (Array.isArray(a)) {
if (!Array.isArray(b)) {
return false;
}
if (a.length !== b.length) {
return false;
}
for (i = 0, len = a.length; i < len; i++) {
if (!deepStrictEqual(a[i], b[i])) {
return false;
}
}
return true;
} else if (typeof a === "function") {
return a === b;
} else if (a instanceof Object) {
if (Array.isArray(b) || !(b instanceof Object)) {
return false;
}
for (prop in a) {
// noinspection JSUnfilteredForInLoop
if (!(prop in b) || !deepStrictEqual(a[prop], b[prop])) {
return false;
}
}
for (prop in b) {
// noinspection JSUnfilteredForInLoop
if (!(prop in a) || !deepStrictEqual(a[prop], b[prop])) {
return false;
}
}
return true;
} else {
return a === b;
}
}
```
## Recursively flatten a nested object.
>param {Object} nestedObject
>return {Object} Returns the flattened object
```js
export function deepFlatten(nestedObject) {
const flattenedObject = {};
_deepFlatten(nestedObject, flattenedObject);
return flattenedObject;
}
// helper function used by deepFlatten
function _deepFlatten(nestedObject, flattenedObject) {
for (const prop in nestedObject) {
if (hasOwnProperty(nestedObject, prop)) {
const value = nestedObject[prop];
if (typeof value === "object" && value !== null) {
_deepFlatten(value, flattenedObject);
} else {
flattenedObject[prop] = value;
}
}
}
}
```
## Test whether the current JavaScript engine supports Object.defineProperty
>returns {boolean} returns true if supported
```js
export function canDefineProperty() {
// test needed for broken IE8 implementation
try {
if (Object.defineProperty) {
Object.defineProperty({}, "x", { get: function () {} });
return true;
}
} catch (e) {}
return false;
}
```
## Attach a lazy loading property to a constant.
The given function `fn` is called once when the property is first requested.
>param {Object} object Object where to add the property
>param {string} prop Property name
>param {Function} valueResolver Function returning the property value. Called
without arguments.
```js
export function lazy(object, prop, valueResolver) {
let _uninitialized = true;
let _value;
Object.defineProperty(object, prop, {
get: function () {
if (_uninitialized) {
_value = valueResolver();
_uninitialized = false;
}
return _value;
},
set: function (value) {
_value = value;
_uninitialized = false;
},
configurable: true,
enumerable: true,
});
}
```
## Get a nested property from an object
>param {Object} object
>param {string | string[]} path
>returns {Object}
```js
export function get(object, path) {
if (typeof path === "string") {
if (isPath(path)) {
return get(object, path.split("."));
} else {
return object[path];
}
}
let child = object;
for (let i = 0; i < path.length; i++) {
const key = path[i];
child = child ? child[key] : undefined;
}
return child;
}
```
## Set a nested property in an object
Mutates the object itself
If the path doesn't exist, it will be created
>param {Object} object
>param {string | string[]} path
>param {} value
>returns {Object}
```js
export function set(object, path, value) {
if (typeof path === "string") {
if (isPath(path)) {
return set(object, path.split("."), value);
} else {
object[path] = value;
return object;
}
}
let child = object;
for (let i = 0; i < path.length - 1; i++) {
const key = path[i];
if (child[key] === undefined) {
child[key] = {};
}
child = child[key];
}
if (path.length > 0) {
const lastKey = path[path.length - 1];
child[lastKey] = value;
}
return object;
}
```