Thứ ba, 17/12/2019 | 00:00 GMT+7

Khám phá phương thức indexOf cho chuỗi và mảng trong JavaScript


Khi bạn cần tìm một phần tử trong một mảng hoặc một chuỗi, indexOf() là một trong những người bạn tốt nhất của bạn.

indexOf trong Mảng

Viết mã trước, giải thích sau:

Mô-đun: findSpencer.js
const zoo = ['🐒', '🦄', '🐊', '🐸', '🐙'];
const spencersIndex = zoo.indexOf('🐊');
// spencersIndex === 2
const spencer = zoo[spencersIndex];
// spencer === '🐊'

Trong version đơn giản nhất của nó, phương thức indexOf nhận một đối số là phần tử mà ta đang cố gắng tìm. Sau đó, nó trả về index của phần tử đầu tiên nó tìm thấy trong mảng thỏa mãn el === target . Điều này nghĩa là ngay cả khi có hai kết quả phù hợp trong mảng của bạn, indexOf sẽ chỉ trả về một kết quả. Kết quả là lần xuất hiện đầu tiên trong mảng (đọc mảng từ trái sang phải).

Khi không có mục nào trong mảng thỏa mãn kiểm tra el === target , giá trị -1 được trả về.

Nhưng giả sử ta cũng đang tìm kiếm Skyler (em gái của Spencer). Sau đó, ta có thể thêm một đối số tùy chọn bổ sung để bắt đầu tìm kiếm từ một index khác.

Mô-đun: findSkyler.js
const zoo = ['🐒', '🦄', '🐊', '🐸', '🐙',  '🐊']; // Skyler just arrived!
const spencersIndex = zoo.indexOf('🐊'); // === 2 same as before

// We start searching after 
const skylersIndex = zoo.indexOf('🐊', spencersIndex + 1);
// skylersIndex === 5

Ta cũng có thể tạo một phương thức trên nguyên mẫu Array trả về tất cả các chỉ số dựa trên indexOf.

Mô-đun: indicesOf.js
// Try to think of ways to make indicesOf more performant
Array.prototype.indicesOf = function (target) {
  const result = [];
  let currentIndex = 0;
  while(true) {
    // here this ===  the array on which we call `indicesOf`
    const targetIndex = this.indexOf(target, currentIndex);
    if (targetIndex == -1)
      break;

    result.push(targetIndex);

    currentIndex = targetIndex +1;
  }

  return result;
}
const zoo = ['🐒', '🦄', '🐊', '🐸', '🐙',  '🐊']; // Skyler just arrived!
const alligatorsIndices = zoo.indicesOf('🐊');
// alligatorsIndices returns [2, 5]

Bạn không thể tìm thấy gì với indexOf?

Bạn có thể nhận thấy rằng ta làm gián đoạn tìm kiếm bằng cách sử dụng el === target so sánh ngang bằng ba el === target , đây là mộtso sánh bình đẳng nghiêm ngặt . Điều này nghĩa là , ví dụ, ta không thể kiểm tra các mảng, đối tượng hoặc chức năng khác với tham chiếu.

const simpleArray = [1, 2, 3];
const simpleFunction = () => {console.log('hey')};
const simpleObject = {alligator: 'cage'};

const compositeArray = [simpleArray, simpleFunction, simpleObject];

// These all work as expected because we compare by reference
compositeArray.indexOf(simpleArray); // returns 0
compositeArray.indexOf(simpleFunction); // returns 1
compositeArray.indexOf(simpleObject); // returns 2

// These won't work 
compositeArray.indexOf([1, 2, 3]); // returns -1
compositeArray.indexOf(() => {console.log('hey')}); // returns -1
compositeArray.indexOf({alligator: 'cage'}) // returns -1

Một chỉ số sâu

Giả sử ta muốn tạo một tiện ích để kiểm tra các đối tượng, mảng và hàm một cách đệ quy:

Mô-đun: inDepthIndexOf.js
Array.prototype.deepIndexOf = function (target) {
  // If the target is an object, array or a function, we give it a special treatment
  if (typeof target === 'object' || typeof target === 'function') {
    // We stringify the target 
    const searchTarget = target.toString()
    // We loop through all of the elements of the array
    for (let index = 0; index < this.length; index++){
      const element = this[index]
      // 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
      if ((typeof element === 'object' || typeof target === 'function') && element.toString() === searchTarget) {
        // if we have a match we interrupt the loop and return the index
        return index
      }
    }
    // if nothing matched we return -1
    return -1
  }
  return this.indexOf(target)
}

