本篇文章给大家介绍25个数组方法,通过实现25个数组方法来来理解及高效使用这些数组方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。
|
本篇文章给大家介绍25个数组方法,通过实现25个数组方法来来理解及高效使用这些数组方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。
要在给定数组上使用方法,只需要通过 没有比把东西拆开再重新组装起来更好的学习方法了。注意,当咱们的实现自己的方法时,不要覆盖现有的方法,因为有的库需要它们,并且这样也方便比较咱们自己的方法与原始方法的差异。 所以不要这样命名咱们自定义的方法: Array.prototype.map = function map() {
// implementation
};最好这样命名: function map(array) {
// implementation
}咱们也可以通过使用 class OwnArray extends Array {
public constructor(...args) {
super(...args);
}
public map() {
// implementation
return this;
}
}唯一的区别是,我们不使用数组参数,而是使用 但是,我觉得 class 方式带来不必要的混乱,所以咱们采用第一种方法。 有了这个,咱们先从实现最简单的方法 集合类.forEach
[1, 2, 3, 4, 5].forEach(value => console.log(value)); 实现 function forEach(array, callback) {
const { length } = array;
for (let index = 0; index < length; index += 1) {
const value = array[index];
callback(value, index, array)
}
}咱们遍历数组并为每个元素执行回调。这里需要注意的一点是,该方法没有返回什么,所以默认返回 方法涟 使用数组方法的好处是可以将操作链接在一起。考虑以下代码: function getTodosWithCategory(todos, category) {
return todos
.filter(todo => todo.category === category)
.map(todo => normalizeTodo(todo));
}这种方式,咱们就不必将 不幸的是, // 无法工作
function getTodosWithCategory(todos, category) {
return todos
.filter(todo => todo.category === category)
.forEach((value) => console.log(value))
.map(todo => normalizeTodo(todo));
}帮助函数 (打印信息)接着实现一个简单的函数,它能更好地解释每个方法的功能:接受什么作为输入,返回什么,以及它是否对数组进行了修改。 function logOperation(operationName, array, callback) {
const input = [...array];
const result = callback(array);
console.log({
operation: operationName,
arrayBefore: input,
arrayAfter: array,
mutates: mutatesArray(input, array), // shallow check
result,
});
}其中 mutatesArray 方法用来判断是否更改了原数组,如果有修改刚返回 function mutatesArray(firstArray, secondArray) {
if (firstArray.length !== secondArray.length) {
return true;
}
for (let index = 0; index < firstArray.length; index += 1) {
if (firstArray[index] !== secondArray[index]) {
return true;
}
}
return false;
}然后使用 logOperation('forEach', [1, 2, 3, 4, 5], array => forEach(array, value => console.log(value)));打印结果: {
operation: 'forEach',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: undefined
}.map
实现 function map(array, callback) {
const result = [];
const { length } = array;
for (let index = 0; index < length; index +=1) {
const value = array[index];
result[index] = callback(value, index, array);
}
return result;
}提供给方法的回调函数接受旧值作为参数,并返回一个新值,然后将其保存在新数组中的相同索引下,这里用变量 这里需要注意的是,咱们返回了一个新的数组,不修改旧的。 测试 logOperation('map', [1, 2, 3, 4, 5], array => map(array, value => value + 5));打印结果: {
operation: 'map',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: [ 6, 7, 8, 9, 10 ]
}.filter
[1, 2, 3, 4, 5].filter(number => number >= 3);
// -> [3, 4, 5]实现 function push(array, ...values) {
const { length: arrayLength } = array;
const { length: valuesLength } = values;
for (let index = 0; index < valuesLength; index += 1) {
array[arrayLength + index] = values[index];
}
return array.length;
}
--------------------------------------------------
function filter(array, callback) {
const result = [];
const { length } = array;
for (let index = 0; index < length; index += 1) {
const value = array[index];
if (callback(value, index, array)) {
push(result, value);
}
}
return result;
}获取每个值并检查所提供的回调函数是否返回 注意,这里对 测试 logOperation('filter', [1, 2, 3, 4, 5], array => filter(array, value => value >= 2));运行: {
operation: 'filter',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: [ 2, 3, 4, 5 ]
}.reduce
确切地说,如何计算该值是需要在回调中指定的。来看呓使用 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].reduce((sum, number) => {
return sum + number;
}, 0) // -> 55注意这里的回调接受两个参数: 这里,当咱们对数组进行迭代时, 实现 function reduce(array, callback, initValue) {
const { length } = array;
let acc = initValue;
let startAtIndex = 0;
if (initValue === undefined) {
acc = array[0];
startAtIndex = 0;
}
for (let index = startAtIndex; index < length; index += 1) {
const value = array[index];
acc = callback(acc, value, index, array)
}
return acc;
}咱们创建了两个变量 然后,检查 每次迭代, 测试 logOperation('reduce', [1, 2, 3, 4, 5], array => reduce(array, (sum, number) => sum + number, 0));运行: { operation: 'reduce',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: 15
}检索类有什么操作比搜索特定值更常见?这里有一些方法可以帮助我们。 .findIndex
[1, 2, 3, 4, 5, 6, 7].findIndex(value => value === 5); // 4
实现 function findIndex(array, callback) {
const { length } = array;
for (let index = 0; index < length; index += 1) {
const value = array[index];
if (callback(value, index, array)) {
return index;
}
}
return -1;
}测试 logOperation('findIndex', [1, 2, 3, 4, 5], array => findIndex(array, number => number === 3));运行: {
operation: 'findIndex',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: 2
}.find
[1, 2, 3, 4, 5, 6, 7].find(value => value === 5); // 5 实现 function find(array, callback) {
const index = findIndex(array, callback);
if (index === -1) {
return undefined;
}
return array[index];
}测试 logOperation('find', [1, 2, 3, 4, 5], array => find(array, number => number === 3));运行 {
operation: 'find',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: 3
}.indexOf
[3, 2, 3].indexOf(3); // -> 0 实现 function indexOf(array, searchedValue) {
return findIndex(array, value => value === searchedValue)
}测试 logOperation('indexOf', [1, 2, 3, 4, 5], array => indexOf(array, 3));执行结果 {
operation: 'indexOf',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: 2
}.lastIndexOf lastIndexOf的工作方式与 [3, 2, 3].lastIndexOf(3); // -> 2 实现 function lastIndexOf(array, searchedValue) {
for (let index = array.length - 1; index > -1; index -= 1 ){
const value = array[index];
if (value === searchedValue) {
return index;
}
}
return -1;
}代码基本与 测试 logOperation('lastIndexOf', [1, 2, 3, 4, 5, 3], array => lastIndexOf(array, 3));执行结果 {
operation: 'lastIndexOf',
arrayBefore: [ 1, 2, 3, 4, 5, 3 ],
arrayAfter: [ 1, 2, 3, 4, 5, 3 ],
mutates: false,
result: 5
}.every
[1, 2, 3].every(value => Number.isInteger(value)); // -> true 咱们可以将 实现 function every(array, callback){
const { length } = array;
for (let index = 0; index < length; index += 1) {
const value = array[index];
if (!callback(value, index, array)) {
return false;
}
}
return true;
}咱们为每个值执行回调。如果在任何时候返回 测试 logOperation('every', [1, 2, 3, 4, 5], array => every(array, number => Number.isInteger(number)));执行结果 {
operation: 'every',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: true
}.some
[1, 2, 3, 4, 5].some(number => number === 5); // -> true 实现 function some(array, callback) {
const { length } = array;
for (let index = 0; index < length; index += 1) {
const value = array[index];
if (callback(value, index, array)) {
return true;
}
}
return false;
}咱们为每个值执行回调。如果在任何时候返回 测试 logOperation('some', [1, 2, 3, 4, 5], array => some(array, number => number === 5));执行结果 {
operation: 'some',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: true
}.includes
[1, 2, 3].includes(3); // -> true 实现 function includes(array, searchedValue){
return some(array, value => value === searchedValue)
}测试 logOperation('includes', [1, 2, 3, 4, 5], array => includes(array, 5));执行结果 {
operation: 'includes',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: true
}拼接、附加和反转数组.concat
[1, 2, 3].concat([4, 5], 6, [7, 8]) // -> [1, 2, 3, 4, 5, 6, 7, 8] 实现 function concat(array, ...values) {
const result = [...array];
const { length } = values;
for (let index = 0; index < length; index += 1) {
const value = values[index];
if (Array.isArray(value)) {
push(result, ...value);
} else {
push(result, value);
}
}
return result;
}
首先,通过复制传入的数组创建
测试 logOperation('concat', [1, 2, 3, 4, 5], array => concat(array, 1, 2, [3, 4]));执行结果 {
operation: 'concat',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: [ 1, 2, 3, 4, 5, 1, 2, 3, 4 ]
}.join
['Brian', 'Matt', 'Kate'].join(', ') // -> Brian, Matt, Kate实现 function join(array, joinWith) {
return reduce(
array,
(result, current, index) => {
if (index === 0) {
return current;
}
return `${result}${joinWith}${current}`;
},
''
)
}
测试 logOperation('join', [1, 2, 3, 4, 5], array => join(array, ', '));执行结果 {
operation: 'join',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: '1, 2, 3, 4, 5'
}.reverse
实现 function reverse(array) {
const result = []
const lastIndex = array.length - 1;
for (let index = lastIndex; index > -1; index -= 1) {
const value = array[index];
result[lastIndex - index ] = value
}
return result;
}其思路很简单:首先,定义一个空数组,并将数组的最后一个索引保存为 测试 logOperation('reverse', [1, 2, 3, 4, 5], array => reverse(array));执行结果 {
operation: 'reverse',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: [ 5, 4, 3, 2, 1 ]
}添加、删除和追加值.shift
[1, 2, 3].shift(); // -> 1 实现 function shift(array) {
const { length } = array;
const firstValue = array[0];
for (let index = 1; index > length; index += 1) {
const value = array[index];
array[index - 1] = value;
}
array.length = length - 1;
return firstValue;
}首先保存数组的原始长度及其初始值,然后遍历数组并将每个值向下移动一个索引。完成遍历后,更新数组的长度并返回初始值。 测试 logOperation('shift', [1, 2, 3, 4, 5], array => shift(array));执行结果 {
operation: 'shift',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 2, 3, 4, 5 ],
mutates: true,
result: 1
}.unshift
[2, 3, 4].unshift(1); // -> [1, 2, 3, 4] 实现 function unshift(array, ...values) {
const mergedArrays = concat(values, ...array);
const { length: mergedArraysLength } = mergedArrays;
for (let index = 0; index < mergedArraysLength; index += 1) {
const value = mergedArrays[index];
array[index] = value;
}
return array.length;
}首先将需要加入数组值(作为参数传递的单个值)和数组拼接起来。这里需要注意的是, 然后保存这个新数组的长度并遍历它,将它的值保存在原始数组中,并覆盖开始时的值。 测试logOperation('unshift', [1, 2, 3, 4, 5], array => unshift(array, 0));执行结果 {
operation: 'unshift',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 0, 1, 2, 3, 4, 5 ],
mutates: true,
result: 6
}.slice slice() 方法返回一个新的数组对象,这一对象是一个由
[1, 2, 3, 4, 5, 6, 7].slice(3, 6); // -> [4, 5, 6] 实现 (简单实现) function slice(array, startIndex = 0, endIndex = array.length) {
const result = [];
for (let index = startIndex; index < endIndex; index += 1) {
const value = array[index];
if (index < array.length) {
push(result, value);
}
}
return result;
}咱们遍历数组从 注意: 测试 logOperation('slice', [1, 2, 3, 4, 5], array => slice(array, 1, 3));执行结果 {
operation: 'slice',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: [ 2, 3 ]
}.splice
首先,指定起始索引,然后指定要删除多少个值,其余的参数是要插入的值。 const arr = [1, 2, 3, 4, 5];
// 从位置0开始,删除2个元素后插入 3, 4, 5
arr.splice(0, 2, 3, 4, 5);
arr // -> [3, 4, 5, 3, 4, 5]实现 function splice( array, insertAtIndex, removeNumberOfElements, ...values) {
const firstPart = slice(array, 0, insertAtIndex);
const secondPart = slice(array, insertAtIndex + removeNumberOfElements);
const removedElements = slice(
array,
insertAtIndex,
insertAtIndex + removeNumberOfElements
);
const joinedParts = firstPart.concat(values, secondPart);
const { length: joinedPartsLength } = joinedParts;
for (let index = 0; index < joinedPartsLength; index += 1) {
array[index] = joinedParts[index];
}
array.length = joinedPartsLength;
return removedElements;
}其思路是在 测试 logOperation('splice', [1, 2, 3, 4, 5], array => splice(array, 1, 3));执行结果 {
operation: 'splice',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 5 ],
mutates: true,
result: [ 2, 3, 4 ]
}.pop
实现 function pop(array) {
const value = array[array.length - 1];
array.length = array.length - 1;
return value;
}首先,将数组的最后一个值保存在一个变量中。然后只需将数组的长度减少 测试 logOperation('pop', [1, 2, 3, 4, 5], array => pop(array));执行结果 {
operation: 'pop',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4 ],
mutates: true,
result: 5
}.push
[1, 2, 3, 4].push(5); // -> [1, 2, 3, 4, 5] 实现 function push(array, ...values) {
const { length: arrayLength } = array;
const { length: valuesLength } = values;
for (let index = 0; index < valuesLength; index += 1) {
array[arrayLength + index] = values[index];
}
return array.length;
}首先,我们保存原始数组的长度,以及在它们各自的变量中要添加的值。然后,遍历提供的值并将它们添加到原始数组中。 测试 logOperation('push', [1, 2, 3, 4, 5], array => push(array, 6, 7));执行结果 {
operation: 'push',
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [
1, 2, 3, 4,5, 6, 7
],
mutates: true,
result: 7
}.fill 当咱们想用一个占位符值填充一个空数组时,可以使用 [...Array(5)].fill(null) // -> [null, null, null, null, null] 实现 function fill(array, value, startIndex = 0, endIndex = array.length) {
for (let index = startIndex; index < endIndex; index += 1) {
array[index] = value;
}
return array;
}
测试 logOperation("fill", [...new Array(5)], array => fill(array, 0));执行结果 {
operation: 'fill',
arrayBefore: [ undefined, undefined, undefined, undefined, undefined ],
arrayAfter: [ 0, 0, 0, 0, 0 ],
mutates: true,
result: [ 0, 0, 0, 0, 0 ]
}扁平类有时咱们的数组会变嵌套两到三层,咱们想要将它们扁,也就是减少嵌套的程度。例如,想将所有值都放到顶层。为咱们提供帮助有两个新特性: .flat
[1, 2, 3, [4, 5, [6, 7, [8]]]].flat(1); // -> [1, 2, 3, 4, 5, [6, 7, [8]]] 因为展开的深度值是 [1, 2, 3, [4, 5]].flat(1) // -> [1, 2, 3, 4, 5] 实现 function flat(array, depth = 0) {
if (depth < 1 || !Array.isArray(array)) {
return array;
}
return reduce(
array,
(result, current) => {
return concat(result, flat(current, depth - 1));
},
[],
);
}首先,我们检查 其次,咱们检查数组参数是否属于数组类型,因为如果它不是,那么扁化就没有意义了,所以只返回这个参数。 咱们们使用了之前实现的 注意,我们调用带有 测试 logOperation('flat', [1, 2, 3, [4, 5, [6]]], array => flat(array, 2));执行结果 {
operation: 'flat',
arrayBefore: [ 1, 2, 3, [ 4, 5, [Array] ] ],
arrayAfter: [ 1, 2, 3, [ 4, 5, [Array] ] ],
mutates: false,
result: [ 1, 2, 3, 4, 5, 6 ]
}.flatMap
在上面的 [1, 2, 3].flatMap(value => [value, value, value]); // [1, 1, 1, 2, 2, 2, 3, 3, 3] 每个返回的数组都是扁平的,我们得到的不是一个嵌套了三个数组的数组,而是一个包含9个元素的数组。 实现 function flatMap(array, callback) {
return flat(map(array, callback), 1);
}首先使用 测试 logOperation('flatMap', [1, 2, 3], array => flatMap(array, number => [number, number]));执行结果 {
operation: 'flatMap',
arrayBefore: [ 1, 2, 3 ],
arrayAfter: [ 1, 2, 3 ],
mutates: false,
result: [ 1, 1, 2, 2, 3, 3 ]
}generator 类最后三种方法的特殊之处在于它们返回生成器的方式。如果你不熟悉生成器,请跳过它们,因为你可能不会很快使用它们。 .values
const valuesGenerator = values([1, 2, 3, 4, 5]);
valuesGenerator.next(); // { value: 1, done: false }实现 function values(array) {
const { length } = array;
function* createGenerator() {
for (let index = 0; index < length; index += 1) {
const value = array[index];
yield value;
}
}
return createGenerator();
}首先,咱们定义 .keys
const keysGenerator = keys([1, 2, 3, 4, 5]);
keysGenerator.next(); // { value: 0, done: false }实现 function keys(array) {
function* createGenerator() {
const { length } = array;
for (let index = 0; index < length; index += 1) {
yield index;
}
}
return createGenerator();
}实现完全相同,但这一次,生成的是索引,而不是值。 .entries
const entriesGenerator = entries([1, 2, 3, 4, 5]);
entriesGenerator.next(); // { value: [0, 1], done: false }实现 function entries(array) {
const { length } = array;
function* createGenerator() {
for (let index = 0; index < length; index += 1) {
const value = array[index];
yield [index, value];
}
}
return createGenerator();
}同样的实现,但现在咱们将索引和值结合起来,并在数组中生成它们。 总结高效使用数组的方法是成为一名优秀开发人员的基础。了解他们内部工作的复杂性是我所知道的最好的方法。
更多编程相关知识,请访问:编程教学!! 以上就是通过实现25个数组方法来理解它们(收藏)的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |
