/////
Search
2️⃣

02 페어프로그래밍 A팀

페어프로그래밍 느낀점 (익명으로 작성하여 주세요)

아무개1
아무개2
아무개3

느낀 점

1.
드라이버는 정리하면서 받아쓰는 역할이고, 내비게이터는 지시하는 역할로 알고 있었습니다.
=> 스프린트 회고를 보니까 생각보다 서로가 동등한 위치로 진행되는 것을 확인하였습니다.
=> 드라이버가 주도적일 수 있다는 점을 알게 되었다.
2.
어떤 사람과 하는 지에 따라 주도성의 영역이 달라질 수 있겠다.
3.
내비게이터의 지시를 다양한 사고, 관점의 일종으로 받아들였다.
4.
내가 한 방법에만 묻히지 않고 다양한 관점을 받아들여서 좋았다.
5.
이야기 하면서 같이 생각을 공유하는 것 자체가 의미 있는 행동이 아니였을까?

프로그래머스 문제 풀이

// 방법1 // 자바스크립트 엔진에 의해 마지막 비교에서 undefined와 비교하는 일이 발생 // 동일한 숫자가 여러 개 나올 때, push가 이루어지지 않다가 다른 숫자가 나왔을 때 이전 숫자가 push 됨 // 마지막까지 비교해야하기 때문에 undefined(존재하지 않는 인덱스의 요소값)까지 고려되어짐 /* function solution(arr) { let result = []; for (let i = 0; i < arr.length; i++) { if (arr[i] !== arr[i + 1]) { result.push(arr[i]); } } return result; } */ /* i arr[i] arr[i+1] condition (arr[i] !== arr[i + 1]) result 0 arr[0] = 4 arr[1] = 4 false [] 1 arr[1] = 4 arr[2] = 4 false [] 2 arr[2] = 4 arr[3] = 3 true [4] 3 arr[3] = 3 arr[4] = 3 false [4] 4 arr[4] = 3 arr[5] = undefined true [4, 3] */ // 시작을 빈 배열로 시작함 // 방법2 // 위 존재하지 않는 인덱스까지 비교하는 문제와 초반에 동일한 숫자가 나올 때 push가 이루어지지 않는 문제를 해결하기 위해서 // 의도적으로 주어지는 배열 arr의 맨 앞에 null 값을 추가하여 인덱스 1번부터 push가 이루어지게 만들었음 function solution(arr) { let result = []; arr.unshift(null); for (let i = 1; i < arr.length; i++) { if (arr[i - 1] !== arr[i]) { result.push(arr[i]); } } return result; } /* i arr[i - 1] arr[i] condition (arr[i - 1] !== arr[i]) result 1 arr[0] = null arr[1] = 4 true [4] 2 arr[1] = 4 arr[2] = 4 false [4] 3 arr[2] = 4 arr[3] = 3 true [4, 3] 4 arr[3] = 3 arr[4] = 3 false [4, 3] */ // 시작을 첫번째 인덱스의 요소를 배열에 넣고 시작함 // 방법3 - 페어프로그래밍 시간에 다루지는 않았으나 Stack 자료구조를 이용한 풀이 // Stack은 LIFO(Last In First Out)의 특징을 가진 선형 자료구조입니다. // 바닥이 막힌 상자를 생각하면 개념을 연상하기 쉽습니다. // 여기서는 연결리스트(linked list)를 이용하여 구현하였습니다. /* class Node { constructor(value) { // 생성자에 value 객체 생성하고 해당 객체는 value를 가지게 설정 this.value = value; // 생성자에 next 객체를 생성하고 노드의 포인터는 아무것도 가리키지 않음 this.next = null; } } class Stack { constructor() { // 비어있는 박스를 생각하면 됨 // top 객체를 생성하고 아무것도 할당되지 않음 this.top = null; // 비어있는 상자이므로 당연히 크기는 0임 this.size = 0; } push(value) { // push 함수로 입력된 value를 새로운 노드로 선언 const node = new Node(value); // 생성된 새로운 노드의 포인터를 새로운 top 객체에 할당 node.next = this.top; // 기존의 top 객체는 이제 입력 받은 노드로 할당 this.top = node; // 입력된게 있으면 해당 개수만큼 크기를 1씩 추가 this.size += 1; } pop() { // top 객체에 저장된 값을 value로 지정 const value = this.top.value; // top 객체를 top 객체의 포인터로 지정 this.top = this.top.next; // 제거된게 있으면 해당 개수만큼 크기를 1씩 감소 this.size -= 1; // 삭제된 상자의 맨 위의 값을 리턴하고 종료 return value; } size() { return this.size; } } function solution(arr) { let answer = []; const stack = new Stack(); // 클래스 Stack을 이용해서 stack 생성 stack.push(arr[0]); // arr[0]을 stack에 넣는다 for (let i = 1; i < arr.length; i++) { // stack의 맨 위에 있는 값과 arr[i]의 값이 다르면 if (stack.top.value !== arr[i]) { stack.push(arr[i]); // stack 맨 위에 arr[i] 값을 쌓는다 } } const sizeOfStack = stack.size; // stack의 크기를 변수에 할당 // stack의 크기만큼 순회하는 for문 for (let i = 0; i < sizeOfStack; i++) { const topOfStack = stack.pop(); // stack의 맨 위에 있는 값을 제거하고 제거된 값을 topOfStack에 저장 answer.unshift(topOfStack); // answer 배열에 왼쪽에서 오른쪽으로 하나씩 채워나감 } return answer; } */ // 시도는 하였으나 올바르지 않은 방법들 /* - for (let i of arr) {} => 이 방법을 이용하는 경우 이웃하는 배열의 요소를 비교할 수 없게 된다. - for (let i in arr) {} => 이 방법을 이용하는 경우 이웃하는 배열의 요소를 얻어낼 수 없었습니다. 왜냐하면 배열의 프로퍼티 키값은 문자열이기 때문입니다. - Set 객체 => 이 방법은 중복되는 요소를 제거할 수 있다는 장점이 있지만, 첫번째 예제인 [1, 1, 3, 3, 0, 1, 1] 배열에 대한 결과값으로 [1, 3, 0]을 만듭니다. 따라서 Set 객체을 이용하는 방법은 이 문제를 풀이함에 있어 올바르지 않은 접근이라고 보여집니다. */ console.log(solution([1, 1, 3, 3, 0, 1, 1])); // 답: [1,3,0,1] console.log(solution([4, 4, 4, 3, 3])); // 답: [4,3]
JavaScript
복사

