array-includes-x
Version:
Determines whether an array includes a certain element.
177 lines (145 loc) • 5.1 kB
JavaScript
import attempt from 'attempt-x';
import toObject from 'to-object-x';
import toLength from 'to-length-x';
import sameValueZero from 'same-value-zero-x';
import findIndex from 'find-index-x';
import splitIfBoxedBug from 'split-if-boxed-bug-x';
import indexOf from 'index-of-x';
import calcFromIndex from 'calculate-from-index-x';
import toBoolean from 'to-boolean-x';
import requireObjectCoercible from 'require-object-coercible-x';
import methodize from 'simple-methodize-x';
const ni = [].includes;
const nativeIncludes = typeof ni === 'function' && methodize(ni);
const getArrayLike = function getArrayLike() {
return {
1: 'a',
2: NaN,
3: -0,
length: 5,
};
};
const test1 = function test1() {
return attempt(null, nativeIncludes, 'a').threw;
};
const test2 = function test2() {
const arr = getArrayLike();
const res = attempt(function attemptee() {
/* eslint-disable-next-line no-void */
return nativeIncludes(arr, void 0, -1);
});
return res.threw === false && res.value === true;
};
const test3 = function test3() {
const arr = getArrayLike();
const res = attempt(function attemptee() {
return nativeIncludes(arr, NaN);
});
return res.threw === false && res.value === true;
};
const test4 = function test4() {
const arr = getArrayLike();
const res = attempt(function attemptee() {
return nativeIncludes(arr, 0);
});
return res.threw === false && res.value === true;
};
const test5 = function test5() {
const testArr = [];
testArr.length = 2;
testArr[1] = null;
const res = attempt(function attemptee() {
/* eslint-disable-next-line no-void */
return nativeIncludes(testArr, void 0);
});
return res.threw === false && res.value === true;
};
const test6 = function test6() {
const res = attempt(function attemptee() {
return nativeIncludes('abc', 'c');
});
return res.threw === false && res.value === true;
};
const test7 = function test7() {
const res = attempt(function attemptee() {
const args = (function getArgs() {
/* eslint-disable-next-line prefer-rest-params */
return arguments;
})('a', 'b', 'c');
return nativeIncludes(args, 'c');
});
return res.threw === false && res.value === true;
};
const isWorking = toBoolean(nativeIncludes) && test1() && test2() && test3() && test4() && test5() && test6() && test7();
const patchedReduce = function includes(array, searchElement) {
/* eslint-disable-next-line prefer-rest-params */
return nativeIncludes(requireObjectCoercible(array), searchElement, arguments[2]);
};
// eslint-disable jsdoc/check-param-names
// noinspection JSCommentMatchesSignature
/**
* This method returns an index in the array, if an element in the array
* satisfies the provided testing function. Otherwise -1 is returned.
*
* @private
* @param {Array} object - The array to search.
* @param {*} searchElement - Element to locate in the array.
* @param {number} fromIndex - The index to start the search at.
* @returns {number} Returns index of found element, otherwise -1.
*/
// eslint-enable jsdoc/check-param-names
const findIdxFrom = function findIndexFrom(args) {
const [object, searchElement, fromIndex] = args;
let fIdx = fromIndex;
const length = toLength(object.length);
while (fIdx < length) {
if (sameValueZero(object[fIdx], searchElement)) {
return fIdx;
}
fIdx += 1;
}
return -1;
};
const runFindIndex = function runFindIndex(obj) {
const {iterable, args, length, searchElement} = obj;
let fromIndex = calcFromIndex(iterable, args[2]);
if (fromIndex >= length) {
return -1;
}
if (fromIndex < 0) {
fromIndex = 0;
}
return fromIndex > 0
? findIdxFrom([iterable, searchElement, fromIndex]) > -1
: findIndex(iterable, function predicate(element) {
return sameValueZero(searchElement, element);
}) > -1;
};
export const implementation = function includes(array, searchElement) {
const object = toObject(array);
const iterable = splitIfBoxedBug(object);
const length = toLength(iterable.length);
if (length < 1) {
return -1;
}
if (typeof searchElement === 'undefined') {
/* eslint-disable-next-line prefer-rest-params */
return runFindIndex({iterable, args: arguments, length, searchElement});
}
/* eslint-disable-next-line prefer-rest-params */
return indexOf(iterable, searchElement, arguments[2], 'samevaluezero') > -1;
};
/**
* This method determines whether an array includes a certain element,
* returning true or false as appropriate.
*
* @param {Array} array - The array to search.
* @throws {TypeError} If `array` is `null` or `undefined`.
* @param {*} searchElement - Element to locate in the `array`.
* @param {number} [fromIndex] - The position in this array at which to begin
* searching for searchElement. A negative value searches from the index of
* array.length + fromIndex by asc. Defaults to 0.
* @returns {boolean} `true` if searched element is included; otherwise `false`.
*/
const $includes = isWorking ? patchedReduce : implementation;
export default $includes;