티스토리 뷰

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

출처😌

클린코드 자바스크립트 | Udemy

자료🙄

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 제작자 (10일만에 제작)

 

 

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
댓글
다크모드
Document description javascript psychology
더보기 ,제목1 태그 호버