[JS] Array Functions



概要


JS Array Objectにはいろいろな方法がありますが、その中で普段よく使われている方法をまとめました.

本題


📍 Array、追加、削除、繰り返し

  • Array.prototype.splice()
  • Array.prototype.slice()
  • Array.prototype.concat()
  • Array.prototype.forEach()
  • {
      /**
       * Array.prototype.splice() 💡
       * - 배열 요소의 추가,삭제,교체 모두 가능
       * - 삭제된 요소로 이뤄진 배열을 따로 반환해준다.
       * - 음수 인덱싱도 가능함
       *
       * [기본 문법]
       * arr.splice(index[, deleteCount, elem1, ..., elemN])
       */
      let arr = ["I", "Love", "Me"];
      console.log(arr); // [ 'I', 'Love', 'Me' ]
      let removeData = arr.splice(2, 1, "You");
      console.log(removeData); // [ 'Me' ]
      console.log(arr); // [ 'I', 'Love', 'You' ]
      console.clear();
    
      /**
       * Array.prototype.slice() 💡
       * - 시작인덱스 ~ 끝인덱스-1 까지의 원본 배열을 복사한 새로운 배열을 반환
       * - 역시, 음수 인덱싱 가능(이 때는 음수 인덱스 ~ 끝까지)
       * - 문자열 메소드인 String.prototype.slice() 와 유사하게 동작
       * - 서브 문자열(substring) 대신, 서브 배열(subarray)을 반환한다는 점이 다름
       * - arr.slice() 처럼, 인수를 하나도 넘기지 않기도 함 ( 많이 사용 ) 🔍
       * - 이 방식은, "새로운 배열"을 생성하는 방법 중에 하나 이므로 자주 사용
       *
       * [기본 문법]
       * arr.slice([start], [end])
       */
      let arr2 = ["1", "2", "3", "4"];
      console.log(arr2.slice(1, 3)); // [ '2', '3' ]
      console.log(arr2.slice(-2)); // [ '3', '4' ]
      console.clear();
    
      /**
       * Array.prototype.concat() 💡
       * - 기존 배열의 요소를 사용해, "새로운 배열"을 만들거나, 기존 배열에 요소를 추가하고자 할 때 사용
       *
       * [기본 문법]
       * - arr.concat(arg1, arg2...)
       * - 인수에는 "배열"이나 "값"이 올 수 있다. 갯수 제한은 없다.
       * - 인수로 "객체"가 넘어오면(유사 배열객체라도), 객체는 "분해 되지 않고 통으로 복사"되어 더해짐 🔍
       * - 그런데, 유사 배열 객체에 "특수한 프로퍼티", "Symbol.isConcatSpreadable" 이 존재하면, concat 은 이 객체를 "배열처럼 취급"
       * - 따라서, 객체 프로퍼티의 값이 더해진다.
       *
       * [참고]
       * SymbolConstructor.isConcatSpreadable: typeof Symbol.isConcatSpreadable
       * - A Boolean value that if true indicates that an object should flatten to its array elements by Array.prototype.concat.
       */
      let arr3 = [1, 2];
      let arrayLike = {
        0: "something",
        length: 1,
      };
      console.log(arr3.concat(arrayLike)); // [ 1, 2, { '0': 'something', length: 1 } ]
    
      let arr4 = [1, 2];
      let arrayLike2 = {
        0: "something",
        1: "else",
        [Symbol.isConcatSpreadable]: true,
        length: 2,
      };
      console.log(arr4.concat(arrayLike2)); // [ 1, 2, 'something', 'else' ]
      console.clear();
    
      /**
       * forEach 로 반복작업 하기
       * - 주어진 함수를, 배열 요소 각각에 대해 실행할 수 있게 해준다.
       */
      [1, 2, 3, 4, 5].forEach((el, idx) => {
        console.log(el, idx);
      });
      // 1 0
      // 2 1
      // 3 2
      // 4 3
      // 5 4
      console.clear();
    }
    

    📍 Arrayを参照

  • Array.prototype.indexOf()
  • Array.prototype.lastIndexOf()
  • Array.prototype.includes()
  • Array.prototype.find()
  • Array.prototype.findIndex()
  • Array.prototype.filter()
  • {
      /**
       * 배열 탐색
       * - Array.prototype.indexOf(item, from) : 배열에 앞에서부터, 해당 요소를 찾으면, 해당 요소의 인덱스를 반환, 없으면 -1 💡
       * - Array.prototype.lastIndexOf(item, from) : 배열에 뒤에서부터, 해당 요소를 찾으면, 해당 요소의 인덱스 반환, 없으면 -1 💡
       * - Array.prototype.includes(item, from) : 해당 요소를 발견하면 true, 없으면 false 💡
       *
       * 같은 이름을 가진 문자열 메소드들과 문법이 동일, 하는 일도 동일 🔍
       * 위에 세 가지 메소드 모두 "항등 연산자(===)"를 사용한다는 점에 유의할 것 🔍
       * 그렇기 때문에, 0 과 false 같은 것을 구분한다. 🔍
       *
       * 요소의 위치를 정확히 알고 싶은 것이 X
       * 배열 내 존재하는지 여부만을 확인하고 싶다 => array.includes 를 사용함
       * - includes 는 NaN 도 판단한다.
       */
    
      let arr1 = [1, 0, false, 1];
      console.log(arr1.indexOf(0)); // 1
      console.log(arr1.indexOf(false)); // 2
      console.log(arr1.indexOf(null)); // -1
      console.log(arr1.lastIndexOf(1)); // 3
      console.log(arr1.includes(1)); // true
      console.clear();
    
      let arr2 = [NaN];
      console.log(arr2.indexOf(NaN)); // -1
      console.log(arr2.includes(NaN)); // true
      console.clear();
      /**
    	 * "객체"로 이뤄진 배열이 있을 때, "특정 조건"에 부합하는 객체를 배열 내에서 찾고 싶을 경우
       * - Array.prototype.find(function(item, index, array)) : 
       * - Array.prototype.findIndex(function(item, index, array)) : 
    	 * 
    	 * [기본 문법]
    	 * let result = arr.find(function(item, index, array) {
      		true가 반환되면 반복이 멈추고 해당 요소를 반환합니다.
      		조건에 해당하는 요소가 없으면 undefined를 반환합니다.
    	 }
    
    	 * 실무에서 객체로 구성된 배열을 다뤄야할 일이 많아서, find 메소드 활용법을 알아두면 좋다.
    	 * findIndex 는 find 와 동일하나, 조건에 맞는 요소의 "인덱스"를 반환, 없으면 -1 반환
       */
      let users = [
        { id: 1, name: "May" },
        { id: 2, name: "Jun" },
        { id: 3, name: "July" },
      ];
    
      let user = users.find((item) => item.id === 2);
      let userIdx = users.findIndex((item) => item.id === 3);
      console.log(user); // { id: 2, name: 'Jun' }
      console.log(userIdx); // 2
      console.clear();
    
      /**
    	 * 조건에 맞는 원소 하나만이 아니라, "여러 개"를 반환받길 웒는 경우
    	 * - Array.prototype.filter()
    	 * 
    	 * let results = arr.filter(function(item, index, array) {
      		// 조건을 충족하는 요소는 results에 순차적으로 더해집니다.
      		// 조건을 충족하는 요소가 하나도 없으면 빈 배열이 반환됩니다.
    		});
    	*/
    
      let someUsers = users.filter((item) => item.id < 3);
      console.log(someUsers); // [ { id: 1, name: 'May' }, { id: 2, name: 'Jun' } ]
    }
    

    📍 アレイ変換

  • Array.prototype.map()
  • Array.prototype.sort()
  • Array.prototype.reverse()
  • Array.prototype.split()
  • Array.prototype.join()
  • Array.prototype.reduce()
  • {
      /**
    	 * JS, 배열을 변형시키거나, 재정렬해주는 메서드
    	 * - Array.prototype.map()	💡
    	 * - Array.prototype.sort(fn) 💡
    	 * 
    	 * map
    	 * - 유용성과 사용 빈도가 아주 높은 메소드 
    	 * - 배열 요소 전체를 대상으로 함수를 호출, 함수 호출 결과를 배열로 반환 🔍
    	 * 
    	 * [기본 문법]
    	 * let result = arr.map(function(item, index, array) {
      		// 요소 대신 새로운 값을 반환합니다.
    			});
    	 *
    	 */
      let arr1 = [1, 2, 3, 4, 5];
      let result = arr1.map((el) => el * 2);
      console.log(result); // [ 2, 4, 6, 8, 10 ]
      console.clear();
    
      /**
       * Array.prototype.sort(fn) 💡
       * - 배열의 요소를 정렬해준다.
       * - 배열 자체가 변경된다. 🔍
       * - 기본 정렬 기준은 "유니코드" 순서에 따라 정렬된다. 🔍
       * - 새로운 정렬 기준을 만들려면, 기준 function 을 넘겨줘야한다. 🔍
    	 * 
       * function compare(a, b) {
    			if (a > b) return 1; // 첫 번째 값이 두 번째 값보다 큰 경우
    			if (a == b) return 0; // 두 값이 같은 경우
    			if (a < b) return -1; //  첫 번째 값이 두 번째 값보다 작은 경우
    		}
    	 *
    	 * Array 에는 숫자, 문자열, 객체 등 정해진 것이 아닌, 알 수 없는 "무언가"로 구성된 집합이 된다.
    	 * 이 "비 동질적인" 집합을 정렬해야 한다고 가정해보자.
    	 * 무언가를 정렬하려면 "기준"이 필요하다. 이때 정렬 기준을 정의해주는 함수(ordering function, 정렬 함수)가 필요
    	 * - sort() 메소드는 최적화된 "Quick Sort(퀵 소트)"를 사용한다. 🔍
    	 * - sort() 는 주어진 함수를 사용해, 정렬 기준을 만들고 이 기준에 따라 요소들을 재배열하므로, 개발자는 내부 정렬 동작원리를 알 필요가 없다.
    	 * - function 을 만들고, 이를 인수로 넘겨주는 것만 해주면 된다.
       */
    
      let arr2 = [7, 3, 1];
      arr2.sort(function (a, b) {
        return a - b;
      });
      console.log(arr2); // [ 1, 3, 7 ]
    
      let arr3 = [5, 4, 3, 2, 1];
      arr3.sort((a, b) => a - b);
      console.log(arr3); // [ 1, 2, 3, 4, 5 ]
    
      let arr4 = ["Österreich", "Andorra", "Vietnam"];
      console.log(arr4.sort((a, b) => (a > b ? 1 : 1))); // [ 'Österreich', 'Andorra', 'Vietnam' ] << 틀림
      console.log(arr4.sort((a, b) => a.localeCompare(b))); // [ 'Andorra', 'Österreich', 'Vietnam' ] << 맞음
      console.clear();
    
      /**
       * 배열의 요소를 역순으로 정렬시켜주는 메소드
       * - Array.prototype.reverse() 💡
       *
       * 반환 값은 "재정렬된 배열"
       */
      let arr5 = [1, 2, 5, 6, 1];
      arr5.reverse();
      console.log(arr5); // [ 1, 6, 5, 2, 1 ]
      console.clear();
    
      /**
       * - Array.prototype.split(delim) : 문자열을 분리 => 배열로 💡
       * - Array.prototype.join(gule) : 배열을 합쳐서 => 문자열로 💡
       */
    
      let names = "May, Jun, July";
      let arr6 = names.split(", ");
      console.log(arr6); // [ 'May', 'Jun', 'July' ]
    
      let test = "test";
      console.log(test.split("")); // [ 't', 'e', 's', 't' ]
      console.log(["t", "e", "s", "t"].join("")); // test
      console.clear();
    
      /**
    	 * 배열을 기반으로 "값 하나를 도출할 때 사용"
    	 * let value = arr.reduce(function(accumulator, item, index, array) {
      		// ...
    			}, [initial]); 💡
    	 * 
    	 * accumulator : 이전 함수 호추르이 결과, initial은 함수 최초 호출시 사용되는 초깃값을 나타냄(옵션)
    	 * item : 현재 배열 요소
    	 * 
    	 * - 이전 함수 호출 결과 -> 다음 함수를 호출 시, 첫 번째(accumulator) 인수(= previousValue) 로 사용
    	 * - 마지막 함수까지 호출되면 이 값은 reduce 의 반환 값이 된다.
    	 * - 맨 마지막 인자(초기값)는 생략해도 된다.
    	 * - 단, 생략하는데, 배열이 비어있다 => 에러발생 🔍
    	 * - 그렇기 때문에, 초기값은 그냥, "명시" 하는 것이 좋다.
    	 */
    
      let arr7 = [1, 2, 3, 4, 5];
      let result7 = arr7.reduce((sum, current) => sum + current, 0);
      console.log(result7); // 15
    
      // let arr8 = [];
      // // TypeError: Reduce of empty array with no initial value
      // // 초깃값을 설정해 주었다면 초깃값이 반환되었을 겁니다.
      // arr8.reduce((sum, current) => sum + current);
    }

    📍 アレイセット

  • Array.prototype.every()
  • Array.prototype.some()
  • {
      let arr1 = [-1, -2, -3, -4, 100];
      /**
       * Array.prototype.every(fn)
       * - 배열에 모든 요소가 조건에 부합하면 true, 아니면 false
       */
      console.log(arr1.every((el) => el > 0)); // false
    
      /**
       * Array.prototype.some(fn);
       * - 배열에 요소들 중, 하나라도 조건에 부합하면 true, 아니면 false
       */
      console.log(arr1.some((el) => el > 0)); // true
    }
    

    📍 Array確認、thisArg

  • Array.isArray()
  • {
      /**
       * Array 를 typeof 로 확인하면, 그냥 object 타입에 속한다.
       * 그렇기 때문에, 제대로, 배열인지 확인하려면
       * - Array.isArray(arr) 가 필요 💡
       */
    
      console.log(typeof {}); // object
      console.log(typeof []); // object
    
      console.log(Array.isArray({})); // false
      console.log(Array.isArray([])); // true
    
      /**
       * 함수를 호출하는 대부분의 배열 메소드(find, filter, map 등)는 thisArg 라는 매개변수를 옵션으로 받을 수 있다.
       *
       *
       * arr.find(func, thisArg);
       * arr.filter(func, thisArg);
       * arr.map(func, thisArg);
       * // thisArg는 선택적으로 사용할 수 있는 마지막 인수입니다.
       *
       * thisArg : function 의 this 가 된다.
       */
      let army = {
        minAge: 18,
        maxAge: 27,
        canJoin(user) {
          return user.age >= this.minAge && user.age < this.maxAge;
        },
      };
    
      let users = [{ age: 16 }, { age: 20 }, { age: 23 }, { age: 30 }];
    
      // army.canJoin 호출 시 참을 반환해주는 user를 찾음
      // army 라는 thisArg 를 넘기지 않고, army.canJoin 사용시, 에러 발생
      let soldiers = users.filter(army.canJoin, army);
    
      console.log(soldiers.length); // 2
      console.log(soldiers[0].age); // 20
      console.log(soldiers[1].age); // 23
    }

    n/a.結論


    次に、Array Objectメソッドでは、includeのようないくつかのメソッドを使用して繰り返しチェックを行うにはO(N)時間が必要であり、このメソッドが特定の繰り返し文に属し、Nが大きいほどパフォーマンスが低下する.
    これらの重複チェックを効率的に実行できるMapまたはSet資料の種類について説明します.

    リファレンス

  • Modern JS