- 数组polyfill
- Array.from( )
- Array.prototype.indexOf( )
- Array.protorype.lastIndexOf( )
- Array.protorype.includes( )
- Array.prototype.find( )
- Array.prototype.findIndex( )
- Array.prototype.copyWithin(target[, start, end])
- Array.prototype.fill(value[, start, end])
- Array.prototype.flat([depth])
- Array.prototype.map( )
- Array.prototype.filter( )
- Array.prototype.every( )
- Array.prototype.some( )
- Array.prototype.reduce( )
数组polyfill
Array.from( )
Array.myFrom = (function () {
// 判断参数是否可调用,也就是判断value是不是函数。
var isCallable = function (fn) {
return typeof fn === 'function' || Object.prototype.toString.call(fn) === '[object Function]';
};
// 因为需要使用类数组中的length属性,我们需要检查length的值是不是整数,不是整数情况下需要转化成整数。
// 也就是判断value是不是数字
var toInteger = function (value) {
var num = Number(value);
if (isNaN(num)) { return 0 };
if (num === 0 || !isFinite(num)) { return num };
return (num > 0 ? 1 : -1) * Math.floor(Math.abs(num)); //变成标准的正整数和负整数。
}
// 上面一个函数使得变成标准的正整数和负整数,但是length的数值不能是负数和无限大的数字。
var toLength = function (value) {
var maxSafeInteger = Number.MAX_SAFE_INTEGER,
len = toInteger(value);
return Math.min(Math.max(len, 0), maxSafeInteger);
}
return function from(arrayLikeOrIterator) {
const caller = this, //保存调用方
item = Object(arrayLikeOrIterator), //参数1包装成对象
isIterator = isCallable(item[Symbol.iterator]); //判断对象是否可迭代
// 检查参数1是不是类数组、可迭代对象
if (!isIterator && arrayLikeOrIterator === null) {
throw new TypeError('Array.from requires an array-like object or iterator - not null or undefined');
}
//变长参数,取到参数2和3。并进行类型判断是否是函数。
var mapfn = arguments.length > 1 ? arguments[1] : void undefined,
T; //参数3:thisArg
if (typeof mapfn !== undefined) { //mapfn参数类型检查
if (isCallable(mapfn))
throw new TypeError('Array.from: when provided, the second argument must be a function');
if (arguments.length > 2) {
T = arguments[2];
}
}
//获得类数组的length属性
var len = toLength(item.length);
var arr = isCallable(caller) ? Object(new caller(len)) : new Array(len); //排除(1).from的情况,并且根据len长度创建数组。
let i = 0,
val;
while (i < len) {
val = item[i];
if (mapfn) {
arr[i] = typeof T === 'undefined' ? mapfn(val, i) : mapfn.apply(T, [val, i]);
} else {
arr[i] = val;
}
i++;
}
return arr;
}
})();
Array.prototype.indexOf( )
语义搜索范围内,从头开始匹配,必须是===严格相等,才会返回索引值的位置。
语法Array.prototype.indexOf(searchElement, fromIndex)
/**
*@param {value} searchElement 需要查找的元素值
*@param {number = 0} fromIndex 查找的开始位置
*@return {number} 查找元素的位置。找不到索引值返回值为-1。
*/
let a = ['a', 'b', 'a', 'd', 'a'];
let b = a.indexOf('a');
let c = a.indexOf('a', 1);
let d = a.indexOf('f');
console.log(b); //0
console.log(c); //2
console.log(a); //["a", "b", "a", "d", "a"]
console.log(d); //-1
例子获取所有的索引值。
var indices = [];
var array = ['a', 'b', 'a', 'c', 'a', 'd'];
function indexAllOf(arr, element) {
const indices = [];
let idx = arr.indexOf(element);
while (idx != -1) {
indices.push(idx);
idx = arr.indexOf(element, idx + 1);
}
return indices;
}
console.log(indexAllOf(array, 'a'));
Array.protorype.lastIndexOf( )
语义搜索范围内,从末尾匹配,必须是===严格相等,返回最后一个索引值。
语法Array.protorype.lastIndexOf ( searchElement, fromIndex )
/**
*@param {value} searchElement 需要查找的元素值
*@param [{number = 0}] fromIndex 查找的开始位置
*@return {number} 查找元素的位置。找不到索引值返回值为-1。
*/
let a = ['a', 'b', 'a', 'd', 'a'];
let b = a.lastIndexOf('a', 4);
let c = a.lastIndexOf('a', 3);
console.log(b); //4
console.log(c); //2
console.log(a); //["a", "b", "a", "d", "a"]
Array.protorype.includes( )
语义搜索数组是否包含某个元素。
关键点该方法可以通过call()、apply()用于类数组对象。
语法Array.protorype.includes( searchElement, fromIndex )
/**
*@param {value} searchElement 需要查找的元素值
*@param [{number = 0}] fromIndex 查找的开始位置
*@return {Boolean}
*/
let a = ['a', 'b', 'a', 'd', 'f'];
let b = a.includes('a', 2);
let c = a.includes('a', 3);
console.log(b); //true
console.log(c); //false
例子polyfill
Array.prototype.myIncludes = function (searchElement) {
if (this === null) {
throw new TypeError('this is null');
}
var O = Object(this);
var len = O.length >>> 0;
var start = arguments[1] === undefined ? 0 : arguments[1] >> 0;
var k = Math.max(start >= 0 ? start : len - Math.abs(start), 0);
while (k < len) {
if (O[k] === searchElement) {
return true;
}
k++;
}
return false;
}
Array.prototype.find( )
语义根据回调函数,找到第一个满足回调函数的元素值。
关键点该方法可以通过call()、apply()用于类数组对象。
关键点find会遍历稀疏数组的空值,效率比较低,取值为undefined。
关键点即使在遍历过程中,数组元素被删除delete,仍然补值undefined。
关键点遍历过程中增加元素,遍历的长度仍然是初始数组长度。
语法Array.prototype.find(callbackFn(element[, index, array])[, thisArg])
/**
*@param {function} callbackFn 回调函数返回的是Boolean值。
*@param [this.Arg] 改变回调函数内部的this值。
*@return {value = undefined} 满足回调函数的第一个值。
*/
例子polyfill
Array.prototype.myFind = function (callBackFn) {
//排除this最为对象时的null值
if (this === null) {
throw new TypeError('this is not null');
}
var O = Object(this);
// 满足类数组,检查length属性值非负整数。
var len = O.length >>> 0;
//检查参数
if (typeof callBackFn !== 'function') {
throw new TypeError('callBackFn is not function');
}
// 此方法不行,如果在回调函数中更改数组的长度,那么会导致死循环。
// for (let key in O) {
// if (callBackFn.call(arguments[1], O[key], key, O)) {
// return O[key];
// }
// }
var key = 0;
while (key < len) {
if (callBackFn.call(arguments[1], O[key], key, O)) {
return O[key];
}
key++;
}
return undefined;
}
Array.prototype.findIndex( )
语义根据回调函数,找到第一个满足回调函数的元素的索引值。
关键点没有找到值时,返回-1。
语法Array.prototype.findIndex(callbackFn(element[, index, array])[, thisArg])
/**
*@param {function} callbackFn 回调函数返回的是Boolean值。
*@param [this.Arg] 改变回调函数内部的this值。
*@return {value = -1} 满足回调函数的第一个元素索引值。
*/
例子polyfill
Array.prototype.myFindIndex = function (callBackFn) {
//排除this最为对象时的null值
if (this === null) {
throw new TypeError('this is not null');
}
var O = Object(this);
// 满足类数组,检查length属性值非负整数。
var len = O.length >>> 0;
//检查参数
if (typeof callBackFn !== 'function') {
throw new TypeError('callBackFn is not function');
}
// 此方法不行,如果在回调函数中更改数组的长度,那么会导致死循环。
// for (let key in O) {
// if (callBackFn.call(arguments[1], O[key], key, O)) {
// return O[key];
// }
// }
var key = 0;
while (key < len) {
if (callBackFn.call(arguments[1], O[key], key, O)) {
return key;
}
key++;
}
return -1;
}
Array.prototype.copyWithin(target[, start, end])
语义移动数组元素:将数组内的一部分元素,复制粘贴到数组的另一个位置。
关键点该方法可以通过call()、apply()用于类数组对象。
/**
*@param {number} target 粘贴数组片段的起点位置
*@param {number = 0} start 复制数组片段开始位置
*@return {number = arr.length} 复制数组片段开始位置(不包含该位置本身)
*/
var a = [1, 2, 3, 4, 5];
var b = a.copyWithin(0, 2);
console.log(b); //[ 3, 4, 5, 4, 5 ]
例子polyfill
比较两个数字的大小,可以使用Math.max/min 的方法
//myCopyWithin(target,[start, end]) //可用于类数组,注意this类型,length属性的类型。 Array.prototype.myCopyWithin = function (target) { if (this === null) { throw new TypeError('this is null or not defined') } //原始值也转为对象。 var O = Object(this); //判读类数组中的length属性值,必须是正整数。 // 1、转化为整数 var toInteger = function (value) { var num = Number(value); if (isNaN(num)) { return 0 }; if (num === 0 || !isFinite(num)) { return num }; return (num > 0 ? 1 : -1) * Math.floor(Math.abs(num)); } // 2、限制范围,0~finite。除去负数和无限值 var toLength = function (value) { var maxSafeInteger = Number.MAX_SAFE_INTEGER, len = toInteger(value); return Math.min(Math.max(len, 0), maxSafeInteger); } var len = toLength(this.length); var tarNumber = toInteger(target); var to = tarNumber < 0 ? Math.max(len + tarNumber, 0) : Math.min(tarNumber, len); var startNumber = toInteger(arguments[1]); var start = startNumber < 0 ? Math.max(len + startNumber, 0) : Math.min(startNumber, len); var endNumber = arguments[2] === undefined ? len : toInteger(arguments[2]); var end = endNumber < 0 ? Math.max(len + endNumber, 0) : Math.min(endNumber, len); //复制数组片段的长度 var count = Math.min(end - start, len - to); var direction = 1; if (start < to && to < start + count) { //后一个判断表示复制粘贴的数组有重叠部分。 direction = -1; start += count - 1; to += count - 1; } while (count > 0) { if (start in O) { O[to] = O[start]; } else { delete O[to]; } start += direction; to += direction; count--; } return O; }
Array.prototype.fill(value[, start, end])
语义在[start, end)区间,填充一样的value值。
关键点该方法可以通过call()、apply()用于类数组对象。/** *@param {number} value 填充的值 *@param {number = 0} start 复制数组片段开始位置 *@return {number = arr.length} 复制数组片段开始位置(不包含该位置本身) */ var a = ['a', 'b', 'c', 'd', 'e']; console.log(a.fill(1)); //[ 1, 1, 1, 1, 1 ]
例子polyfill
Array.prototype.myFill = function (value) { var relStart = arguments[1], relEnd = arguments[2]; //step1: 由于类数组也可以用此方法,判断this、length if (this === null) { throw new TypeError('this is null'); } var O = Object(this); var len = O.length >>> 0; //len必须是正整数 //step2: 参数类型判断 relStart >>= 0; start = relStart < 0 ? Math.max(len + relStart, 0) : Math.min(relStart, len); relEnd = relEnd === undefined ? len : arguments[2] >> 2; end = relEnd < 0 ? Math.max(len + relEnd, 0) : Math.min(relEnd, len); if (start < end) { O[start] = value; start++; } return O; }
Array.prototype.flat([depth])
语义将嵌套的数组结构展开,可以指定递归的层数。
/** *@param {number=1} depth *@return {array} 相同的展开数组。 */
例子polyfill
尾递归一定要先写递归终止语句。一般是return语句或者是带有副作用的语句。 ```javascript Array.prototype.myFlat = function () { if (!Array.isArray(this)) {
throw new TypeError('this is not Array');
} var depth = arguments[0] === undefined ? 1 : arguments[0] >>> 0;
var res = []; var flatDeep = function (arr, depth) {arr.forEach(element => { if (depth > 0 && Array.isArray(element)) { flatDeep(element, depth - 1); } else { res.push(element); //递归终止语句 } });
}; flatDeep(this, depth); return res; }
//运用栈算法,push和pop Array.prototype.myFlat = function () { if (!Array.isArray(this)) { throw new TypeError(‘this is not Array’); } var depth = arguments[0] === undefined ? 1 : arguments[0] >>> 0; var res = [], stack = […this]; //浅拷贝一份原数组
while (stack.length) {
var popElement = stack.pop();
if (Array.isArray(popElement)) {
stack.push(...popElement);
} else {
res.unshift(popElement);
}
}
return res;
}
<a name="iApZS"></a>
## Array.prototype.flatMap( )
语义数组展开一次,再进行映射。<br />语法flatMap( function callbackFn( currentValue, index, array ) { ... }, [thisArg] )<br />关键点原数组不改变。
```javascript
/**
*@param {function} callbackFn map函数
*@param [this.Arg] 改变回调函数内部的this值。
*@return {array} 新数组。
*/
var arr = [1, [2], [[3, 4, 5]]];
console.log(arr.flatMap(x => x));
console.log(arr); //[ 1, 2, [ 3, 4, 5 ] ]
例子polyfill
if (!Array.prototype.flatMap) {
Object.defineProperty(Array.prototype, 'flatMap', {
configurable: true,
writable: true,
value: function () {
return Array.prototype.map.apply(this, arguments).flat(1);
},
});
}
Array.prototype.map( )
let deepClone = source => {
let target = Array.isArray(source) ? [] : {};
for (let key in source) {
if (source.hasOwnProperty(key)) {
if (typeof source[key] === 'object' && source[key] !== null) { //不判断null
target[key] = deepClone(source[key]); //递归的返回值target,赋值给target[key]
} else {
target[key] = source[key];
}
}
}
return target;
}
Array.prototype.myMap = function(callbackFn){
var arg2 = arguments[1] || window,
len = this.length,
mapArray = [];
for (let i = 0; i < len; i++) {
var element = deepClone(this[i]),
returnValue = callbackFn.apply(arg2, [element, i , this]);
mapArray.push(returnValue);
}
return mapArray;
}
Array.prototype.filter( )
let deepClone = source => {
let target = Array.isArray(source) ? [] : {};
for (let key in source) {
if (source.hasOwnProperty(key)) {
if (typeof source[key] === 'object' && source[key] !== null) { //不判断null
target[key] = deepClone(source[key]); //递归的返回值target,赋值给target[key]
} else {
target[key] = source[key];
}
}
}
return target;
}
Array.prototype.myFilter = function (callbackFn) {
var backThis = arguments[1] || window; //保存形参中的this的值,改变回调函数this
var filterArray = [],
len = this.length;
for (let i = 0; i < len; i++) {
var element = deepClone(this[i]);
if (callbackFn.apply(backThis, [element, i, this])) {
filterArray.push(element);
}
}
return filterArray;
}
Array.prototype.every( )
Array.prototype.myEvery = function (callbackFn) {
var arg2 = arguments[1] || window,
len = this.length,
res = true;
for (let i = 0; i < len; i++) {
res = callbackFn.apply(arg2, [this[i], i, this]);
if(res === false){
break;
}
}
return res;
}
Array.prototype.some( )
Array.prototype.mySome = function (callbackFn) {
var arg2 = arguments[1] || window,
len = this.length,
res = false;
for (let i = 0; i < len; i++) {
res = callbackFn.apply(arg2, [this[i], i, this]);
if(res === true){
break;
}
}
return res;
}
Array.prototype.reduce( )
Array.prototype.myReduce = function (callbackFn, initial) {
var len = this.length,
prev = initial;
for (let i = 0; i < len; i++) {
prev = callbackFn(prev, this[i], i, this);
}
return prev;
}