-
Notifications
You must be signed in to change notification settings - Fork 9
Cookbook (es6)
Janry edited this page Dec 19, 2016
·
10 revisions
Simple iterator based on {RecursiveIterator}
instead forEach
method.
Description
import RecursiveIterator from 'your_path';
class Iterator extends RecursiveIterator {
/**
* @param {Object|Array} iterated
*/
constructor(iterated) {
super(iterated, 1, false, 1);
}
}
export default Iterator;
Usage
import Iterator from 'your_path';
for(let {node, key} of new Iterator([1, 2, 3])) {
console.log(node);
}
for(let {node, key} of new Iterator(document.getElementsByTagName('h1'))) {
console.log(node, key);
}
Example of DOM iterator.
Description
import RecursiveIterator from 'your_path';
class DomIterator extends RecursiveIterator {
/**
* @param {*} arguments_
*/
constructor(...arguments_) {
super(...arguments_);
}
/**
* @param {*} any
* @returns {Boolean}
*/
isLeaf(any) {
return super.isLeaf(any) && !any.children.length;
}
/**
* Returns states of child nodes
* @param {Object} node
* @param {Array} path
* @param {Number} deep
* @returns {Array<Object>}
*/
getStatesOfChildNodes(node, path, deep) {
return Array.from(node.children).map((value) =>
this.getState(node, value, value.tagName, path.concat(value.tagName), deep + 1)
);
}
}
/**
* @param {*} any
* @returns {Boolean}
*/
function isObject(any) {
return any !== null && typeof any === 'object';
}
export default DomIterator;
Usage
<ul id="root">
<li>1
<ul>
<li>1.1</li>
<li>1.2</li>
</ul>
</li>
<li>2</li>
</ul>
import DomIterator from 'your_path';
var root = document.getElementById('root');
for(let {node, path} of new DomIterator(root)) {
console.log(path.join('.'), node);
}
// LI <li>…</li>
// LI.UL <ul>…</ul>
// LI.UL.LI <li>1.1</li>
// LI.UL.LI <li>1.2</li>
// LI <li>2</li>
var toString = Object.prototype.toString;
/**
* @param {*} any
* @returns {Boolean}
*/
function isObject(any) {
return any !== null && typeof any === 'object';
}
/**
* @param {*} any
* @returns {String}
*/
function getType(any) {
return toString.call(any).slice(8, -1);
}
/**
* @param {*} any
* @returns {*}
*/
function shallowCopy(any) {
var type = getType(any);
switch (type) {
case 'Object':
return {};
case 'Array':
return [];
case 'Date':
return new Date(any);
case 'RegExp':
return new RegExp(any);
case 'Number':
case 'String':
case 'Boolean':
case 'Undefined':
case 'Null':
return any;
default:
return String(any);
}
}
/**
* @param {*} any
* @param {Boolean} [deep]
* @returns {*}
*/
function copy(any, deep = false) {
if (!deep || !isObject(any)) {
return shallowCopy(any);
}
var map = new Map();
var rootNode = shallowCopy(any);
map.set(any, rootNode);
for(var {parent, node, key} of new RecursiveIterator(any, 1, true)) {
var parentNode = map.get(parent);
var cloneNode = shallowCopy(node);
parentNode[key] = cloneNode;
map.set(node, cloneNode);
}
map.clear();
return rootNode;
}
// ---------------------------------
// USAGE
// ---------------------------------
var some = {
foo: {
bar: 1
}
};
var clone = copy(some, true);
alert(JSON.stringify(clone));
alert(clone === some); // false
let {RecursiveIterator, encodeURIComponent} = window;
let {isArray, isObject} = angular; // (!) YOU MUST IMPLEMENT THESE FUNCTIONS
/**
* Converts path to name
* @param {Array} path
* @returns {String}
*/
function toName(path) {
let array = path.map(part => `[${encodeURIComponent(part)}]`);
array[0] = path[0];
return array.join('');
}
/**
* @param {Object|Array} any
* @returns {String}
*/
export default function toQueryString(any) {
if (!isObject(any) && !isArray(any)) {
throw new TypeError('Argument must be object or array');
}
let stack = [];
for(let {node, path} of new RecursiveIterator(any)) {
if (isObject(node)) continue;
let name = toName(path);
let value = encodeURIComponent(node);
stack.push(`${name}=${value}`);
}
return stack.join('&');
}
'use strict';
let {FormData} = window;
let {toString} = Object.prototype;
let {isObject, isUndefined} = angular; // (!) YOU MUST IMPLEMENT THESE FUNCTIONS
/**
* Returns type of anything
* @param {Object} any
* @returns {String}
*/
function getType(any) {
return toString.call(any).slice(8, -1);
}
/**
* Converts path to FormData name
* @param {Array} path
* @returns {String}
*/
function toName(path) {
let array = path.map((part) => `[${part}]`);
array[0] = path[0];
return array.join('');
}
/**
* Converts object to FormData
* @param {Object} object
* @returns {FormData}
*/
export default function(object) {
if (!isObject(object)) {
throw new TypeError('Argument must be object');
}
let form = new FormData();
let iterator = new RecursiveIterator(object, 0, true);
let appendToForm = function(path, node, filename) {
let name = toName(path);
if (isUndefined(filename)) {
form.append(name, node);
} else {
form.append(name, node, filename);
}
};
iterator.onStepInto = function({parent, node}) {
let type = getType(node);
switch (type) {
case 'Array':
return true; // step into
case 'Object':
return true; // step into
case 'FileList':
return true; // step into
default:
return false; // prevent step into
}
};
for(let {node, path} of iterator) {
var type = getType(node);
switch (type) {
case 'Array':
break;
case 'Object':
break;
case 'FileList':
break;
case 'File':
appendToForm(path, node);
break;
case 'Blob':
appendToForm(path, node, node.name);
break;
default:
appendToForm(path, node);
break;
}
}
return form;
}
new RecursiveIterator(root, 1);
See options bypassMode
.
new RecursiveIterator(root, 0);
// or new RecursiveIterator(root);
See options bypassMode
.
new RecursiveIterator(root, 0, false, /* limit */);
See options maxDeep
.
// sample of node
export default class Node {
/**
* @param {Number} cost
* @param {Array<Node>} [children]
*/
constructor(cost = 0, children = []) {
this.cost = cost;
this.children = children;
}
}
import RecursiveIterator from 'your_path';
export default class UniformCostIterator extends RecursiveIterator {
/**
* @param {Object|Array} root
* @param {Boolean} [ignoreCircular=false]
* @param {Number} [maxDeep=100]
*/
constructor(root, ignoreCircular, maxDeep) {
super(root, 0, ignoreCircular, maxDeep);
}
/**
* Returns states of child nodes
* @param {Object} node
* @param {Array} path
* @param {Number} deep
* @returns {Array<Object>}
*/
getStatesOfChildNodes(node, path, deep) {
return node.children
.map((child, key) =>
this.getState(node, child, key, path.concat(child.cost), deep + 1))
.sort((a, b) =>
a.node.cost - b.node.cost);
}
}
// usage
import UniformCostIterator from './UniformCostIterator';
import Node from './Node';
var root = new Node(0, [
new Node(2, [
new Node(8), new Node(4)
]),
new Node(1, [
new Node(12, [
new Node(4)
]),
new Node(9, [
new Node(7, [
new Node(6)
]),
new Node(5, [
new Node(10)
])
])
]),
new Node(3)
]);
for(var {node, path} of new UniformCostIterator(root)) {
console.log(node, path.join('.'));
}
// Node {cost: 1, children: Array[2]} "1"
// Node {cost: 9, children: Array[2]} "1.9"
// Node {cost: 5, children: Array[1]} "1.9.5"
// Node {cost: 10, children: Array[0]} "1.9.5.10"
// Node {cost: 7, children: Array[1]} "1.9.7"
// Node {cost: 6, children: Array[0]} "1.9.7.6"
// Node {cost: 12, children: Array[1]} "1.12"
// Node {cost: 4, children: Array[0]} "1.12.4"
// Node {cost: 2, children: Array[2]} "2"
// Node {cost: 4, children: Array[0]} "2.4"
// Node {cost: 8, children: Array[0]} "2.8"
// Node {cost: 3, children: Array[0]} "3"