자바스크립트 - 이차원 배열 다루기

틱택토 게임

  • 오목의 축소판. 3*3 표 위에서 진행
  • 이차원 배열로 표현

1. 이차원 배열

  • 이차원 배열: 배열 안에 배열이 들어있는 형태
    const data = [[], [], []];
  • 이 게임에서는 화면과 배열을 연결하기 위해 td 태그를 변수로 할당하여 배열에 저장하는 것이 낫다.
  • HTML에서 테이블을 만들 수 있지만 자바스크립트에서도 createElement를 이용하여 테이블을 만들 수 있다.

1) 구조분해 할당

  • 객체 내부의 속성 이름과 변수명이 같을 때 사용
  • 이는 자유롭게 바꿀 수 있고 코드를 줄일 때 사용할 수 있어서 편리하지만 그러나 createElement 같이 작성해도 안 먹히는 애들이 있으니 주의해서 사용하기‼️
const { body } = document;
const body = document.body;
  • 배열에서도 사용 가능함
const arr = [1, 2, 3, 4, 5];
const one = arr[0];
const two = arr[1];
const three = arr[2];
const four = arr[3];
const five = arr[4];

const [one, two, three, four, five] = arr; // 구조분해 할당
const [one,, three,, five] = arr; // 속성이름을 정하고 싶지 않을 땐 ,로 스킵

const obj = {
  a: 'hello',
  b: {
    c: 'hi',
    d: {e: 'wow'},
  },
};
const a = obj.a;
const c = obj.b.c;
const e = obj.b.d.e;
// a, c, e 속성을 구조분해 할당 문법으로 변수에 할당하기
const {a, b: {c, d: {e}} = obj;

2. append vs. appendChild

  • 부모 노드에 자식 노드를 추가하는 메서드

1) append()

  • 노드 객체나 DOMString을 사용할 수 있고, 한번에 여러 개의 자식 요소를 설정할 수 있다.
  • return 값을 반환하지 않는다.

2) appendChild()

  • 노드 객체만 사용할 수 있고, DOMString을 사용할 수 없다. 한번에 하나의 노드만 추가 가능하다.
  • return 값을 반환한다. (추가한 노드 객체 리턴)

3. 이벤트 버블링, 이벤트 캡쳐링

  • td 태그에 클릭 이벤트 리스너를 달게 되면, remove할 때 9개의 이벤트 리스너를 일일이 제거해야 하는 번거로움이 발생한다. 이럴 때 사용하는 것이 바로 이벤트 버블링이다.

1) 이벤트 버블링

  • 이벤트가 부모 태그로 퍼져 나가는 현상
    • 수면으로 올라가는 물방울 모양과 비슷하다고 해서 이러한 이름이 붙었다.
  • HTML에서는 이벤트가 발생할 때 부모 태그에도 순차적으로 동일한 이벤트가 발생한다.
    • 만약 td에서 이벤트가 발생했다면 td의 부모인 tr와 tr의 부모인 table, table의 부모인 body에서도 해당 이벤트가 발생한다. 따라서 td 태그가 아닌 table 태그에 이벤트 리스너를 달아주어도 동일하게 작동한다. (td를 클릭하면 tr, table을 클릭한 것과 동일하기 때문에)
  • event.target이 아닌 event.currentTarget을 사용하면 자식 태그가 아닌 이벤트를 붙인 태그의 동작을 변경할 수 있다.
  • event.stopPropagation(): 이벤트 버블링 현상을 막는 메서드

2) 이벤트 캡쳐링

  • 이벤트 버블링과 반대로 부모를 클릭했을 때 자식 태그에 이벤트가 가는 현상
    팝업 바깥쪽을 클릭하면 팝업이 닫히게 하는 것.
  • addEventListener('click', func, true);: false는 기본값이며 이벤트 버블링 현상이 일어난다.

4. 승부 판단하기

  • 승부 판단과 같은 검사 시에는 변수 값에 false 넣어서 이기면(맞으면) true로 바꿔주는 것이 좋다.
  • 승부 판단 시에는 내가 지금 클릭한 칸을 기준으로 가로줄/세로줄/대각선으로 세 칸이 같은지 확인하면 된다.
