티스토리 뷰
🔖TAG 💡scope, 💡var지양, 💡변수다루기, 💡임시변수제거, 💡함수표현식, 💡호이스팅 📕

출처😌
자료🙄
Git: pocojang/clean-code-js (github.com)
목차
1. 과정 소개 🚩
1-1. 클린 코드를 고민해야하는 이유
1-2. JS의 특성을 파악해야하는 이유
1-3. JS Everywhere
1-4. 사례를 파악하고 의식적으로 수련하기
2. 변수 다루기 🚩
2-1. var를 지양하자
2-2. function scope & block scope
2-3. 전역 공간 사용 최소화
2-4. 임시변수 제거하기
2-5. 호이스팅 주의하기
3. 타입 다루기
4. 경계 다루기
5. 분기 다루기
6. 배열 다루기
7. 객체 다루기
8. 함수 다루기
1. 과정소개🙃
1-1. 클린 코드에 대해 고민하기
- 타인이 정의한 답을 의심합니다.
- 배움에 열린 태도를 가집니다.
- 직접 생각하고 또 고민합니다.
- 클린 코드가 무엇인지를 자바스크립트를 통해 학습합니다.
- 흔히 알려진 자바스크립트 코드 스타일에 대한 견해를 탐구합니다.
1-2. JavaScript 특성 파악하기
- JS는 타입이 동적으로 형변환되는 언어입니다. 자연스러운 변화. 즉, 몽키 패치라고도 합니다.
- 몽키 패치(Monkey patch) : 런타임 중인 프로그램의 내용이 변경되는 행동을 의미합니다.
- JS를 이루는 기능의 원출처는 아래와 같습니다.
- 문법 -> Java
- 문자열, 배열, 정규표현식 -> perl
- 함수 -> 오크
- 클로저, 스코프환경 -> 스키마
- 프로토타입 -> 셀프
- 이벤트 -> 하이퍼토크
- JS 밈: The Best JavaScript Meme I've Ever Seen, Explained in detail (freecodecamp.org)
- WTF JS ?! : wtfjs/README-kr.md at master · denysdovhan/wtfjs (github.com)

1-3. JavaScript EveryWhere

