[Part3] 배열과 반복자 method

누리·2023년 8월 14일
0

Interview

목록 보기
8/13

배열과 객체의 차이는?

  • 순서가 있는지 없는지
  • 순환 할 수 있는지 없는지
const arr = [1,2,3];
console.log(arr); // 콘솔을 찍었을때 Symbol(Symbol.iterlator)의 속성을 확인 할 수 있다
const arr2 = new Array(3).fill(0);
console.log(arr2);

여기서 new 키워드는 무엇일까 여기에는 class 가 숨어있다 Array라는 class에서 상속을 받기 때문에 prototype으로 손쉽게 사용할 수 있다.

배열은 순서가 있다
객체는 순서가 없다
객체에서 상속을 받아서 내려온 것이 배열이다

메소드들을 살펴보자

1. 배열 메소드 map, filter, reduce, forEach의 차이점은 무엇인가요? 각각 어떤 상황에서 사용하나요?

  • map과 forEach를 같이 물어보는 의도는 return이 있는지 없는지의 차이를 아는지 물어보는것이다.
    그냥 순회만 하는지 순회해서 리턴값을 받을건지
  • reduce 물어보는 의도는 형변환을 위한 메소드인지 아는가

map : 배열의 각 요소에 대해 주어진 함수를 실행하고, 그 결과를 포함하는 새로운 배열을 반환합니다. 예를 들어, 배열의 모든 요소를 제곱하거나 특정 속성만 추출하여 새로운 배열을 만드는 데 사용할 수 있습니다.


filter : 배열의 각 요소에 대해 주어진 테스트 함수를 실행하고, 그 함수를 통과하는 요소만으로 이루어진 새 배열을 반환합니다. 예를 들어, 배열에서 특정 조건을 만족하는 요소만 선택하려는 경우 사용합니다.


reduce : 배열의 각 요소에 대해 주어진 reducer 함수를 실행하고, 하나의 출력값을 반환합니다. 이는 종종 배열의 요소를 결합하거나 압축하는 데 사용됩니다. 예를 들어, 배열의 모든 요소의 합계를 계산하거나 배열의 요소를 이용해 객체를 생성하는 경우 사용합니다.
reduce의 기본형 : .reduce((acc, current) => , {});

  • 첫번째 인자 : 콜백함수(가산되는값, 현재값)
  • 두번째 인자 : 초기값
    (reduce는 형변환이다 queryString으로 예시 들기)
const url = 'https://www.youtube.com/watch?v=exCdaVKG&t=5s';

const [baseUrl, qs] = url.split('?');
// ['https://www.youtube.com/watch', 'v=exCdaVKG&t=5s']

// {v: 'exC...', t: '5s'} 의 값을 얻으려면?
const queryObj = qs.split('&')
	.map((query) => query.split("="))
	// 배열형태이다 [['v','exCdaVKG'],['t','5s']]
	// 배열에서 객체로 형변환이 필요함 >> reduce 사용
  	.reduce((acc,[key,value]) => ({...acc,[key]:value}),
  	{});
console.log(queryObj); // {v: 'exC...', t: '5s'}

//다시 문자열 전환 (역산하는방법)
baseUrl+'?'+
Object.entries(queryObj)
	.map(([key,value]) => `${key}=${value}`)
	.join("&");

forEach : 배열의 각 요소에 대해 주어진 함수를 실행합니다. 반환값이 없습니다(즉, 새로운 배열을 생성하지 않습니다). 주로 배열의 각 요소에 대해 어떤 작업을 수행하려는 경우 사용합니다.

const myArr = [1,2,3,4,5];
const doubledArr = myArr.forEach((v)=> return(v*2));
console.log(doubledArr); // undefined
console.log(myArr); // [1,2,3,4,5]

forEach 메소드는 리턴값이 없는 메소드이기 때문에 함수에 return을 명시하더라도 리턴값이 없다.
그리고 원본배열도 변경되지 않는다.
DOM을 변경하는 것이 아니라 딱 순회만 할 때(액션만취하고빠질때) 사용이된다.
ex)무한스크롤 구현등