let rowIndex;
let cellIndex;
rows.forEach((row, ri) => {
  row.forEach((cell, ci) => {
    if (cell === target) {
      rowIndex = ri;
      cellIndex = ci;
    }
  });
});

// 위 코드를 이렇게 줄일 수 있다.
const rowIndex = target.parentNode.rowIndex;
const cellIndex = target.cellIndex;

1) parentNode

  • parentNode: 현재 태그의 부모 태그를 선택하는 속성
  • target이 td 태그이므로 target.parentNode는 tr 태그가 된다.
  • 자바스크립트에서는 tr 태그는 rowIndex라는 속성을, td 태그는 cellIndex라는 속성을 제공하기 때문에 줄 수와 칸 수를 쉽게 알아낼 수 있다.

2) children & from()

  • children: parentNode의 반대 속성
  • 부모 태그는 하나이지만, 자식 태그는 여러 개이므로 배열과 같은 모양을 나타내지만, 이는 진짜 배열이 아닌 유사 배열 객체(array-like object)이다.
    $table.children; // HTMLCollecion(3) [tr, tr, tr]
  • 따라서 forEach 문은 사용 불가하고, for 문은 돌릴 수 있다.
for (let i = 0; i < 3; i++) {
  console.log($table.childeren[i]);
}
  • Array.from($table.children): 유사 배열을 배열로 바꿔주는 최신 기술
    from 메서드를 적용하면 유사 배열 객체가 배열이 되어 indexOf와 같은 배열의 메서드를 사용할 수 있다.

  • 무승부는 9칸에 모두 textContent가 들어 있으면 무승부이므로 forEach 문을 돌려서 이를 확인한다. 한 칸이라도 빈칸이 있다면 draw를 false로 바꾼다.

 // 승자가 없으면
let draw = true;
rows.forEach((row) => {
  row.forEach((cell) => {
    if (!cell.textContent) {
      draw = false;
    }
  });
});
if (draw) {
  $result.textContent = `무승부`;
  return;
}

3) every & flat

  • every(): 배열의 요소가 하나라도 false이면 반환값도 false가 되는 메서드. 모두가 true이면 true 반환한다.
    true 기준 비교 연산자 AND로 생각하기
  • 1차원 배열에서만 사용 가능하기 때문에 flat 메서드 사용해서 차원을 낮춰줘야 한다.
  • flat(): 배열의 차원을 낮추는 메서드. n차원 배열을 n-1차원 배열로 낮춰줌.
  • every와 flat을 이용하면 더 간단하게 검사할 수 있다.
// 승자가 없으면
const draw = rows.flat().every((cell) => cell.textContent);
if (draw) {
  $result.textContent = `무승부`;
  return;
}

4) some

  • some(): 하나라도 true이면 true 반환, 모두가 false면 false 반환
    true 기준 비교 연산자 OR로 생각하기

5. Self-Check & 최종 코드

  • 혼자서 게임하는 것이 아닌 X의 역할은 컴퓨터가 하도록 만들기
    컴퓨터가 비어 있는 칸에 무작위로 X를 입력하게끔
  • filter(): 조건에 해당하는 요소를 선택해주는 메서드. 마찬가지로 일차원 배열만 가능함
    filter 메서드 이용하여 textContent가 빈 요소 찾아서 그 중 랜덤하게 골라 새로운 변수에 저장하기
    저장한 변수에 textContent 'X'를 추가하고 위에서와 동일하게 승부가 났는지, 무승부인지 확인하기 -> 겹치므로 함수로 따로 빼기
  • 생각하는 척 하는 컴퓨터를 나타내기 위해 setTimeout 이용한다.
    setTimeout을 이용하게 되면 컴퓨터가 생각하는 동안 사용자가 클릭할 수 있으므로 clickable 플래그를 선언하여 X일 때는 click할 수 없게 만든다.