JS 基础:数组方法实现
总结至 MDN
forEach
forEach()
方法按升序为数组中含有效值的每一项执行一次 callback
函数,那些已删除或者未初始化的项将被跳过。
forEach 语法
arr.forEach(callback(currentValue [, index [, array]])[, thisArg]);
forEach 参数
callback
: 为数组中每个元素执行的函数,该函数接收三个参数currentValue
: 数组中正在处理的当前元素index
(可选): 数组中正在处理的当前元素的索引array
(可选):forEach()
方法正在操作的数组thisArg
(可选): 当执行回调函数callback
时,用作this
的值
forEach 返回值
undefined
forEach Polyfill
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (callback, thisArg) {
var T, k;
if (this == null) {
throw new TypeError(' this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0; //头部补零的右移运算符,表示将一个数的二进制值向右移动指定的位数.此处的目的是将任意值转化为Number,且不会出现NaN
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
T = thisArg;
}
k = 0;
while (k < len) {
var kValue;
if (k in O) {
kValue = O[k];
callback.call(T, kValue, k, O);
}
k++;
}
};
}
filter
filter 描述
filter
为数组中的每个元素调用一次 callback
函数,并利用所有使得 callback
返回 true
或等价于 true
的值的元素创建一个新数组。
callback
只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback
测试的元素会被跳过,不会被包含在新数组中。
filter
不会改变原数组,它返回过滤后的新数组。
filter
遍历的元素范围在第一次调用 callback
之前就已经确定了。在调用 filter
之后被添加到数组中的元素不会被 filter
遍历到。
filter 语法
var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
filter 参数
callback
: 用来测试数组的每个元素的函数。返回 true 表示该元素通过测试,保留该元素,false 则不保留。element
: 数组中正在处理的当前元素index
(可选): 数组中正在处理的当前元素的索引array
(可选): 调用了filter
的数组本身thisArg
(可选): 当执行回调函数callback
时,用作this
的值
filter 返回值
一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。
filter Polyfill
if (!Array.prototype.filter) {
Array.prototype.filter = function (func, thisArg) {
'use strict';
if (!((typeof func === 'Function' || typeof func === 'function') && this)) throw new TypeError();
var len = this.length >>> 0,
res = new Array(len),
t = this,
c = 0,
i = -1;
if (arguments.length > 1) {
T = thisArg;
}
while (++i !== len) {
if (i in this) {
if (func.call(T, t[i], i, t)) {
res[c++] = t[i];
}
}
}
res.length = c;
return res;
};
}
every
every 描述
every
方法为数组中的每个元素执行一次 callback
函数,直到它找到一个会使 callback
返回 falsy
的元素。如果发现了一个这样的元素,every
方法将会立即返回 false
。否则,callback
为每一个元素返回 true
,every
就会返回 true
。
every
遍历的元素范围在第一次调用 callback
之前就已确定了。在调用 every
之后添加到数组中的元素不会被 callback
访问到。如果数组中存在的元素被更改,则他们传入 callback
的值是 every
访问到他们那一刻的值。那些被删除的元素或从来未被赋值的元素将不会被访问到。
every
不会改变原数组。
若收到一个空数组,此方法在一切情况下都会返回 true
。
every 语法
arr.every(callback(element [, index [, array]])[, thisArg])
every 参数
callback
: 用来测试每个元素的函数,它可以接收三个参数element
: 用于测试的当前值index
(可选): 用于测试的当前值的索引array
(可选): 调用every
的当前数组thisArg
(可选): 当执行回调函数callback
时,用作this
的值
every 返回值
如果回调函数的每一次返回都为 truthy
值,返回 true
,否则返回 false
。
every Polyfill
if (!Array.prototype.every) {
Array.prototype.every = function (callbackfn, thisArg) {
'use strict';
var T, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;
if (typeof callbackfn !== 'function') {
throw new TypeError();
}
if (arguments.length > 1) {
T = thisArg;
}
k = 0;
while (k < len) {
var kValue;
if (k in O) {
kValue = O[k];
var testResult = callbackfn.call(T, kValue, k, O);
if (!testResult) {
return false;
}
}
k++;
}
return true;
};
}
some
some 描述
some()
为数组中的每一个元素执行一次 callback
函数,直到找到一个使得 callback
返回一个“真值”(即可转换为布尔值 true
的值)。如果找到了这样一个值,some()
将会立即返回 true
。否则,some()
返回 false
。
some()
被调用时不会改变数组。
some()
遍历的元素的范围在第一次调用 callback
. 前就已经确定了。在调用 some()
后被添加到数组中的值不会被 callback
访问到。如果数组中存在且还未被访问到的元素被 callback
改变了,则其传递给 callback
的值是 some()
访问到它那一刻的值。已经被删除的元素不会被访问到。
some 语法
arr.some(callback(element[, index[, array]])[, thisArg])
some 参数
callback
: 用来测试每个元素的函数,接受三个参数element
: 数组中正在处理的元素index
(可选): 数组中正在处理的元素的索引值array
(可选):some()
被调用的数组thisArg
(可选): 执行callback
时使用的this
值
some 返回值
数组中有至少一个元素通过回调函数的测试就会返回 true
, 所有元素都没有通过回调函数的测试返回值才会为 false
。
some Polyfill
if (!Array.prototype.some) {
Array.prototype.some = function (fun, thisArg) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.some called on null or undefined');
}
if (typeof fun !== 'function') {
throw new TypeError();
}
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;
};
}
map
map 描述
map
方法会给原数组中的每个元素都按顺序调用一次 callback
函数。callback
每次执行后的返回值(包括 undefined
)组合起来形成一个新数组。 callback
函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete
删除的索引则不会被调用。
因为 map
生成一个新数组,当你不打算使用返回的新数组却使用 map
是违背设计初衷的,请用 forEach
或者 for-of
替代。
map
不修改调用它的原数组本身(当然可以在 callback
执行时改变原数组)。
map
方法处理数组元素的范围是在 callback
方法第一次调用之前就已经确定了。调用 map 方法之后追加的数组元素不会被 callback
访问。如果存在的数组元素改变了,那么传给 callback
的值是 map
访问该元素时的值。
map 语法
var newArray = arr.map(callback(currentValue[, index[, array]])[, thisArg])
map 参数
callback
: 生成新数组元素的函数,接受三个参数currentValue
:callback
数组中正在处理的当前元素index
(可选):callback
数组中正在处理的当前元素的索引array
(可选):map
方法调用的数组thisArg
(可选): 执行callback
时使用的this
值
map 返回值
返回一个新数组,回调函数的结果组成了新数组的每一个元素。
map Polyfill
if (!Array.prototype.map) {
Array.prototype.map = function (callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
T = arguments[1];
}
A = new Array(len);
k = 0;
while (k < len) {
var kValue, mappedValue;
if (k in O) {
kValue = O[k];
mappedValue = callback.call(T, kValue, k, O);
A[k] = mappedValue;
}
k++;
}
return A;
};
}
reduce
reduce 描述
reduce
为数组中的每一个元素依次执行 callback
函数,不包括数组中被删除或从未被赋值的元素。
callback
第一次执行时,如果提供了 initialValue
,accumulator
取值为 initialValue
,currentValue
取数组中的第一个值,reduce
会从索引 0 的地方开始执行 callback
方法;如果没有提供 initialValue
,那么 accumulator
取数组中的第一个值,currentValue
取数组中的第二个值,reduce
会从索引 1 的地方开始执行 callback
方法。
如果数组仅有一个元素(无论位置如何)并且没有提供 initialValue
, 或者有提供 initialValue
但是数组为空,那么此唯一值将被返回并且 callback
不会被执行。
reduce 语法
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
reduce 参数
callback
: 执行数组中每个值 (如果没有提供initialValue
则第一个值除外)的函数,包含四个参数accumulator
: 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue
currentValue
:callback
数组中正在处理的当前元素index
(可选): 数组中正在处理的当前元素的索引。 如果提供了initialValue
,则起始索引号为 0,否则从索引 1 起始。array
(可选): 调用reduce()
的数组initialValue
(可选): 作为第一次调用callback
函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用reduce
将报错。
reduce 返回值
函数累计处理的结果
reduce Polyfill
if (!Array.prototype.reduce) {
Object.defineProperty(Array.prototype, 'reduce', {
value: function (callback, initialValue) {
if (this === null) {
throw new TypeError('Array.prototype.reduce ' + 'called on null or undefined');
}
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
var o = Object(this);
var len = o.length >>> 0;
var k = 0;
var value;
if (arguments.length >= 2) {
value = arguments[1];
} else {
while (k < len && !(k in o)) {
k++;
}
if (k >= len) {
throw new TypeError('Reduce of empty array ' + 'with no initial value');
}
value = o[k++];
}
while (k < len) {
if (k in o) {
value = callback(value, o[k], k, o);
}
k++;
}
return value;
},
});
}
扩展
flat
?
即将多维数组拍平(flatten)为一维数组。
递归
function wrap() {
var ret = [];
return function flat(a) {
for (var item of a) {
if (item.constructor === Array) {
ret.concat(flat(item));
} else {
ret.push(item);
}
}
return ret;
};
}
console.log(wrap()(arr));
迭代
const flatten = function (arr) {
while (arr.some((item) => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
};
console.log(flatten(arr));