2. map, filter, reduce 메소드를 직접 구현해 주세요.

일단 이런 문제가 나오면 실제 메소드를 한번 돌려서 과정들을 생각해본다

const arr = [1, 2, 3, 4, 5];
arr.map((v) => v * 2);

//프로토 타입에 직접 주입
// this 사용시에는 arrow function 사용x
Array.prototype.myMap = function(callback) {
  let result = [];
  console.log(this); // [1, 2, 3, 4, 5]
  
  for (let i = 0; i< this.length; i++) {
  	result.push(callback(this[i]));  
  }
  
  return result;
}
arr.myMap((v) => v * 2); //[2, 4, 6, 8, 10]

Array.prototype.myFilter = function(callback){
  let result = [];
  for(let i = 0; i < this.length; i++) {
    if(callback(this[i], i, this)) {
      result.push(this[i]);
    }
  }
  return result;
};

Array.prototype.myReduce = function(callback, initialValue) {
  let accumulator = initialValue === undefined ? this[0] : initialValue;
  for(let i = initialValue === undefined ? 1 : 0; i < this.length; i++) {
    accumulator = callback(accumulator, this[i], i, this);
  }
  return accumulator;
};

3. slice, splice 차이점을 설명해 주세요.

  • 이 때 이 질문의 의도는 가변 내장함수무결성 내장 함수를 구분할 줄 아는가를 묻는것이다.

slice : 배열의 부분적인 복사본을 생성합니다. 원본 배열은 변경되지 않습니다. 시작 인덱스와 종료 인덱스를 인자로 받아, 시작 인덱스부터 종료 인덱스 전까지의 요소를 새로운 배열로 반환합니다.
splice : 배열의 특정부분을 제거하거나 추가하며, 원본 배열을 변경합니다. 시작 인덱스와 제거할 요소의 갯수, 그리고 추가할 요소를 인자로 받아 제거된 요소를 배열로 반환하며, 원본 배열은 제거된 요소를 제외하거나 추가한 요소를 포함하는 상태로 변경됩니다.

배열 내장함수

4. some, every 메소드 차이점과 적절한 예시를 들어주세요.

  • some : 배열의 적어도 하나의 요소가 주어진 함수를 통과하는지 테스트 할 수 있다. 예를 들어, 배열의 특정 조건을 만족하는 요소가 존재하는지 확인하려는 경우에 사용한다.
  • every : 배열의 모든 요소가 주어진 함수를 통과하는지 테스트 할 수 있다. 예를 들어, 배열의 모든 요소가 특정 조건을 만족하는지 확인하려는 경우에 사용한다.
import React, { useState } from "react";

const INIT_STATE = {
  id: "",
  password: "",
  userName: ""
};

const RULE = {
  id: (value) => value.includes("@"),
  password: (value) => value.length >= 8,
  userName: (value) => value.length >= 2
};

export default function App() {
  const [formData, setFormData] = useState(INIT_STATE);
  const onChangeInput = ({ target }: any) => {
    const { name, value } = target;
    setFormData({ ...formData, [name]: value });
  };
  const isAllValid = Object.entries(formData).every(([k, v]) => RULE[k](v));

  return (
    <form>
      <input type="text" name="userName" onChange={onChangeInput} />
      <input type="text" name="id" onChange={onChangeInput} />
      <input type="password" name="password" onChange={onChangeInput} />
      {isAllValid && <button>제출</button>}
    </form>
  );
}

5. Spread Operator 와 Rest Parameter를 배열과 함께 사용하는 예제를 들어 설명해주세요.

  • react 에서 prop을 넘겨주는 걸로 예시들어주면 된다.
import React, { useState } from "react";
import "./styles.css";
import Input from "./Input";

const INIT_STATE = {
  id: "",
  password: "",
  userName: ""
};
const RULE = {
  id: (value) => value.includes("@"),
  password: (value) => value.length >= 8,
  userName: (value) => value.length >= 2
};

