52 lines
1.4 KiB
JavaScript
52 lines
1.4 KiB
JavaScript
|
const own = {}.hasOwnProperty
|
||
|
|
||
|
/**
|
||
|
* Perform the specified action for each element in an array.
|
||
|
* When `callbackFn` returns a `number`, moves to the element at that index
|
||
|
* next.
|
||
|
*
|
||
|
* @param {unknown[]} values
|
||
|
* Values to iterate over.
|
||
|
* @param {(this: unknown, value: unknown, index: number, array: unknown[]) => number | void} callbackFn
|
||
|
* Function called for each element.
|
||
|
* Can return the `index` to move to next.
|
||
|
* @param {unknown} [thisArg]
|
||
|
* Optional object assigned as `this` in `callbackFn`.
|
||
|
* @returns {void}
|
||
|
*/
|
||
|
export function arrayIterate(values, callbackFn, thisArg) {
|
||
|
let index = -1
|
||
|
|
||
|
if (!values) {
|
||
|
throw new Error('Iterate requires that |this| not be ' + values)
|
||
|
}
|
||
|
|
||
|
if (!own.call(values, 'length')) {
|
||
|
throw new Error('Iterate requires that |this| has a `length`')
|
||
|
}
|
||
|
|
||
|
if (typeof callbackFn !== 'function') {
|
||
|
throw new TypeError('`callback` must be a function')
|
||
|
}
|
||
|
|
||
|
// The length might change, so we do not cache it.
|
||
|
while (++index < values.length) {
|
||
|
// Skip missing values.
|
||
|
if (!(index in values)) {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
const result = callbackFn.call(thisArg, values[index], index, values)
|
||
|
|
||
|
// If `callback` returns a `number`, move `index` over to `number`.
|
||
|
if (typeof result === 'number') {
|
||
|
// Make sure that negative numbers do not break the loop.
|
||
|
if (result < 0) {
|
||
|
index = 0
|
||
|
}
|
||
|
|
||
|
index = result - 1
|
||
|
}
|
||
|
}
|
||
|
}
|