const simpleArray = [1, 2, 3];
const simpleFunction = () => {console.log('hey')};
const simpleObject = {alligator: 'cage'};

const compositeArray = [simpleArray, simpleFunction, simpleObject];

// These all work as expected because we compare by reference
compositeArray.deepIndexOf(simpleArray); // returns 0
// ... You know the rest
// These will work!
compositeArray.deepIndexOf([1, 2, 3]); // returns 0
compositeArray.deepIndexOf(() => {console.log('hey')}); // returns 1
compositeArray.deepIndexOf({alligator: 'cage'}) // returns 2

Có nhiều cách để cải thiện mã này. Nếu bạn có một chút thời gian trong tay, hãy cố gắng nghĩ cách làm cho nó chính xác và hiệu quả hơn. Tôi muốn đọc những ý tưởng của bạn trên Twitter.

Hiệu suất

Sử dụng indexOf chậm hơn nhiều so với chỉ thực hiện một for loop . Điều đó không nghĩa là indexOf chậm. Nếu mảng của bạn nhỏ, bạn sẽ không bao giờ thấy sự khác biệt giữa indexOf () hoặc vòng lặp for. Nếu mảng của bạn lớn đến mức bạn có thể nhận thấy sự khác biệt giữa hai phương pháp, thì có lẽ bạn nên tự hỏi tại sao mảng của bạn lại lớn như vậy và làm cách nào bạn có thể tối ưu hóa tìm kiếm. Bạn có thể tìm thấy các điểm chuẩn hiệu suất trên JSPerf .

var spencersIndex
// This is faster than indexOf('🐊') but it is much uglier
for(var index = 0; index < zoo.length; index ++) {
  if (zoo[index] === '🐊')
    spencersIndex = index
}
// spencers Index === 2

indexOf trong chuỗi

Bạn có thể chuyển tất cả logic từ Array.indexOf sang phần này. Hãy code!

Mô-đun: whereIsSpencer.js
const whereIsSpencer = "We are all looking for Spencer the alligator. Spencer is a dear friend. Lookout here comes 🐊!"

const spencersIndex = whereIsSpencer.indexOf('Spencer');
// spencersIndex ===  23

// to find find the second occurence of 'Spencer',
// we need to add one to the position of spencer #1
const secondSpencerIndex = whereIsSpencer.indexOf('Spencer', spencersIndex + 1);
// secondSpencerIndex ===  46

const alligatorIndex = whereIsSpencer.indexOf('🐊');
// alligatorIndex ===  91

// Be careful the search is case sensitive!
const lowerCaseSpencer = whereIsSpencer.indexOf('spencer');
// lowerCaseSpencer === -1

Bây giờ ta có thể tạo cùng một hàm indicesOf cho Array.prototype.string .

Mô-đun: indicesOfStrings.js
// This is a bit more concise than the previous indicesOf function
// But it is exactly the same logic
String.prototype.indicesOf = function (target) {
  let currentIndex = this.indexOf(target);
  const allIndices = []
  while(currentIndex != -1) {
    allIndices.push(currentIndex);
    currentIndex =  this.indexOf(target, currentIndex +1 );
  }

  return allIndices;
}

const whereIsSpencer = "We are all looking for Spencer the alligator. Spencer is a dear friend. Lookout here comes 🐊!";

const spencerIndices = whereIsSpencer.indicesOf('Spencer');
// spencerIndices equals [23, 46]

Tôi hy vọng bạn đã vui vẻ khi đọc bài viết này! Nếu bạn có đề xuất, câu hỏi hoặc comment nào, hãy hỏi trên Twitter .


Tags:

Các tin liên quan

Thao tác DOM trong JavaScript với innerText và innerHTML
2019-12-14
Cách gói một gói JavaScript Vanilla để sử dụng trong React
2019-12-12
Cách phát triển một trình tải lên tệp tương tác với JavaScript và Canvas
2019-12-12
Cách sử dụng map (), filter () và Reduce () trong JavaScript
2019-12-12
Giải thích về lập trình chức năng JavaScript: Ứng dụng một phần và làm xoăn
2019-12-12
Giới thiệu về Closures và Currying trong JavaScript
2019-12-12
Bắt đầu với các hàm mũi tên ES6 trong JavaScript
2019-12-12
Cách đếm số nguyên âm trong một chuỗi văn bản bằng thuật toán JavaScript
2019-12-12
Cách sử dụng phép gán cấu trúc hủy trong JavaScript
2019-12-12
Giải thích về lập trình chức năng JavaScript: Kết hợp & truyền tải
2019-12-12