export default function App() {
  const [formData, setFormData] = useState(INIT_STATE);
  const onChangeInput = ({ target }: any) => {
    const { name, value } = target;
    setFormData({ ...formData, [name]: value });
  };
  const isAllValid = Object.entries(formData).every(([k, v]) => RULE[k](v));

  return (
    <form>
      <Input type="text" name="userName" onChange={onChangeInput} />
      <Input type="text" name="id" onChange={onChangeInput} />
      <Input type="password" name="password" onChange={onChangeInput} />
      {Input({name: 'secondName', onChange: onChangeInput})} /
      {isAllValid && <button>제출</button>}
    </form>
  );
}
import React from "react";

// 뭔가 중요한 prop이 있다면 따로 분리해서 사용할 수 있다. (Rest Parameter)
// 이때 ...props에는 name을 제외한 props 들이 들어있다
const Input = ({ name, ...props }) => {
  return (
    <div>
      <p>{name}</p>
      <input className="styled-input" {...props} />
    </div>
  );
};

export default Input;

6. 배열을 복제하는 여러가지 방법과 차이점을 설명해 주세요.

  • Array.prototype.slice : 원본 배열을 변경하지 않고 새 배열을 반환
  • Array.prototype.concat : 원본 배열을 변경하지 않고 새 배열을 반환
  • Spread operator(...배열변수명) : 이 연산자를 사용하면 쉽게 배열 복제 가능
  • Array.from : 이 메서드는 iterable 객체나 array-like 객체를 새 배열로 변환

    모두 새 배열을 반환하므로 원본 배열은 변경되지 않는다. 그러나 이 방법은 모두 얕은 복사 를 수행한다.
    즉, 배열 요소가 객체인 경우, 새 배열은 원본 배열의 객체에 대한 참조를 가지게 되므로 이러한 객체를 변경하면 원본 배열과 새 배열 모두에 영향을 미친다.

깊은 복사 하는방법

  • JSON.parse(JSON.stringify(array)) 사용
  • immerjs 깊은 복사 라이브러리 사용

7. sort 메소드 사용할 때 주의할 점은?

  • sort 메소드는 원본 배열을 변경하므로, 원본 배열을 유지해야하는 경우 sort메소드 사용하기 전에 배열을 복제해야 한다.
const arr = [5, 6, 2];

const sortedArr = arr.sort((a, b) => b - a);

console.log(arr); // [6, 5 ,2]
console.log(sortedArr); // [6, 5, 2]
  • 기본적으로 문자열로 변환된 요소를 기준으로 정렬을 수행하므로, 숫자 배열을 정렬할 때 주의해야 한다. 이 경우, 콜백함수를 제공하여 숫자를 기준으로 정렬을 수행할 수 있다.
  • sort 메소드는 안정 정렬이 아니다. 즉, 동일한 값의 요소의 상대적인 순서가 정렬 후에 유지되지 않을 수 있다.
  • 요즘 toSorted 메소드가 새로 나왔다 (원본 배열 복사도 같이 해줌)

8. 자바스크립트에서 배열과 객체의 차이점은 무엇인가? 어떤경우에 배열을 사용하고 객체를 사용하는가?

  • 자바스크립트에서 배열과 객체는 모두 복합 데이터 타입이다. 즉, 여러 값을 한 번에 저장할 수 있는 데이터 구조이다.
    그러나 그들의 사용 목적과 사용 방식은 다르다.
  • 배열(Array)은 순서가 있는 데이터 집합을 저장할 때 사용한다. 배열은 정수 인덱스를 기반으로 요소에 접근하며, 배열의 각 요소는 임의의 타입이 될 수 있다. 배열은 주로 같은 종류의 아이템들을 저장하고 순서대로 처리할 때 사용된다.
  • 객체(Object)는 이름-값 쌍의 집합을 저장할 때 사용한다. 객체의 속성은 문자열 키를 기반으로 접근하며, 각 속성 값은 임의의 타입이 될 수 있다. 객체는 다양한 타입의 값을 포함하고, 각 값에 고유한 이름(key)를 부여하여 관리할 필요가 있을 때 사용된다.
profile
프론트엔드 개발자

1개의 댓글

comment-user-thumbnail
2023년 8월 14일

이렇게 유용한 정보를 공유해주셔서 감사합니다.

답글 달기