/**
* @file Polyfill to extend functions of Array for WSH (Windows Script Host {@link https://docs.microsoft.com/en-us/previous-versions//9bbdkx3k(v=vs.85)|Microsoft Docs}). I recommend that JScript File Encoding is UTF-8[BOM, dos]
* @description JScript 5.8 is similar to ECMA-262 3rd edition and doesn't have many useful features that ES5 (ECMA-262 5.1 edition) and above have. This module adds those to JScript.
* @requires wscript.exe/cscript.exe
* @requires ./Function.js
* @requires ./Object.js
* @author Tuckn <tuckn333@gmail.com>
* @license MIT
* @see {@link https://github.com/tuckn/WshPolyfill|GitHub}
*/
/* eslint valid-typeof: "off" */
/** @namespace Array */
// Array.from {{{
// Production steps of ECMA-262, Edition 6, 22.1.2.1
if (!Array.from) {
/**
* Creates a new, shallow-copied Array instance from an array-like or iterable object. {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from|MDN}
*
* @function from
* @memberof Array
* @param {*} arrayLike - An array-like or iterable object to convert to an array.
* @returns {Array} - A new Array instance.
* @example
console.dir(Array.from('foo'));
// Outputs: ["f", "o", "o"]
console.dir(Array.from([1, 2, 3], function (x) { return x + x; }));
// Outputs: [2, 4, 6]
* @endOfExamples
*/
Array.from = (function () {
var toStr = Object.prototype.toString;
var isCallable = function (fn) {
return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
};
var toInteger = function (value) {
var number = Number(value);
if (isNaN(number)) { return 0; }
if (number === 0 || !isFinite(number)) { return number; }
return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
};
var maxSafeInteger = Math.pow(2, 53) - 1;
var toLength = function (value) {
var len = toInteger(value);
return Math.min(Math.max(len, 0), maxSafeInteger);
};
// The length property of the from method is 1.
return function from (arrayLike/* , mapFn, thisArg */) {
// 1. Let C be the this value.
var C = this;
// 2. Let items be ToObject(arrayLike).
// var items = Object(arrayLike);
var items;
if (typeof arrayLike === 'string') {
items = arrayLike.split('');
} else {
items = Object(arrayLike);
}
// 3. ReturnIfAbrupt(items).
if (arrayLike == null) {
throw new Error('Array.from requires an array-like object - not null or undefined');
}
// 4. If mapfn is undefined, then let mapping be false.
var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
var T;
if (typeof mapFn !== 'undefined') {
// 5. else
// 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
if (!isCallable(mapFn)) {
throw new Error('Array.from: when provided, the second argument must be a function');
}
// 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (arguments.length > 2) {
T = arguments[2];
}
}
// 10. Let lenValue be Get(items, "length").
// 11. Let len be ToLength(lenValue).
var len = toLength(items.length);
// 13. If IsConstructor(C) is true, then
// 13. a. Let A be the result of calling the [[Construct]] internal method
// of C with an argument list containing the single item len.
// 14. a. Else, Let A be ArrayCreate(len).
var A = isCallable(C) ? Object(new C(len)) : new Array(len);
// 16. Let k be 0.
var k = 0;
// 17. Repeat, while k < len… (also steps a - h)
var kValue;
while (k < len) {
kValue = items[k];
if (mapFn) {
A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
} else {
A[k] = kValue;
}
k += 1;
}
// 18. Let putStatus be Put(A, "length", len, true).
A.length = len;
// 20. Return A.
return A;
};
}());
} // }}}
// Array.isArray {{{
if (!Array.isArray) {
/**
* Determines whether the passed value is an Array. {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray|MDN}
*
* @function isArray
* @memberof Array
* @param {*} value - The value to be checked.
* @returns {boolean} - true if the value is an Array; otherwise, false.
* @example
Array.isArray([1, 2, 3]); // true
Array.isArray({ foo: 123 }); // false
Array.isArray('foobar'); // false
Array.isArray(undefined); // false
* @endOfExamples
*/
Array.isArray = function (value) {
return Object.prototype.toString.call(value) === '[object Array]';
};
} // }}}
/**
* @namespace Array.prototype
* @memberof Array
*/
/**
* @callback Array~requestCallback
* @param {*} element - The current element being processed in the array.
* @param {number} [index] - The index of the current element being processed in the array.
* @param {Array} [array] - The array function was called upon.
*/
// Array.prototype.filter {{{
if (!Array.prototype.filter) {
/**
* Creates a new array with all elements that pass the test implemented by the provided function. {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter|MDN}
*
* @function filter
* @memberof Array.prototype
* @param {Array~requestCallback} callback - Function to execute on each value in the array, taking 3 arguments
* @param {*} [thisArg] - Value to use as this when executing callback.
* @returns {Array} - A new array with the elements that pass the test
* @example
var words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
var result = words.filter((function (word) { return word.length > 6; }));
console.dir(result);
// expected output: Array ["exuberant", "destruction", "present"]
* @endOfExamples
*/
Array.prototype.filter = function (callback, thisArg) {
'use strict';
if (!((typeof callback === 'Function' || typeof callback === 'function') && this)) {
throw new Error();
}
var len = this.length >>> 0;
var res = new Array(len); // preallocate array
var t = this, c = 0, i = -1;
var kValue;
if (thisArg === undefined) {
while (++i !== len) {
// checks to see if the key was set
if (i in this) {
kValue = t[i]; // in case t is changed in callback
if (callback(t[i], i, t)) res[c++] = kValue;
}
}
} else {
while (++i !== len) {
// checks to see if the key was set
if (i in this) {
kValue = t[i];
if (callback.call(thisArg, t[i], i, t)) res[c++] = kValue;
}
}
}
res.length = c; // shrink down array to proper size
return res;
};
} // }}}
// Array.prototype.find {{{
// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
/**
* Returns the value of the first element in the provided array that satisfies the provided testing function. From ECMAScript 2015 (6th Edition, ECMA-262). {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find|MDN}
*
* @function find
* @memberof Array.prototype
* @param {Array~requestCallback} callback - Function to execute on each value in the array, taking 3 arguments
* @param {*} [thisArg] - Value to use as this when executing callback.
* @returns {*} - The value of the first element in the array that satisfies the provided testing function. Otherwise, undefined is returned.
* @example
var array1 = [5, 12, 8, 130, 44];
var found = array1.find(function (element) {
return element > 10;
});
console.log(found); // expected output: 12
* @endOfExamples
*/
Array.prototype.find = function (callback) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new Error('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If IsCallable(callback) is false, throw a TypeError exception.
if (typeof callback !== 'function') {
throw new Error('callback must be a function');
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(callback, T, « kValue, k, O »)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (callback.call(thisArg, kValue, k, o)) {
return kValue;
}
// e. Increase k by 1.
k++;
}
// 7. Return undefined.
return undefined;
};
} // }}}
// Array.prototype.findIndex {{{
// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.findIndex) {
/**
* Returns the index of the first element in the array that satisfies the provided testing function. From ECMAScript 2015 (6th Edition, ECMA-262). {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex|MDN}
*
* @function findIndex
* @memberof Array.prototype
* @param {Array~requestCallback} callback - The function to execute on each value in the array until the function returns true, indicating that the satisfying element was found. It takes three arguments
* @param {*} [thisArg] - Optional object to use as this when executing callback.
* @returns {number} - The index of the first element in the array that passes the test. Otherwise, -1.
* @example
var array1 = [5, 12, 8, 130, 44];
function findFirstLargeNumber(element) { return element > 13; }
console.log(array1.findIndex(findFirstLargeNumber)); // expected output: 3
* @endOfExamples
*/
Array.prototype.findIndex = function (callback) {
if (this === null) {
throw new Error('Array.prototype.findIndex called on null or undefined');
}
if (typeof callback !== 'function') {
throw new Error('callback must be a function');
}
var list = Object(this);
var length = list.length >>> 0;
var thisArg = arguments[1];
var value;
for (var i = 0; i < length; i++) {
value = list[i];
if (callback.call(thisArg, value, i, list)) {
return i;
}
}
return -1;
};
} // }}}
// Array.prototype.forEach {{{
// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
if (!Array.prototype.forEach) {
/**
* Executes a provided function once for each array element. From ECMA-262 5.1 edition. {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach|MDN}
*
* @function forEach
* @memberof Array.prototype
* @param {Array~requestCallback} callback - Function to execute on each element. It accepts between one and three arguments.
* @param {*} [thisArg] - Value to use as this when executing callback.
* @returns {void}
* @example
var array1 = ['a', 'b', 'c'];
array1.forEach(function (element) { console.dir(element); });
// expected output: "a"
// expected output: "b"
// expected output: "c"
* @endOfExamples
*/
Array.prototype.forEach = function (callback/* , thisArg */) {
var T, k;
if (this == null) {
throw new Error('this is null or not defined');
}
// 1. Let O be the result of calling toObject() passing the
// |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get() internal
// method of O with the argument "length".
// 3. Let len be toUint32(lenValue).
var len = O.length >>> 0;
// 4. If isCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== 'function') {
throw new Error(callback + ' is not a function');
}
// 5. If thisArg was supplied, let T be thisArg; else let
// T be undefined.
if (arguments.length > 1) {
T = arguments[1];
}
// 6. Let k be 0.
k = 0;
// 7. Repeat while k < len.
while (k < len) {
var kValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator.
// b. Let kPresent be the result of calling the HasProperty
// internal method of O with argument Pk.
// This step can be combined with c.
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal
// method of O with argument Pk.
kValue = O[k];
// ii. Call the Call internal method of callback with T as
// the this value and argument list containing kValue, k, and O.
callback.call(T, kValue, k, O);
}
// d. Increase k by 1.
k++;
}
// 8. return undefined.
};
} // }}}
// Array.prototype.includes {{{
if (!Array.prototype.includes) {
/**
* Determines whether an array includes a certain value among its entries. From ECMA-262 5.1 edition.{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes|MDN}
*
* @function includes
* @memberof Array.prototype
* @param {*} valueToFind - The value to search for
* @param {number} [fromIndex=0] - The position in this array at which to begin searching for valueToFind.
* @returns {boolean} - which is true if the value valueToFind is found within the array
* @example
var pets = ['cat', 'dog', 'bat'];
console.dir(pets.includes('cat')); // Outputs: true
* @endOfExamples
*/
Object.defineProperty(Array.prototype, 'includes', {
value: function (valueToFind, fromIndex) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new Error('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If len is 0, return false.
if (len === 0) {
return false;
}
// 4. Let n be ? ToInteger(fromIndex).
// (If fromIndex is undefined, this step produces the value 0.)
var n = fromIndex | 0;
// 5. If n ≥ 0, then
// a. Let k be n.
// 6. Else n < 0,
// a. Let k be len + n.
// b. If k < 0, let k be 0.
var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
function sameValueZero (x, y) {
return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
}
// 7. Repeat, while k < len
while (k < len) {
// a. Let elementK be the result of ? Get(O, ! ToString(k)).
// b. If SameValueZero(valueToFind, elementK) is true, return true.
// c. Increase k by 1.
if (sameValueZero(o[k], valueToFind)) {
return true;
}
k++;
}
// 8. Return false
return false;
}
});
} // }}}
// Array.prototype.indexOf {{{
// Production steps of ECMA-262, Edition 5, 15.4.4.14
// Reference: http://es5.github.io/#x15.4.4.14
if (!Array.prototype.indexOf) {
/**
* Returns the first index at which a given element can be found in the array. From ECMA-262 5.1 edition.{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf|MDN}
*
* @function indexOf
* @memberof Array.prototype
* @param {*} searchElement - Element to locate in the array.
* @param {number} [fromIndex=0] - The index to start the search at.
* @returns {number} - The first index of the element in the array; -1 if not found.
* @example
var array = [2, 9, 9];
array.indexOf(2); // 0
array.indexOf(7); // -1
* @endOfExamples
*/
Array.prototype.indexOf = function (searchElement, fromIndex) {
'use strict';
var k;
// 1. ToObject に this 値を引数として渡した結果を
// o とします。
if (this == null) {
throw new Error('"this" is null or not defined');
}
var o = Object(this);
// 2. "length" を引数として o の Get 内部メソッドを呼んだ結果を
// lenValue とします。
// 3. ToUint32(lenValue) を len とします。
var len = o.length >>> 0;
// 4. len が 0 の場合、-1 を返します。
if (len === 0) {
return -1;
}
// 5. n を fromIndex 引数が存在する場合は ToInteger(fromIndex) と、
// 存在しない場合は 0 とします。
var n = fromIndex | 0;
// 6. n が len 以上の場合 -1 を返します。
if (n >= len) {
return -1;
}
// 7. n が 0 以上の場合 k を n とします。
// 8. n が 0 未満の場合 k を len - abs(n) とします。
// k が 0 未満の場合 k を 0 とします。
k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
// 9. k が len 未満の間は以下を繰り返します。
for (; k < len; k++) {
// a. Pk を ToString(k) とします。
// これは暗黙的に in 演算子の左辺値です。
// b. kPresent を Pk を引数として o の
// HasProperty 内部メソッドを呼んだ結果とします。
// このステップは c と組み合わせることができます。
// c. kPresent が真の場合
// i. elementK を ToString(k) を引数として
// o の [[Get]] 内部メソッドを呼んだ結果とします。
// ii. same を searchElement と elementK で
// 厳密な同一比較アルゴリズムを行った結果とします。
// iii. same が真の場合 k を返します。
if (k in o && o[k] === searchElement) return k;
}
return -1;
};
} // }}}
// Array.prototype.map {{{
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.io/#x15.4.4.19
if (!Array.prototype.map) {
/**
* Creates a new array populated with the results of calling a provided function on every element in the calling array. From ECMA-262 5.1 edition. {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map|MND}
*
* @function map
* @memberof Array.prototype
* @param {Array~requestCallback} callback - Function that is called for every element of the array. Each time callback executes, the returned value is added to the new array.
* @param {*} [thisArg] - Value to use as this when executing callback.
* @returns {Array} - A new array with each element being the result of the callback function.
* @example
var array1 = [1, 4, 9, 16];
var map1 = array1.map(function (x) { return x * 2; });
console.dir(map1); // expected output: Array [2, 8, 18, 32]
* @endOfExamples
*/
Array.prototype.map = function (callback/* , thisArg */) {
var T, A, k;
if (this == null) {
throw new Error('this is null or not defined');
}
// 1. Let O be the result of calling ToObject passing the |this|
// value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal
// method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== 'function') {
throw new Error(callback + ' is not a function');
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (arguments.length > 1) {
T = arguments[1];
}
// 6. Let A be a new array created as if by the expression new Array(len)
// where Array is the standard built-in constructor with that name and
// len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
// 8. Repeat, while k < len
while (k < len) {
var kValue, mappedValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal
// method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal
// method of O with argument Pk.
kValue = O[k];
// ii. Let mappedValue be the result of calling the Call internal
// method of callback with T as the this value and argument
// list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor
// { Value: mappedValue,
// Writable: true,
// Enumerable: true,
// Configurable: true },
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, k, {
// value: mappedValue,
// writable: true,
// enumerable: true,
// configurable: true
// });
// For best browser support, use the following:
A[k] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
} // }}}
// Array.prototype.reduce {{{
if (!Array.prototype.reduce) {
/**
* Executes a reducer function (that you provide) on each element of the array, resulting in a single output value. From ECMA-262 5.1 edition. {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce|MDN}
*
* @function reduce
* @memberof Array.prototype
* @param {reducerCallback} callback - The function to execute on each element in the array (except for the first, if no initialValue is supplied).
* @param {*} [initialValue] - Value to use as this when executing callback.
* @returns {*} - The single value that results from the reduction.
* @example
var array1 = [1, 2, 3, 4];
var reducer = function (accumulator, currentValue) {
return accumulator + currentValue;
}
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer)); // expected output: 10
// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5)); // expected output: 15
* @endOfExamples
*/
Array.prototype.reduce = function reduce (callback) {
/**
* @typedef {object} reducerCallback
* @property {*} accumulator - The accumulator accumulates callback's return values. It is the accumulated value previously returned in the last invocation of the callback—or initialValue, if it was supplied
* @property {*} element - The current element being processed in the array.
* @property {number} [index] - The index of the current element being processed in the array.
* @property {Array} [array] - The array function was called upon.
*/
if (this === null || this === undefined) {
throw new Error('Object is null or undefined');
}
var i = 0, l = this.length >> 0, curr;
// ES5 : 'If IsCallable (callbackfn) is false, throw a TypeError exception.'
if (typeof callback !== 'function') {
throw new Error('First argument is not callable');
}
if (arguments.length < 2) {
if (l === 0) {
throw new Error('Array length is 0 and no second argument');
}
curr = this[0];
i = 1; // start accumulating at the second element
} else {
curr = arguments[1];
}
while (i < l) {
if (i in this) curr = callback.call(undefined, curr, this[i], i, this);
++i;
}
return curr;
};
} // }}}
// Array.prototype.some {{{
// Production steps of ECMA-262, Edition 5, 15.4.4.17
// Reference: http://es5.github.io/#x15.4.4.17
if (!Array.prototype.some) {
/**
* Method tests whether at least one element in the array passes the test implemented by the provided function. From ECMA-262 5.1 edition. {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some|MDN}
*
* @function some
* @memberof Array.prototype
* @param {Array~requestCallback} callback - Function to execute on each value in the array, taking 3 arguments
* @param {*} [thisArg] - Value to use as this when executing callback.
* @returns {boolean} - true if the callback function returns a truthy value for at least one element in the array. Otherwise, false.
* @example
var array = [1, 2, 3, 4, 5];
var even = function (element) {
return element % 2 === 0; // checks whether an element is even
};
console.dir(array.some(even)); // Outputs: true
* @endOfExamples
*/
Array.prototype.some = function (fun/* , thisArg */) {
'use strict';
if (this == null) {
throw new Error('Array.prototype.some called on null or undefined');
}
if (typeof fun !== 'function') {
throw new Error();
}
var t = Object(this);
var len = t.length >>> 0;
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t && fun.call(thisArg, t[i], i, t)) {
return true;
}
}
return false;
};
} // }}}
// vim:set foldmethod=marker commentstring=//%s :