当您需要在数组或字符串中找到一个元素时,‘indexOf()’是您最好的朋友之一。
「indexOf」在 Arrays
代码先,解释后:
1[label Module: findSpencer.js]
2const zoo = ['🐒', '🦄', '🐊', '🐸', '🐙'];
3const spencersIndex = zoo.indexOf('🐊');
4// spencersIndex === 2
5const spencer = zoo[spencersIndex];
6// spencer === '🐊'
在其最简单的版本中,indexOf
方法采用一个参数,这是我们试图找到的元素,然后它返回了它在数组中找到的第一个元素的索引,满足了el ===目标
。这意味着即使你的数组中有两个匹配, indexOf 只会返回一个结果。
当数组中的任何项目都没有满足el ===目标
检查时,返回-1
的值。
但是假设我们也在寻找Skyler(Spencer的妹妹),然后我们可以添加一个额外的可选参数来从不同的索引开始搜索。
1[label Module: findSkyler.js]
2const zoo = ['🐒', '🦄', '🐊', '🐸', '🐙', '🐊']; // Skyler just arrived!
3const spencersIndex = zoo.indexOf('🐊'); // === 2 same as before
4
5// We start searching after
6const skylersIndex = zoo.indexOf('🐊', spencersIndex + 1);
7// skylersIndex === 5
我们还可以在 Array 原型上创建一种方法,该方法会根据 indexOf 返回所有索引。
1[label Module: indicesOf.js]
2// Try to think of ways to make indicesOf more performant
3Array.prototype.indicesOf = function (target) {
4 const result = [];
5 let currentIndex = 0;
6 while(true) {
7 // here this === the array on which we call `indicesOf`
8 const targetIndex = this.indexOf(target, currentIndex);
9 if (targetIndex == -1)
10 break;
11
12 result.push(targetIndex);
13
14 currentIndex = targetIndex +1;
15 }
16
17 return result;
18}
19const zoo = ['🐒', '🦄', '🐊', '🐸', '🐙', '🐊']; // Skyler just arrived!
20const alligatorsIndices = zoo.indicesOf('🐊');
21// alligatorsIndices returns [2, 5]
你不能用 indexOf 找到什么?
您可能已经注意到,我们通过使用三重等同比较 el ===目标
(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness)来中断搜索,这意味着,例如,我们不能通过参考来测试其他数组、对象或函数。
1const simpleArray = [1, 2, 3];
2const simpleFunction = () => {console.log('hey')};
3const simpleObject = {alligator: 'cage'};
4
5const compositeArray = [simpleArray, simpleFunction, simpleObject];
6
7// These all work as expected because we compare by reference
8compositeArray.indexOf(simpleArray); // returns 0
9compositeArray.indexOf(simpleFunction); // returns 1
10compositeArray.indexOf(simpleObject); // returns 2
11
12// These won't work
13compositeArray.indexOf([1, 2, 3]); // returns -1
14compositeArray.indexOf(() => {console.log('hey')}); // returns -1
15compositeArray.indexOf({alligator: 'cage'}) // returns -1
深度指数
假设我们想创建一个实用程序,以便反复检查对象、数组和函数:
1[label Module: inDepthIndexOf.js]
2Array.prototype.deepIndexOf = function (target) {
3 // If the target is an object, array or a function, we give it a special treatment
4 if (typeof target === 'object' || typeof target === 'function') {
5 // We stringify the target
6 const searchTarget = target.toString()
7 // We loop through all of the elements of the array
8 for (let index = 0; index < this.length; index++){
9 const element = this[index]
10 // We check if the element in the array is an object or a function AND if so we check if its' stringified value is equal to our target
11 if ((typeof element === 'object' || typeof target === 'function') && element.toString() === searchTarget) {
12 // if we have a match we interrupt the loop and return the index
13 return index
14 }
15 }
16 // if nothing matched we return -1
17 return -1
18 }
19 return this.indexOf(target)
20}
21
22const simpleArray = [1, 2, 3];
23const simpleFunction = () => {console.log('hey')};
24const simpleObject = {alligator: 'cage'};
25
26const compositeArray = [simpleArray, simpleFunction, simpleObject];
27
28// These all work as expected because we compare by reference
29compositeArray.deepIndexOf(simpleArray); // returns 0
30// ... You know the rest
31// These will work!
32compositeArray.deepIndexOf([1, 2, 3]); // returns 0
33compositeArray.deepIndexOf(() => {console.log('hey')}); // returns 1
34compositeArray.deepIndexOf({alligator: 'cage'}) // returns 2
有很多方法可以改进这个代码 如果你有时间,试着想想如何让它更准确和性能。
表演
使用indexOf
比简单地做for loop
要慢得多,这并不意味着indexOf
是慢的,如果你的数组很小,你永远不会看到 indexOf() 或 a for loop 之间的差异,如果你的数组如此之大,以至于你可以注意到两种方法之间的差异,那么你可能想知道为什么你的数组如此之大,以及如何优化搜索。
1var spencersIndex
2// This is faster than indexOf('🐊') but it is much uglier
3for(var index = 0; index < zoo.length; index ++) {
4 if (zoo[index] === '🐊')
5 spencersIndex = index
6}
7// spencers Index === 2
字符串中的indexOf
你可以将从Array.indexOf
的所有逻辑转移到这个部分。
1[label Module: whereIsSpencer.js]
2const whereIsSpencer = "We are all looking for Spencer the alligator. Spencer is a dear friend. Lookout here comes 🐊!"
3
4const spencersIndex = whereIsSpencer.indexOf('Spencer');
5// spencersIndex === 23
6
7// to find find the second occurence of 'Spencer',
8// we need to add one to the position of spencer #1
9const secondSpencerIndex = whereIsSpencer.indexOf('Spencer', spencersIndex + 1);
10// secondSpencerIndex === 46
11
12const alligatorIndex = whereIsSpencer.indexOf('🐊');
13// alligatorIndex === 91
14
15// Be careful the search is case sensitive!
16const lowerCaseSpencer = whereIsSpencer.indexOf('spencer');
17// lowerCaseSpencer === -1
现在我们可以为 Array.prototype.string 创建相同的 indexOf 函数。
1[label Module: indicesOfStrings.js]
2// This is a bit more concise than the previous indicesOf function
3// But it is exactly the same logic
4String.prototype.indicesOf = function (target) {
5 let currentIndex = this.indexOf(target);
6 const allIndices = []
7 while(currentIndex != -1) {
8 allIndices.push(currentIndex);
9 currentIndex = this.indexOf(target, currentIndex +1 );
10 }
11
12 return allIndices;
13}
14
15const whereIsSpencer = "We are all looking for Spencer the alligator. Spencer is a dear friend. Lookout here comes 🐊!";
16
17const spencerIndices = whereIsSpencer.indicesOf('Spencer');
18// spencerIndices equals [23, 46]
我希望你有趣的阅读这个帖子! 如果你有任何建议,问题或评论,请自由地问在Twitter(https://twitter.com/alligatorio)。