Node을 출현이후 JS는 폭발적인 성장을 이뤄냈습니다.
예시 앱으로는 VSCode, Notion, Twitch, 야놀자 등등이 있습니다.
1-4. 사례를 파악하고 의식적으로 수련하기
function hello() {
return 'Hello World!'
}
위의 코드를 누가 보느냐? 또는 상황에 따라서 [👍 / 👎] 코드가 될 수 있습니다.
항상 👍코드와 👎코드를 확인해 나가면서 학습을 진행 할 것입니다.
의식적인 수련의 가장 적절한 예는 피드백 주고받기가 있습니다.
2. 변수다루기🧐
2-1. var를 지양하자
- var를 사용하지 말고 const를 주로 사용해야한다는 말을 들어보신적 있나요?
- JS에서 let과 const는 ES2015버전 부터 생긴 것이라 이전에는 어쩔 수 없이 var를 쓸 수 밖에 없었습니다.
- var를 대신할 좋은 기능의 예가 let 과 const가 된 것입니다.
- 핵심
- var는 함수 스코프입니다.,
- let & const는 블록 단위 스코프이고 TDZ(temperal dead zone) 속성을 가집니다. -> 안전한 코드 작성가능
👎 var
똑같은 이름의 변수를 재선언(중복선언)해도 동작합니다.
var name = '이름1'
var name = '이름2'
var name = '이름3'
console.log(name) // 이름3
콘솔을 먼저 찍어봐도 동작합니다.
console.log(name) // 이름1
var name = '이름1'
지금은 코드의 길이가 짧아서 코드를 이해하는데에 무리가 없지만, 코드가 엄청 많을 때는 코드를 보기가 힘들어 집니다.
👍 let & const
이미 선언된 변수라고 오류를 냅니다.
let name = '이름1'
let name = '이름2' // Uncaught SyntaxError: Identifier 'name' has already been declared (at practice:2:5)
let name = '이름3'
console.log(name)
변수를 선언하기 전에 콘솔로 변수를 찍어보면, 변수가 선언되지 않았다고 오류를 냅니다.
console.log(name) // Uncaught ReferenceError: name is not defined at practice:1:13
let name = '이름1'
let과 const의 차이점은 재할당의 차이 입니다.
let name = '이름1'
name = '이름2'
name = '이름3'
console.log(name) // 이름3
const height = 160
height = 161; // Uncaught TypeError: Assignment to constant variable.
console.log(height)
2-2. function scope & block scope
👎 var
전역변수가 담긴 문자열
var global = '전역'
if (global === '전역') {
var global = '지역'
console.log(global) // 지역
}
console.log(global) // 지역 <- 전역 공간 스코프까지 오염되었습니다.
var는 함수단위 스코프 이고 if 문은 블록 스코프 이기 때문에 global 값이 바뀌게 된것입니다.
👍 let & const
let은 블록 스코프 이기 때문에 전역변수에 영향을 미치지 않습니다.
let global = '전역'
{
let global = '지역'
console.log(global) // 지역
}
console.log(global) // 전역
const는 재할당이 안됩니다.
하지만, const로 선언된 객체(Object, Array ...)는 내부의 값을 바꾸는 방법이 있습니다.
// const로 선언한 객체
const person = {
name: 'LEE',
age: '10'
}
// 당연히 const는 재할당이 안됩니다.
// person = {name: 'PARK', age: '11'} //Uncaught TypeError: Assignment to constant variable.
// 하지만 const로 선언된 객체 내부의 값을 바꾸는건 가능합니다.
person.name = 'PARK'
person.age = '11'
console.log(person) // {name: 'PARK', age: '11'}
const로 선언된 배열
const person = [
{
name: 'LEE',
age: '10'
}
]
//const로 선언된 배열 역시 재할당이 불가능합니다.
// person = [ { name: 'PARK', age: '11' } ] // Uncaught TypeError: Assignment to constant variable.
//const로 선언된 배열의 내부 값 바꾸는 방법
person[0] = (
{
name: 'PARK',
age: '11'
}
)
console.log(person)
2-3. 전역 공간 사용 최소화
전역공간을 왜 사용하면 안되는지 혹은 최소화해서 사용해야 하는지에 대해서 알아보겠습니다.
누군가 이야기 합니다.
"전역공간을 사용하지말라!"
왜 그럴까요?🤔
전역공간이란 무엇일까요?
말그대로 ①Global 혹은 ②Window라고 합니다.
브라우저 환경에서 돌아가는 경우에는 Window가 최상위이고
NodeJS 환경에서는 Global이 최상위 입니다.
console.log(window) //Window {window: Window, self: Window, document: document, location: Location, …}
즉, 최상위 공간(Window, Global)이 전역 공간이 되는 것입니다.
발생할 위험성
① 변수 중복
Html 파일에 script 파일이 2개 들어갔다고 가정해봅니다.
이때 첫 번째 파일에서 전역변수를 선언해놓고 콘솔에 찍어보면 원하는대로 잘 나옵니다.
하지만 두 번째 스크립트 파일에서 첫 번째 스크립트에 전역변수로 만든 변수를 콘솔로 찍으면 값이 나옵니다.
이게 왜 나오는 것일까요? 그건 전역에 변수를 저장해놓았기 때문입니다.
저같은 초보 개발자에게는 위험을 초래할 수 있는 환경입니다.
첫 번째와 두 번째 스크립트에서 전역 공간을 써버리면 변수가 겹치는 문제가 발생할 수 있습니다.
<!DOCTYPE html>
<html>
<body>
<script>
var globalVar = '전역'
console.log(globalVar) // 전역
</script>
<script>
console.log(globalVar) // 전역
console.log(window.globalVar) // 전역
</script>
</body>
</html>
여기서 이런 의문이 들 수 있습니다.
어? 파일을 나누면 코드 구역도 나뉘는게 아닌가?🤔
그렇지 않다는 것이죠. 코드의 구역 보다는 Scope로 생각하는게 좋습니다.
<script></script> 와 <script></script> 부분이 하나의 Scope로 묶입니다.
<!DOCTYPE html>
<html>
<body>
<script>
let localLet = '지역'
console.log(localLet) // 지역
const localConst = 'CONST'
console.log(localConst) // CONST
</script>
<script>
// localConst = 'CONST2' //Uncaught TypeError: Assignment to constant variable.
console.log(localLet) // 지역
</script>
</body>
</html>
② 내장함수 사용 시 오류발생 가능성 (ex. setTimeout 함수)
첫 번째 스크립트에서 setTimeout이라는 변수를 선언하면
두 번째 스크립트에서 잘 사용하던 setTimeout 함수가 동작하지 않게 됩니다.
<!DOCTYPE html>
<html>
<body>
<script>
var setTimeout = 'setTimeout'
</script>
<script>
setTimeout(() => { // Uncaught TypeError: setTimeout is not a function
console.log('1sec')
}, 1000)
</script>
</body>
</html>
③ var로 for문을 사용할 때
for 에서 i 값이 for 문을 벗어났는데도 i값이 찍힙니다. var가 함수 스코프이기 때문에 전역 변수로 저장되기 때문입니다.
그래서 var 대신 const & let으로 바꿔주는게 좋습니다.
const array = [1, 2, 3]
for (var i = 0; i < array.length; i++) {
console.log(array[i]) // 1 2 3
}
console.log(i) // 3
요약
1. 전역 공간을 더럽히지 말아야합니다.
이유는 어디서나 접근이 가능하기 때문입니다.
그래서 전역변수를 애초에 만들지 않는 것이 좋습니다.
2. 지역변수만 사용하는게 좋습니다.
3. Window, Global에 접근하여 조작하지 않는게 좋습니다.
4. var 대신 const & let을 쓰면 위의 문제들이 어느정도 해소가 됩니다.
5. IIFE(즉시실행함수), Module, Closure 와 같이 Scope를 나누는 방법에 대해 고민해볼 필요가 있습니다. (추후 나옴)
2-4. 임시변수 제거하기
임시변수란 특정 공간의 Scope안에 전역변수처럼 활용되는 친구를 말합니다.
const로 선언된 임시 객체(result)도
getElements 함수가 커지면
전역 공간이나 다름 없는 상황이 나올 수 있습니다.
그러면 이 임시 객체인 result가 위험한 요소가 될 수 있습니다.
왜냐하면 임시 객체(result)가 생기는 순간 이 객체에 접근해서 CRUD를 하고 싶은 유혹이 들기 때문입니다.
이런 상황은 전역변수를 만드는 것과 다름이 없습니다.
function getElements() {
const result = {} // 임시 객체
result.title = document.querySelector('.title')
result.text = document.querySelector('.text')
result.value = document.querySelector('.value')
// ...
// ...
return result
}
임시 변수를 제거하는 간단한 방법 :
① 객체안에 미리 선언하기
function getElements() {
const result = {
title: document.querySelector('.title'),
text: document.querySelector('.text'),
value: document.querySelector('.value')
}
return result
}
② 더 명확한 방법: 객체로 바로 반환하기
function getElements() {
return {
title: document.querySelector('.title'),
text: document.querySelector('.text'),
value: document.querySelector('.value')
}
}
요약
Q. 임시변수 제거해야하는 이유?
① 임시변수는 않좋습니다. 이유는 명령형으로 가득한 로직이 나오기 때문 입니다.
② 어디서 어떻게 값이 나오게되었는지 디버깅하기 힘듭니다.
③ 추가적인 코드를 작성하고 싶은 유혹이 듭니다. 그러면 코드 유지보수가 힘들어집니다.
Q. 해결책?
① 함수를 나눕니다.
② 함수를 바로 반환하는 것이 좋습니다.
③ 고차함수를 사용합니다 (map, filter, reduce)
④ 선언형 코드로 바꾸는게 좋습니다. (↔명령형)
2-5. 호이스팅 주의하기
호이스팅이란?
선언과 할당이 분리된 것을 말합니다. 언제? 바로 런타임(프로그램 동작)시를 말합니다.
코드를 작성할 때는 스코프를 예상해서 작성해 나갑니다.
하지만 런타임때는 작성자의 예상대로 움직여 주지 않는 경우가 있습니다.
그 현상 중에 하나가 호이스팅 입니다.
호이스팅은 var로 선언한 변수가
초기화가 제대로 되어 있지 않았을 때
undefined로 최상단에 끌어올려줄 수 있는 것을 뜻합니다. (즉, 선언부만 최상단으로 끌어올려지는 것입니다)
let & const를 쓰면 이런 현상은 잘 겪지 않겠지만(TDZ),
var를 쓰면 종종 겪는 문제입니다.
호이스팅의 종류
① var 호이스팅
console.log(global) // 0.3
var global = 0.3
function outer() {
console.log(global) // undefined 📌호이스팅이 동작한 사례
var global = 5 //📌 함수 스코프 안에서 여기의 var global = undefined; 가 outer함수 최상단에 끌어올려집니다.
function inner() {
var global = 10
console.log(global) // 10
}
inner()
global = 1
console.log(global) // 1
}
outer()
📌부분이 아래의 코드와 같습니다.
function outer() {
var global;
console.log(global) // undefined
global = 5
}
아래의 경우는 알아보기가 쉽습니다.
하지만 var와 같이 전역변수를 만드는 것이나, 호이스팅이 동작하게 하는 것은
개발자들이 실수를 하게 하는 요소가 될 수 있습니다.
function duplicatedVar() {
var a
console.log(a) // undefined
var a = 100
console.log(a) // 100
}
duplicatedVar()
② 함수 호이스팅
sum()이 어느 자리에 있든 값이 찍히는 이유는
함수도 호이스팅 되기 때문입니다.
var sum
sum = function() {
return 1 + 2
}
console.log(sum()) // 3
var sum
console.log(sum()) // 3
sum = function() {
return 1 + 2
}
console.log(sum()) // 3
var sum
sum = function() {
return 1 + 2
}
함수 선언문으로 변수를 덮어씌울 수도 있습니다.
console.log(sum()) // 10
var sum
sum = function() {
return 1 + 2
}
sum = function() {
return 1 + 2 + 3
}
sum = function() { // 마지막의 이 녀석이 호이스팅 됩니다.
return 1 + 2 + 3 + 4
}
결국 위의 코드는 아래와 같습니다.
var와 함수가 맨위로 호이스팅되어 올라갑니다.
그리고 콘솔에 값이 찍히는 것이죠.
var sum
sum = function() {
return 1 + 2
}
sum = function() {
return 1 + 2 + 3
}
sum = function() {
return 1 + 2 + 3 + 4
}
console.log(sum()) // 10
🤔 그렇다면, 호이스팅을 탈피할 수 있는 방법은 무엇이 있을 까요?
🤩보통 함수를 만들 때 const를 사용해서 만든 후 함수를 할당하는 방식을 추천합니다. (함수 표현식)
함수 표현식은 함수 호이스팅을 막을 수 있어서 실수할 여지를 줄일 수 있습니다.
함수 표현식이란 익명의 함수 function() { return 1+2 }를 변수에 할당하는 것입니다.
console.log(sum()) // Uncaught ReferenceError: sum is not defined
const sum = function() { // 함수 표현식 (vs 함수 선언문)
return 1 + 2
}
📌결론적으로 함수를 만들 땐? 함수 표현식으로 만드는 것을 추천드립니다.
요약
① 호이스팅은 런타임시에 바로 선언을 최상단으로 끌어올려 주는걸 말합니다.
② 문제는 코드를 작성할 때 예측하지 못한 실행 결과가 노출되는 것입니다.
③ 이런 예측하지 못하는 상황을 탈피하기 위해 var를 지양합니다. (let & const 사용하기)
④ 함수도 호이스팅 되기 때문에 함수를 사용할 때는 함수 표현식을 사용합니다.
'WEB > JavaScript' 카테고리의 다른 글
| [클린코드 For JS] 4. 경계 (0) | 2022.06.27 |
|---|---|
| [클린코드 For JS] 3. 타입 (0) | 2022.06.27 |
| 타자게임 - 데이터상태처리 (setInterval) & API 연동 (0) | 2022.06.16 |
| 타자게임 이벤트 처리 (basic) (0) | 2022.06.15 |
| TODO Dom & Event (0) | 2022.06.14 |