-
Notifications
You must be signed in to change notification settings - Fork 173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[클린코드 6기 정민지] 로또 미션 STEP 2 #284
base: jungminji0215
Are you sure you want to change the base?
Conversation
아! 헉 step2 에 대한 테스트코드가 없네요.. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 민지님, 테스트 코드 작성 후 리뷰 요청 주세요~
질문에 대한 답변 드릴게요!
step1 에서 피드백 받은 PRIZE_MAP 관련된 사항입니다.
StatisticsLotto가 생성될때 PRIZES 객체를 복사하여 this.#prizes에 할당하고, count 를 증가시킬때는 PRIZES 객체를 복사한 #prizes의 count 가 수정되도록 했습니다. 이렇게하면 상수가 직접적으로 수정되지 않을 것으로 생각됩니다.. 근데 사실.. 이것저것 찾아보면서 방법을 찾은거라.. 확신이 안서는데,
제가 수정한 방식이 상수를 직접 건드리지 않는 방식인지 한번 확인부탁드립니다.
객체가 얕은 복사 방식으로 복사되어, 사본 객체의 하위 객체를 수정했을 때 원본 객체가 함께 수정되어 발생한 문제입니다.
다음과 같은 객체를 { ...obj }
방식으로 복사하고, 사본의 1단계 깊이 프로퍼티인 a
와, 2단계 깊이 프로퍼티인 b.b_a
를 변경하면 원본 객체의 2단계 깊이 프로퍼티인 b.b_a
가 함께 변경되는 것을 확인할 수 있어요.
const 원본 = {
a: "새롭게 복사됨",
b: { // 중첩 객체
b_a: "원본 객체에 대한 참조가 유지됨",
}
};
// 얕은 복사
const 사본 = { ...원본 };
사본.a = "새로운 값"; // 원본 객체의 a는 변경되지 않습니다
사본.b.b_a = "새로운 값"; // 원본 객체의 b.b_a도 변경됩니다
이러한 일이 발생하는 이유는, 자바스크립트의 자료형들이 값을 어떻게 저장하고 있는 지와 관련이 되어 있어요.
자바스크립트의 자료형은 원시값과 객체의 2가지로 나눌 수 있는데요, 원시값(number, string, boolean 등 객체가 아닌 값)이 값 그자체를 저장하고 있다면 객체는 객체를 가리키고 있는 주소값을 저장하고 있습니다.
따라서 호출이 일어날 때, 값을 복사하여 전달하는 과정에서 주소값이 복사되면서 해당 주소값이 가리키고 있는 원래 객체의 하위 프로퍼티는 여전히 연결이 유지되어 있게 됩니다.
원시값을 호출하는 경우
const a = 'a'; // a에 'a'를 저장함
const b = a; // 'a'가 복사되어 전달됨
객체를 호출하는 경우
const a = { a: 'a' } // a에 객체를 가리키는 주소값 100을 저장함
const b = a; // 주소값 100이 복사되어 전달됨
따라서 얕은 복사를 한 객체는 각 하위 객체들이 원본에 대한 참조를 유지하고 있어 값이 함께 변경될 수 있어요. 원본 객체가 변경되지 않도록(불변성) 객체 하위의 모든 중첩된 객체들을 복사해서 사본 객체에 전달해주는 방식을 깊은 복사라고 하고, 사본 객체 생성 시 권장되는 방식입니다. 깊은 복사를 할 때 재귀 호출 등의 방법으로 객체의 모든 프로퍼티를 순회하며 복사하기도 하고, JSON.stringify
, structuredClone와 같은 함수를 사용하거나 혹은 immer 등의 라이브러리를 사용하기도 해요.
이러한 자바스크립트의 동작 원리에 대해서 더 깊이 알고 싶으시다면 원시 값, 값에 의한 참조, 불변성 등의 개념을 참고해주세요.
재시작할 때 초기화 관련 질문입니다.
재시작하면 play() 내부에서 const statisticsLotto = new StatisticsLotto(); 로 인해 StatisticsLotto 를 새로 만들기때문에 #prizes 를 초기화 하는 기능이 필요없겠구나 라고 생각했습니다. 그러나 재시작할 때 이전 count 기록이 남아있더군요.
StatisticsLotto의 인스턴스가 새로 생성되는 것이 아니라 기존의 인스턴스를 사용하는 것으로 보이는데... 다음과 같이 동작하는 이유를 파악하지 못했습니다. 😢 왜 이렇게 동작하는지 궁금합니다.
위와 동일하게 PRIZES
원본 객체가 변경되어 발생한 문제입니다.
오류 발생 시 재입력 관련입니다.
해당 기능을 while 문 안의 try catch 로 감싸는 방식으로 했습니다. 그런데 이렇게 하다보니 while 문 밖에서 변수를 선언할 수 밖에 없다보니 코드가 깔끔하지 못하다는 느낌이 드는데요, 꼭 try catch 방식으로만 해결한 기능인지 궁금합니다. 다른 방법도 있을까요?!
아래 코멘트를 확인해주세요
} | ||
|
||
export function printStatisticsLotto(prizes) { | ||
console.log("\n당첨 통계"); | ||
console.log("--------------------"); | ||
|
||
console.log( | ||
`${prizes.FIFTH.match}개 일치 (5,000원) - ${prizes.FIFTH.count}개` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5000같은 것도 prizes 객체에서 참조해오면 좋을 것 같네요
try { | ||
purchase = await readLineAsync("> 구입금액을 입력해 주세요. "); | ||
lottoMachine = new LottoMachine(); | ||
count = lottoMachine.calculateLottoCount(purchase); | ||
printCount(count); | ||
|
||
const lottos = Array.from({ length: count }, () => { | ||
const lotto = lottoMachine.generateLottoNumber(); | ||
const lottoNumbers = lotto.getLottoNumbers(); | ||
printLottoNumber(lottoNumbers); | ||
return lottoNumbers; | ||
}); | ||
lottos = Array.from({ length: count }, () => { | ||
const lotto = lottoMachine.generateLottoNumber(); | ||
const lottoNumbers = lotto.getLottoNumbers(); | ||
printLottoNumber(lottoNumbers); | ||
return lottoNumbers; | ||
}); | ||
|
||
break; | ||
} catch (error) { | ||
console.error("오류가 발생했습니다: ", error); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
질문, 입력값 변환, 에러 출력등의 코드를 함수로 분리하면 try/catch 구문과 같이 가독성을 해치는 코드들이 추상화되어 가독성이 개선될 것 같습니다. 다음 예시 코드를 보고 비슷하게 구현해봐도 좋을 것 같아요!
const prompt = ({
query, // 질문
validate, // 입력값 검증
transform // 입력값 변환
}) => {
try {
// 질문
// 입력값 검증
// 입력값 변환 및 반환
} catch(e) {
// 에러 출력
}
}
// 질문 프롬프트 로직을 추상화한 예시
const lottos = prompt({
query: "> 구입금액을 입력해 주세요.",
validate: LottoMachine.isValidPurchaseAmount,
transform: (answer) => {
lottoMachine = new LottoMachine();
count = lottoMachine.calculateLottoCount(answer);
printCount(count);
lottos = Array.from({ length: count }, () => {
const lotto = lottoMachine.generateLottoNumber();
const lottoNumbers = lotto.getLottoNumbers();
printLottoNumber(lottoNumbers);
return lottoNumbers;
});
}
})
안녕하세요 리뷰어님 step1 피드백 감사합니다. 이어서 step2 PR 올립니다. 😄
아래는 궁금한 사항들 정리하였습니다!
step1 에서 피드백 받은 PRIZE_MAP 관련된 사항입니다.
StatisticsLotto가 생성될때 PRIZES 객체를 복사하여 this.#prizes에 할당하고, count 를 증가시킬때는 PRIZES 객체를 복사한 #prizes의 count 가 수정되도록 했습니다. 이렇게하면 상수가 직접적으로 수정되지 않을 것으로 생각됩니다.. 근데 사실.. 이것저것 찾아보면서 방법을 찾은거라.. 확신이 안서는데,
제가 수정한 방식이 상수를 직접 건드리지 않는 방식인지 한번 확인부탁드립니다.
재시작할 때 초기화 관련 질문입니다.
재시작하면 play() 내부에서
const statisticsLotto = new StatisticsLotto();
로 인해 StatisticsLotto 를 새로 만들기때문에 #prizes 를 초기화 하는 기능이 필요없겠구나 라고 생각했습니다. 그러나 재시작할 때 이전 count 기록이 남아있더군요.StatisticsLotto의 인스턴스가 새로 생성되는 것이 아니라 기존의 인스턴스를 사용하는 것으로 보이는데... 다음과 같이 동작하는 이유를 파악하지 못했습니다. 😢 왜 이렇게 동작하는지 궁금합니다.
오류 발생 시 재입력 관련입니다.
해당 기능을 while 문 안의 try catch 로 감싸는 방식으로 했습니다. 그런데 이렇게 하다보니 while 문 밖에서 변수를 선언할 수 밖에 없다보니 코드가 깔끔하지 못하다는 느낌이 드는데요, 꼭 try catch 방식으로만 해결한 기능인지 궁금합니다. 다른 방법도 있을까요?!
그럼 감사합니다 😊