프린스 알리 2024. 11. 12. 20:53

내일배움캠프 Node.js 트랙 12일차

1. ZEP에서 이루어진 로그라이크 게임 개발 프로젝트

코드를 짜다보면 자주 쓰게 되는 배열 메서드들이 있다. push, splice, slice 등….

 

어떤 메서드들은 서로 하는 일이 비슷해 보이는데, 희한하게도 바라는 결과가 나오지 않을 때도 한다. 왜냐하면 원본 배열을 변경하는 메서드가 있는가 하면 새로운 배열을 반환하는 객체도 있기 때문이다. 또 비슷한 일을 하는데 반환값의 자료형이 전혀 다른 경우도 있다.

 

오늘 TIL에서는 두 가지 분류에 따라 메서드를 정리해보고자 한다.

 

아래는 일부 메서드에서 예시로 쓰게 될 원본 배열이다.

let iveMembers = ["안유진", "가을", "레이", "장원영", "리즈", "이서"];

console.log(iveMembers);

 

원본 배열을 변경하는 메서드

push()

배열의 끝에서 요소를 추가한다. 반환값은 요소를 추가한 배열의 길이

// push()
console.log("push('코드펜')을 써보면?");
let returnOfPush = iveMembers.push("코드펜");
console.log(iveMembers);
// push()의 반환값은 배열의 길이
console.log(returnOfPush);

 

pop()

배열의 끝에서 요소를 제거한다. 반환값은 제거한 요소

console.log("pop()을 써보면?");
let returnOfPop = iveMembers.pop();
console.log(iveMembers);
// pop()의 반환값은 제거한 요소
console.log(returnOfPop);

 

shift()

배열의 앞에서 요소를 제거한다. 반환값은 제거한 요소

// shift()
console.log("shift()를 써보면?");
let returnOfShift = iveMembers.shift();
console.log(iveMembers);
// shift()의 반환값도 제거한 요소
console.log(returnOfShift);

 

unshift()

배열의 앞에서 요소를 추가한다. 반환값은 요소를 추가한 배열의 길이

// unshift()
console.log("unhift()를 써보면?");
let returnOfUnshift = iveMembers.unshift("안유진");
console.log(iveMembers);
// unshift()의 반환값도 요소를 추가한 배열의 길이
console.log(returnOfUnshift);

 

splice()

배열의 요소를 제거하거나 대체한다.(원본을 바꾸고 싶지 않다면 toSpliced 사용) 반환값은 제거한 요소를 담은 배열

const months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// Inserts at index 1
console.log(months);
// Expected output: Array ["Jan", "Feb", "March", "April", "June"]

months.splice(4, 1, 'May');
// Replaces 1 element at index 4
console.log(months);
// Expected output: Array ["Jan", "Feb", "March", "April", "May"]

내가 적어야 하는 것 : 시작점으로부터 몇 개를 지우고 싶니? 지운 자리에 무엇을 넣고 싶니?

새로운 배열을 반환하는 메서드(원본 배열 변경x)

concat()

concat은 배열을 연결(병합)해준다.

const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3 = array1.concat(array2);

console.log(array3);
// Expected output: Array ["a", "b", "c", "d", "e", "f"]
console.log(array1);
// Expected output: Array ['a', 'b', 'c']
console.log(array2);
// Expected output: Array ['d', 'e', 'f']

concat을 사용해서 배열을 합쳐줄 때, array1과 array2에는 아무런 변화가 없다.

 

겉보기엔 push랑 비슷해 보인다. 다만 push는 배열을 인자로 받을 경우 배열을 통째로 한 요소로 취급하여 추가해준다. 그러나 concat은 argument 배열이 가진 각 요소들을 병합해준다. 다만 argument 배열 속에 또 배열이 있다면? 그때는 배열의 형태로 연결이 된다.

const num1 = [[1]];
const num2 = [2, [3]];

const numbers = num1.concat(num2);

console.log(numbers);
// 결과는 [[1], 2, [3]]

// num1의 첫 번째 요소를 수정합니다.
num1[0].push(4);

console.log(numbers);
// 결과는 [[1, 4], 2, [3]]

slice()

시작점부터 끝점까지(끝점 미포함) 잘라준다. 반환값은 당연히 새 배열.

const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

console.log(animals.slice(2));
// Expected output: Array ["camel", "duck", "elephant"]

console.log(animals.slice(2, 4));
// Expected output: Array ["camel", "duck"]

console.log(animals.slice(1, 5));
// Expected output: Array ["bison", "camel", "duck", "elephant"]

console.log(animals.slice(-2));
// Expected output: Array ["duck", "elephant"]

console.log(animals.slice(2, -1));
// Expected output: Array ["camel", "duck"]

console.log(animals.slice());
// Expected output: Array ["ant", "bison", "camel", "duck", "elephant"]

메서드 활용 예시

shuffleAllCards() {
    // 손패 비우기
    let splicedHand = this.hasCardInHand.splice(0);
    // splice는 배열을 반환하므로, hasCard배열과 합쳐줄 때 전개 구문을 사용했다.
    this.hasCard.push(...splicedHand);

    // 카드를 잘 섞어주자(Fisher-Yates 셔플 알고리즘)
    for (let i = this.hasCard.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [this.hasCard[i], this.hasCard[j]] = [this.hasCard[j], this.hasCard[i]];
    }

    // 손패 다시 채우기
    for (let i = 0; i < this.handSize; i++) {
      this.hasCardInHand.push(this.hasCard.shift());
    }
    setMessage('카드를 섞고 손패를 가득 채웠습니다!');
  }

위 코드 블럭은 Player 클래스에 속한 shuffleAllCards()메서드이다. 손패에 있는 카드와 더미에 있는 카드를 모두 섞어서 다시 드로우하는 기능을 가지고 있다.

 

(1) '손패를 비운다.'라는 건 해당 배열의 요소를 모두 잘라내기 하겠다는 의미가 된다. 이런 경우엔 원본 배열을 변경시키는 splice를 써줘야 한다. 참고로 splice는 두번째 인자를 쓰지 않으면 배열의 끝까지 잘라준다. 이는 MDN 사이트에서 더 자세하게 확인할 수 있다.

 

(2) 때마침 splice를 살펴보니 배열을 반환하는 메서드다. 이 배열의 요소들을 카드 더미 배열로 push()해주면 되겠다는 생각이 든다. 물론 for문을 돌려서 하나하나 넣어줘도 되고 concat으로 배열을 병합해도 되겠지만, 여기서는 전개구문을 이용해서 push()를 해주었다.

 

(3) 손패를 다시 채우는 방법도 매우 다양하게 있따. for 문을 쓰는 김에 index를 써도 가능할 테지만 shift()의 반환값이 '제거한 배열의 요소'라는 걸 알고 있다면 위와 같이 응용할 수 있다.