To Do List 코드리뷰

// 최상위 부모 요소 const main = document.querySelector('.artcl_main'); // input요소 const userTask = main.querySelector('header input'); // input의 Button const addBtn = main.querySelector('header button'); // ul요소 const listTodo = main.querySelector('.list_todo'); // 할일 추가 이벤트 addBtn.addEventListener('click', createListItem); // 경고 메세지 생성 const message = document.createElement('strong'); message.style.display = 'none'; message.classList.add('txt_invalid'); main.appendChild(message); userTask.addEventListener('input', () => { message.style.display = 'none'; }); // 다운로드 버튼 생성 const downloadBtn = document.createElement('button'); downloadBtn.classList.add('btn'); downloadBtn.textContent = '리스트 다운로드'; main.appendChild(downloadBtn); downloadBtn.addEventListener('click', downloadFile); // 투두를 저장할 배열 // 'tasklist'라는 키를 가진 localStroage에 저장된 값(문자열)을 // 객체로 불러온다. // Note: JSON.stringify() 객체 => 문자열 // JSON.parse() 문자열 => 객체 // 단축 평가를 이용함 (단, B는 항상 true === 값이 있음) // - A && B => A가 false면 A && B를 false로 판단 => A를 반환 // - A || B => A가 false면 A || B를 true로 판단 => B를 반환 // 정리! /* A B 평가결과 true || anything => true false || anything => anything true && anything => anything false && anything => false */ /* const a = undefined; const b = 'hello world'; if (a && b) { arr.push(c); } */ const tasks = JSON.parse(localStorage.getItem('tasklist')) || []; // 초기 화면에서 저장되어있는 데이터를 가지고 목록을 생성합니다. if (tasks.length > 0) { tasks.forEach((task) => { genItem(task.val, task.checked); }); showDownload(); } function createListItem() { // input에 입력된 값을 inpVal 변수에 저장한다. const inpVal = userTask.value; if (inpVal /* inpVal에 값이 있으면 */) { // 할일을 저장하는 객체를 생성합니다. const tempTask1 = { val: inpVal, checked: false, // default setting }; // 할일 목록에 새로운 할일을 저장합니다. tasks.push(tempTask1); // 목록 요소를 생성합니다. genItem(inpVal, false); // 할일 데이터를 localStorage 에 저장합니다. saveTasks(); // 다운로드 버튼 노출 함수 showDownload(); // li가 하나 이상 존재할 것이므로 다운로드 버튼의 display속성을 block으로 변경하여 웹 사이트에 표기하여 준다. } else { errorMsg('내용을 작성해주세요'); } } // 목록 요소를 생성합니다. function genItem(val, complete /*파라미터*/) { //li 요소 생성 const li = document.createElement('li'); li.textContent = val; listTodo.appendChild(li); // 인풋 입력값 초기화 userTask.value = ''; // 만약 수행한 일이라면 => '업데이트 아이템' 함수를 따로 정의해주는 것이 좋지 않을까? // if (complete) { // li.classList.add('done'); // } // 왜 들어갔을까? 다 잘 작동되는데... 코드 낭비?? li.addEventListener('click', () => { li.classList.toggle('done'); // 할일 데이터의 업데이트 함수 buildTasks(); }); // 삭제버튼 만들기 const btn = document.createElement('button'); btn.innerHTML = '<i class="fa-solid fa-trash"></i>'; li.appendChild(btn); btn.addEventListener('click', () => { li.remove(); // 할일 데이터의 업데이트 함수 buildTasks(); // 다운로드 버튼 노출 함수 (예외 처리용) showDownload(); // 삭제 버튼을 눌러서 li가 사라짐 // 만약에 삭제된 li가 마지막 하나 남은 것일 경우 (또는 하나만 있었던 경우에) // 삭제 버튼을 눌러서 남은 li가 없어지면, 다운로드 버튼을 display: none;으로 변경시키기 위해 넣었음 }); } // localStorage 에 할일 목록을 저장하는 함수 function saveTasks() { localStorage.setItem( 'tasklist', JSON.stringify(tasks) /* task에 저장된 값들을 문자열로 변환 */ ); /* 변환된 문자열을 tasklist 키의 값으로 하여 localStroage에 저장 */ } // 할일 정보를 업데이트 하는 함수입니다. 할일을 클릭했을 때, 혹은 할일을 제거했을 때. function buildTasks() { //업데이트 하기 전에 기존에 저장된 tasks 배열의 데이터를 초기화(=== 빈배열로 만듦)합니다. //tasks.length = 0; tasks = []; // 왜 안써? const curList = listTodo.querySelectorAll('li'); // 할일 정보 목록을 재생성합니다. // curList.filter((el) => !el.checked); // 이미 수행한 정보는 모두 사라지고, 아직 수행하지 못한 정보만 남아있게 됩니다. // filter 사용시 문제점 (요구사항에 따라서 문제가 될수도 있음) // - 삭제 버튼을 사용자가 누르지 않았는데, 단순히 done 클래스명이 들어갔다는 이유만으로 알아서 삭제가 되는 문제가 발생 curList.forEach((el) => { const tempTask2 = { val: el.textContent, checked: false, // checked: el.checked, ?? }; if (el.classList.contains('done')) { tempTask2.checked = true; } tasks.push(tempTask2); }); saveTasks(); } // 다운로드 버튼의 노출을 판단하는 함수 function showDownload() { const curList = listTodo.querySelectorAll('li'); if (curList.length > 0) { downloadBtn.style.display = 'block'; } else { downloadBtn.style.display = 'none'; } } // 경고 메세지 활성화 함수 function errorMsg(msg) { message.style.display = 'block'; message.textContent = msg; userTask.focus(); } function downloadFile() { let temp = '<나의 할일 목록>\n\n'; const curList = listTodo.querySelectorAll('li'); curList.forEach((el) => { if (el.classList.contains('done')) { temp += '완료 - '; // '완료 -'를 붙일지 말지 판단 } temp += `${el.textContent}\n`; // li의 내용 }); /* <나의 할일 목록> 완료 - 미경님이랑 페어프로그래밍 하기 선영님이랑 페어프로그래밍 하기 완료 - 잠자기 운동하기 */ /* 여기서의 element는 가상적으로 존재하는 것입니다. */ let element = document.createElement('a'); element.setAttribute('href', `data:text/plain; charset=utf-8,${temp}`); element.setAttribute('download', 'todoList.txt'); // click() : 클릭 가능한 요소라면 클릭을 시뮬레이션 한다 (두뇌 GPU가 딸립니다...) element.click(); // 메모리 상에서 a 태그를 제거한다 element = null; }
JavaScript
복사