Skip to content

Instantly share code, notes, and snippets.

@roboncode
Last active December 15, 2022 20:13
Show Gist options
  • Save roboncode/998fb8ad9d8d7180e62755d66c043bd8 to your computer and use it in GitHub Desktop.
Save roboncode/998fb8ad9d8d7180e62755d66c043bd8 to your computer and use it in GitHub Desktop.
forEach.ts
type Iteraterable = {
next: () => { value?: any; key?: any; hasNext: boolean; done: () => void }
hasNext: () => boolean
}
const clone = (obj: any) => JSON.parse(JSON.stringify(obj))
const makeArrayIterator = (array: any[]): Iteraterable => {
array = clone(array)
let nextIndex = 0
const done = (): void => {
nextIndex = array.length
}
return {
hasNext: () => nextIndex < array.length,
next: () =>
nextIndex < array.length
? {
key: nextIndex,
value: array[nextIndex++],
hasNext: true,
done,
}
: {
hasNext: false,
done,
},
}
}
type KeyVal = { [key: string]: any }
const makeObjectIterator = (obj: KeyVal): Iteraterable => {
const keys = Object.keys(obj)
let nextIndex = 0
const done = () => {
nextIndex = keys.length
}
return {
hasNext: () => nextIndex < keys.length,
next: () =>
nextIndex < keys.length
? {
key: keys[nextIndex],
value: obj[keys[nextIndex++]],
hasNext: true,
done,
}
: {
hasNext: false,
done,
},
}
}
const makeStringIterator = (str: string): Iteraterable => {
let nextIndex = 0
const done = () => {
nextIndex = str.length
}
return {
hasNext: () => nextIndex < str.length,
next: () =>
nextIndex < str.length
? {
key: nextIndex,
value: str[nextIndex++],
hasNext: true,
done,
}
: {
hasNext: false,
done,
},
}
}
const makeNumberIterator = (num: number): Iteraterable => {
let nextIndex = 0
const done = () => {
nextIndex = num
}
return {
hasNext: () => nextIndex < num,
next: () =>
nextIndex < num
? {
key: nextIndex,
value: nextIndex++,
hasNext: true,
done,
}
: {
hasNext: false,
done,
},
}
}
const iterate = (fn: (item: any, index: number, done: () => void) => void, iterator: Iteraterable) => {
do {
const { value, key, done } = iterator.next()
fn(value, key, done)
} while (iterator.hasNext())
}
export const forEach = (value: any, fn: (item: any, index: number, done: () => void) => void) => {
let itr: Iteraterable
if (Array.isArray(value)) {
itr = makeArrayIterator(value)
} else if (typeof value === 'string') {
itr = makeStringIterator(value)
} else if (typeof value === 'number') {
itr = makeNumberIterator(value)
} else if (typeof value === 'object') {
itr = makeObjectIterator(value)
} else {
throw new Error('Invalid type')
}
iterate(fn, itr)
}
// banned words: throw, for, do, while, async, await, Promise, setTimeout, setInterval, setImmediate, fetch, XMLHttpRequest, WebSocket, EventSource, FileReader, FileReaderSync, Atomics, SharedArrayBuffer, import, export, new, debugger, yield
async function main() {
const fn = new Function('forEach,$value', `
forEach($value, (item, key, done) => {
console.log(item, key)
if (key === 5) {
done()
}
})`)
const result = fn(forEach, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
// const result = fn(forEach, { a: 1, b: 2, c: 3 })
// forEach([1, 2, 3, 4, 5], (item, index, done) => {
// console.log(item, index)
// if (index === 10) {
// done()
// }
// })
// forEach({ a: 1, b: 2, c: 3 }, (item, key) => {
// console.log(item, key)
// })
// forEach('abc', (item, key) => {
// console.log(item, key)
// })
// forEach(3, (item, key) => {
// console.log(item, key)
// })
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment