페어프로그래밍 느낀점 (익명으로 작성하여 주세요)
아무개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
복사