做者:Maciej Cieslar
译者:前端小智
来源: dev
阿里云最近在作活动,低至2折,有兴趣能够看看:
https://promotion.aliyun.com/...
为了保证的可读性,本文采用意译而非直译。html
要在给定数组上使用方法,只须要经过[].方法名
便可,这些方法都定义在 Array.prototype
对象上。在这里,我们先不使用这些相,反,我们将从简单的方法开始定义本身的版本,并在这些版本的基础上进行构建。前端
没有比把东西拆开再从新组装起来更好的学习方法了。注意,当我们的实现本身的方法时,不要覆盖现有的方法,由于有的库须要它们,而且这样也方便比较我们本身的方法与原始方法的差别。git
因此不要这样命名我们自定义的方法:github
Array.prototype.map = function map() { // implementation };
最好这样命名:数组
function map(array) { // implementation }
我们也能够经过使用class
关键字并扩展Array
构造函数来实现我们的方法,以下所示:函数
class OwnArray extends Array { public constructor(...args) { super(...args); } public map() { // implementation return this; } }
惟一的区别是,咱们不使用数组参数,而是使用this
关键字。工具
可是,我以为 class 方式带来没必要要的混乱,因此我们采用第一种方法。学习
有了这个,我们先从实现最简单的方法 forEach
开始!测试
Array.prototype.forEach
方法对数组的每一个元素执行一次提供的函数,并且不会改变原数组。this
[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) } }
我们遍历数组并为每一个元素执行回调。这里须要注意的一点是,该方法没有返回什么,因此默认返回undefined
。
方法涟
使用数组方法的好处是能够将操做连接在一块儿。考虑如下代码:
function getTodosWithCategory(todos, category) { return todos .filter(todo => todo.category === category) .map(todo => normalizeTodo(todo)); }
这种方式,我们就没必要将map
的执行结果保存到变量中,代码会更简洁。
不幸的是,forEach
没有返回原数组,这意味着我们不能作下面的事情
// 没法工做 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 方法用来判断是否更改了原数组,若是有修改刚返回 true
,不然返回 false
。固然大伙有好的想法能够在评论提出呦。
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
方法。
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
方法会给原数组中的每一个元素都按顺序调用一次 callback
函数。callback
每次执行后的返回值(包括 undefined
)组合起来造成一个新数组。
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; }
提供给方法的回调函数接受旧值做为参数,并返回一个新值,而后将其保存在新数组中的相同索引下,这里用变量 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 ] }
Array.prototype.filter
过滤回调返回为false
的值,每一个值都保存在一个新的数组中,而后返回。
[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; }
获取每一个值并检查所提供的回调函数是否返回true
或false
,而后将该值添加到新建立的数组中,或者适当地丢弃它。
注意,这里对result
数组使用push
方法,而不是将值保存在传入数组中放置的相同索引中。这样,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()
方法接收一个函数做为累加器,数组中的每一个值(从左到右)开始缩减,最终计算为一个值。reduce()
方法接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce() 的数组。
确切地说,如何计算该值是须要在回调中指定的。来看呓使用reduce
的一个简单的例子:对一组数字求和:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].reduce((sum, number) => { return sum + number; }, 0) // -> 55
注意这里的回调接受两个参数:sum
和number
。第一个参数老是前一个迭代返回的结果,第二个参数在遍历中的当前数组元素。
这里,当我们对数组进行迭代时,sum
包含到循环当前索引的全部数字的和由于每次迭代我们都将数组的当前值添加到sum
中。
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; }
我们建立了两个变量acc
和startAtIndex
,并用它们的默认值初始化它们,分别是参数initValue
和0
。
而后,检查initValue
是不是undefined
。若是是,则必须将数组的第一个值设置为初值,为了避免重复计算初始元素,将startAtIndex
设置为1
。
每次迭代,reduce
方法都将回调的结果保存在累加器(acc
)中,而后在下一个迭代中使用。对于第一次迭代,acc
被设置为initValue
或array[0]
。
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
findIndex
方法对数组中的每一个数组索引0..length-1
(包括)执行一次callback
函数,直到找到一个callback
函数返回真实值(强制为true
)的值。若是找到这样的元素,findIndex
会当即返回该元素的索引。若是回调从不返回真值,或者数组的length
为0
,则findIndex
返回-1
。
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
与findIndex
的惟一区别在于,它返回的是实际值,而不是索引。实际工做中,我们能够重用已经实现的findIndex
。
[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
是获取给定值索引的另外一种方法。然而,这一次,我们将实际值做为参数而不是函数传递。一样,为了简化实现,可使用前面实现的findIndex
[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的工做方式与indexOf
相同,lastIndexOf()
方法返回指定元素在数组中的最后一个的索引,若是不存在则返回 -1
。
[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; }
代码基本与findIndex
相似,可是没有执行回调,而是比较value
和searchedValue
。若是比较结果为 true
,则返回索引,若是找不到值,返回-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
我们能够将every
方法看做一个等价于逻辑与的数组。
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; }
我们为每一个值执行回调。若是在任什么时候候返回false
,则退出循环,整个方法返回false
。若是循环终止而没有进入到if
语句里面(说明条件都成立),则方法返回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
方法与 every
恰好相反,即只要其中一个为true
就会返回true
。与every
方法相似,我们能够将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; }
我们为每一个值执行回调。若是在任什么时候候返回true
,则退出循环,整个方法返回true
。若是循环终止而没有进入到if
语句里面(说明条件都不成立),则方法返回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
方法的工做方式相似于 some
方法,可是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; }
concat
将数组做为第一个参数,并将未指定个数的值做为第二个参数,这些值能够是数组,也能够是其余类型的值。
首先,经过复制传入的数组建立 result
数组。而后,遍历 values
,检查该值是不是数组。若是是,则使用push
函数将其值附加到结果数组中。
push(result, value)
只会向数组追加为一个元素。相反,经过使用展开操做符push(result,…value)
将数组的全部值附加到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}`; }, '' ) }
reduce
的回调是神奇之处:reduce
遍历所提供的数组并将结果字符串拼接在一块儿,在数组的值之间放置所需的分隔符(做为joinWith
传递)。
array[0]
值须要一些特殊的处理,由于此时result
是一个空字符串,并且我们也不但愿分隔符(joinWith
)位于第一个元素前面。
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; }
其思路很简单:首先,定义一个空数组,并将数组的最后一个索引保存为变量(lastIndex)
。接着反过来遍历数组,将每一个值保存在结果result
中的(lastIndex - index)
位置,而后返回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; }
首先将须要加入数组值(做为参数传递的单个值)和数组拼接起来。这里须要注意的是,values
放在第一位的,也就是放置在原始数组的前面。
而后保存这个新数组的长度并遍历它,将它的值保存在原始数组中,并覆盖开始时的值。
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()
方法返回一个新的数组对象,这一对象是一个由 begin
和 end
决定的原数组的浅拷贝(包括 begin
,不包括end
)原始数组不会被改变。
slice
会提取原数组中索引从 begin
到 end
的全部元素(包含 begin
,但不包含 end
)。
[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; }
我们遍历数组从startIndex
到endIndex
,并将每一个值放入result
。这里使用了这里的默认参数,这样当没有传递参数时,slice
方法只建立数组的副本。
注意:if
语句确保只在原始数组中存在给定索引下的值时才加入 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; }
其思路是在insertAtIndex
和insertAtIndex + removeNumberOfElements
上进行两次切割。这样,将原始数组切成三段。第一部分(firstPart
)和第三部分(secondPart
)加个插入的元素组成为最后数组的内容。
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; }
首先,将数组的最后一个值保存在一个变量中。而后只需将数组的长度减小1
,从而删除最后一个值。
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
方法。若是想建立一个指定数量的null
元素数组,能够这样作:
[...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; }
fill
方法真正作的是替换指定索引范围内的数组的值。若是没有提供范围,该方法将替换全部数组的值。
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
和flatMap
方法。
flat
方法经过可指定深度值来减小嵌套的深度。
[1, 2, 3, [4, 5, [6, 7, [8]]]].flat(1); // -> [1, 2, 3, 4, 5, [6, 7, [8]]]
由于展开的深度值是1
,因此只有第一级数组是被扁平,其他的保持不变。
[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)); }, [], ); }
首先,咱们检查depth
参数是否小于1
。若是是,那就意味着没有什么要扁平的,我们应该简单地返回数组。
其次,我们检查数组参数是否属于数组类型,由于若是它不是,那么扁化就没有意义了,因此只返回这个参数。
我们们使用了以前实现的reduce
函数。从一个空数组开始,而后取数组的每一个值并将其扁平。
注意,咱们调用带有(depth - 1)
的flat
函数。每次调用时,都递减depth
参数,以避免形成无限循环。扁平化完成后,将返回值来回加到result
数组中。
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()
方法首先使用映射函数映射每一个元素,而后将结果压缩成一个新数组。它与 map 和 深度值1的 flat 几乎相同,但 flatMap 一般在合并成一种方法的效率稍微高一些。
在上面的map
方法中,对于每一个值,只返回一个值。这样,一个包含三个元素的数组在映射以后仍然有三个元素。使用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); }
首先使用map
,而后将数组的结果数组扁平化一层。
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 ] }
最后三种方法的特殊之处在于它们返回生成器的方式。若是你不熟悉生成器,请跳过它们,由于你可能不会很快使用它们。
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(); }
首先,我们定义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(); }
实现彻底相同,但这一次,生成的是索引,而不是值。
entry
方法返回生成键值对的生成器。
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(); }
一样的实现,但如今我们将索引和值结合起来,并在数组中生成它们。
高效使用数组的方法是成为一名优秀开发人员的基础。了解他们内部工做的复杂性是我所知道的最好的方法。
代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug。
原文:https://dev.to/bnevilleoneill...
阿里云最近在作活动,低至2折,有兴趣能够看看:https://promotion.aliyun.com/...
干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。
https://github.com/qq44924588...
我是小智,公众号「大迁世界」做者,对前端技术保持学习爱好者。我会常常分享本身所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,便可看到福利,你懂的。
每次整理文章,通常都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励