[모던자바스크립트 Deep Dive] 4장. 변수 🦎

Shin Hyun Woo·2022년 5월 3일
0
post-thumbnail

원래 '무던한 개발자를 위한 모던한 자바스크립트'라는 책을 먼저 읽고 해보려고 했으나 솔직히 처음부터 어려운 용어들이 많이 나와서 차라리 이럴바엔 "모던 자바스크립트 Deep Dive"를 회독하자! 라는 생각에 시작했다.

모던 자바스크립트 Deep Dive 첫번째 회독을 시작해보자!

4장. 변수

변수란 무엇인가?

애플리케이션은 데이터를 다룬다.
아무리 복잡한 애플리케이션이라도 단순히 데이터를 "입력 input"받아 처리하고 그 결과를 "출력 output"하는 것이 전부이다.

변수프로그래밍 언어에서 데이터를 관리하기 위한 핵심 개념이다.


컴퓨터는 사람을 모델로 디자인되었기 때문에 사람과 유사하게 동작한다.

20 + 10

사람은 위의 연산을 하려면 숫자 "20"과 "10", 연산자 "+"의 의미를 알아야한다. 또한 이것이 "20"과 "10"을 "더한다"라는 의미도 해석할 수 있어야한다.

그리고 위의 연산을 해석하고 "20", "10", "+"를 두뇌에 기억하고 그 결과인 "30"도 기억한다.

자바스크립트 엔진 또한 자바스크립트 코드를 계산하기 위해 숫자 "20", "10"과 연산자 "+"의 의미를 알고 있어야 하며, 이것이 "20"과 "10"을 "더한다"라는 의미도 알고 해석할 수 있어야한다.

사람과 컴퓨터의 차이점은 사람은 계산/기억을 모두 두뇌에서 하지만 컴퓨터는 연산과 기억을 수행하는 부붐이 나눠져 있다는 것이다.

컴퓨터 CPU를 통해 연산하고 메모리를 사용하여 데이터를 기억한다.

여기서 메모리는 데이터를 저장할 수 있는 메모리 셀의 집합체이다.
메모리 셀 하나는 1바이트(8비트)이며, 해당 1바이트인 메모리 셀에 데이터를 저장하거나 읽어들인다.


각 메모리 셀은 고유의 메모리 주소를 가진다.

이 메모리 주소는 메모리 공간의 위치를 의미하고 0부터 메모리의 크기만큼 정수로 표현된다.

위의 예제를 메모리를 추가하여 설명해보면,

숫자 "10", "20"은 메모리 상의 임의의 위치(메모리 셀의 메모리 주소)에 저장되고 CPU는 이 값을 읽어들여 연산을 수행한다. 연산 결과로 생성된 숫자 "30"도 메모리 상의 임의의 위치에 저장된다.

연산이 끝나서 결과는 나왔으나 현재 결과 값을 재사용할 수가 없다.
그래서 이 상황에서 사용하는 것이 "변수"이다.

변수(Variable)는 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 메모리 공간을 식별하기 위해 붙인 이름이라고 정의 내려진다.

위의 이미지를 보면 "변수명 선언"이라는 하나의 과정이 추가된 것을 볼 수 있다. 이를 통해 연산을 통한 결과 값을 다시 재사용할 수 있게 되었다.

❓ 메모리 셀마다 주소와 변수명은 같은가?

메모리 셀마다 메모리 주소가 있다는 말을 위에서 했었다.
보통 메모리 주소는 "0x00000000" ~ "0xFFFFFFFF)까지의 메모리를 가지는데 복잡한 메모리 주소로 직접 접근하는 것은 치명적인 오류를 발생시킬 수 있어 "변수"라는 것을 사용하는데 변수의 이름은 "변수명" 또는 식별자라고도 한다.

위의 이미지에서 "변수명 선언"이라는 과정에서 기존에 여러가지 값들을 저장하던 메모리 셀의 주소 대신 그 셀을 상징하는 "식별자명"을 입력하여 결과값에 접근하여 재사용하게 해준다.

이렇게 식별자명을 지어주는 것은 "변수의 선언"이라고 한다.


변수의 선언과 할당

변수의 선언은 위에서 설명한 것처럼 메모리 주소를 상징하는 "식별자명"을 지어주고 변수에 값을 저장한다.

위 과정을 코드로 나타내면 아래처럼 된다.

  1. 변수의 선언 : 식별자명을 선언하여 메모리 셀의 주소에 상징적인 이름을 붙인다. 여기서 값을 할당하지 않으면 기본값인 'undefined'가 할당이 된다. 'undefined'가 할당되는 것을 "변수값을 초기화한다"라고 한다.

변수의 선언은 키워드인 'var', 'let', 'const'를 사용하여 선언하면 된다.

<script>
  let result; // 변수의 선언
</script>

⚠️ var 키워드는 사용하지 않는 것이 좋다.

"var" 키워드는 여러 단점이 있다. 단점 중 가장 대표적인 것이 "블록 레벨 스코프"를 지원하지 않고 "함수 레벨 스코프"를 지원한다는 것이다. 이는 의도치 않게 전역 변수가 선언이 되어 심각한 오류를 발생시킬 수 있는 위험이 있다.

함수 레벨 스코프란, 함수를 제외한 나머지 블록({})에서 선언된 변수는 "전역 변수"가 되는 것이다.

<script>
  // 조건문 if
  	if(true){
  		var test = true;
  	}
  
  	alert(test) // 함수 블록이 아니기 때문에 var는 전역변수로 접근가능 
  
  // 반복문 for
  
  	for (var i = 0; i < 10; i++) {
		...
  	}	
	alert(i); // 함수 블록이 아니기 때문에 var는 전역변수로 접근가능
</script>

위의 소스코드처럼 함수가 아닌 if문, for문 등 "함수" 블록이 아닌 블록 내에서 선언된 변수는 전역 변수로 선언이 된다고 생각하면 된다.

<script>
  // 함수
  function sayHello(){
  	if(true){
  		var say = "hello";
  	}
  	alert(say); // 함수 sayHello 블록 내에서 선언된 변수이기 때문에 접근 가능
  }
  
  sayHello();
  alert(say); // var는 함수 레벨 스코프이기 때문에 함수 내에서만 접근이 가능하다. 그래서 접근 불가
</script>

하지만 함수 레벨 스코프인 'var' 키워드는 함수 블록 내에서 선언된 변수는 그 함수 내에서만 접근 가능한 "지역 변수"가 된다고 생각하면 쉽다.

'var'와 반대로 'let'과 'const'는 "블록 레벨 스코프"로 블록으로 감싸진 모든 곳에서 선언한 변수는 지역변수가 되어 'var'처럼 나도 모르게 전역 변수를 선언하는 위험이 없다. 그래서 더욱 'let'과 'const' 사용이 권장된다.


  1. 변수에 값을 할당(저장) : 변수에 값을 저장한다.
<script>
  let result = 30; // 변수에 값을 할당
</script>

  1. 변수를 참조 : 변수에 저장된 값을 읽는다.
<script>
  let result = 30; // 변수에 값을 할당
  console.log(result); // 변수에 저장된 값을 읽는다(참조한다)
</script>

변수의 호이스팅 ⭐️

<script>
	console.log(score);  
  	
  	var score; // 기본값 undefined
</script>

위의 소스코드를 보면 콘솔창에 출력하는 console.log()score라는 변수를 출력하라고 명령했다.

하지만 console.log(score)는 변수를 선언하는 코드보다 위에 있다. 이것을 실행시켜보면 아래의 결과를 볼 수 있다.

현재 var 키워드를 통해 선언된 변수 scoreundefined를 기본값으로 할당되는데 정상적으로 출력되는 것을 볼 수 있다.

이것은 바로 "변수의 호이스팅" 때문이다.

❓ 변수의 호이스팅(Variable Hoisting)이란?

변수의 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 '자바스크립트 고유의 특징'이다.

변수의 선언은 소스코드가 한 줄씩 순차적으로 실행되는 시점을 의미하는 '런타임(Runtime)'이 아닌 그 이전 단계에서 먼저 실행이 되는데 이를 호이스팅이라고 한다.

하지만 변수말고도 키워드를 사용하여 선언하는 모든 식별자(변수/함수/클래스 등)가 호이스팅이 된다.

한번 더 예시를 보자. 여기서 가장 위와 가장 아래의 console의 출력값은 어떻게 될까?

<script>
  console.log(score);
  
  score = 80; // 변수에 값 할당
  var score; // 변수의 선언
  
  console.log(score);
</script>

위의 소스코드는 아래의 코드로 읽을 수 있다.

<script>
  var score; // 호이스팅으로 인해 변수의 선언이 코드의 최상단으로 이동
  
  console.log(score); // 변수에 값이 할당되지 않았기 때문에 undefined
  
  score = 80; // 변수에 값 할당
 
  console.log(score); // 80, score 변수에 80이 할당되었음
</script>

호이스팅으로 인해 첫번째 console의 출력값은 변수 score는 선언만 했을 뿐 값이 할당이 되지 않았기 때문에 기본값인 undefined이 된다.

반면에 가장 마지막 줄의 console의 출력값은 위의 score = 80으로 인해 값이 할당이 되었기 때문에 80을 출력한다.

호이스팅은 처음에 보면 헷갈리지만 점차 하다보면 익숙해 질 것이다. 비전공자인 나도 그랬다.
그리고 이는 반드시 알아둬야한다는 말이 많았다. 실제로 면접에서도 자주 나오는 문제라고 한다.

변수의 재할당

변수의 재할당이란, 기존 선언한 변수에 할당한 값을 다시 할당하는 것을 말한다.

재할당의 과정

<script>
  var score = 80; // 변수의 선언과 동시에 값을 할당
  score = 90 // 값의 재할당
</script>

위의 소스코드를 이미지로 보면 이렇다.


  1. 변수 선언 : 변수에 식별자를 선언하여 메모리의 셀에 기본값인 "undefined"를 저장한다.

  2. 값의 할당 : 변수의 식별자 score가 할당된 값인 80의 메모리 셀로 이동한다.

  3. 값의 재할당 : 변수의 식별자 score가 재할당된 값인 70의 메모리 셀로 이동한다.


위를 보면 식별자인 score가 메모리 셀을 이동하는 것을 볼 수 있다. 실제로는 메모리 셀이 아닌 메모리 주소를 따라 이동하는 것이다.

이것은 값이 할당된다고 해서 선언부터 저장되어있던 메모리 셀 자리에서 재할당되는 것이 아닌 새로운 메모리 셀의 주소를 따라 이동한다는 것을 알 수 있다.

const의 특징

하지만 이미 값을 할당한 변수에 재할당을 할 수 없는 경우도 있다.
바로 상수 키워드인 'const'를 사용할 때이다.

<script>
  const score = 80;
  score = 70;
  // Uncaught TypeError: Assignment to constant variable. 에러 발생
</script>

상수인 score에 재할당을 시도하면 "상수로 지정됨"이라는 에러를 볼 수 있다.

만약 재선언이 되지 않아 위와 같은 에러가 발생한다면 변수가 const 키워드를 사용하여 선언된 것은 아닌지 확인을 해봐야할 것이다.

식별자 네이밍 규칙

위에서 정리된 것처럼 식별자는 "어떤 값을 구별해서 식별해낼 수 있는 고유한 이름"을 말한다.
규칙인 만큼 아래와 같은 네이밍 규칙을 준수해야한다.

<script>
  var person, $elem, _name, first_name, val1; // 사용 가능
</script>
  • 식별자는 특수문자를 제외한 문자, 숫자, 언더스코어(_), 달러 기호($)를 포함할 수 있다.
    : 참고로 위의 코드처럼 변수 키워드를 하나를 쓰고 식별자를 ,로 구분하여 쓰면 나열한 변수들이 모두 선언된다. 하지만 가독성이 나빠짐으로 사용을 권장하지 않는다.

  • 단, 식별자는 특수문자를 제외한 문자, 언더스코어(_), 달러 기호($)로 시작해야 한다.

  • 숫자로 시작하는 것은 허용되지 않는다. 아래의 이미지처럼 에러를 보게 될 것이다.

<script>
  var 2val; // Uncaught SyntaxError: Invalid or unexpected token 에러 발생
  var 2words; // Uncaught SyntaxError: Invalid or unexpected token 에러 발생
</script>

  • 예약어는 식별자로 사용할 수 없다.
    : 예약어는 프로그래밍 언어에서 사용되고 있거나 사용될 예정인 단어를 의미한다. MDN 공식문서로 링크를 걸어놨으니 확인해보면 될 것이다.

가능하지만 권장하지 않는 것

  • 식별자를 만들 때 유니코드 문자를 허용하기 때문에 알파벳 이외에 한글이나 일본어를 사용할 수 있지만 권장하지 않는다.
<script>
  var 한글;
  var 何でも;
</script>

허용을 하기 때문에 에러가 발생하지 않는다.

  • 변수의 이름은 자유지만 변수의 존재 목적을 쉽게 캐치할 수 있게 명확히 표현해야한다.
    : 만약 변수 자체에 설명이 필요해서 주석을 사용한 것이라면 "의미를 명확히 드러내지 못한다"라고 간주해도 된다.
    변수가 보통의 변수의 길이보다 길어지더라도 명확하게 작성하는 것이 중요하다.
<script>
  var x = 30; // x는 무엇을 의미하는 것인지 모호하다. 그래서 의미없는 변수명은 되도록 사용하지 않는 것을 권장한다.
  var score = 30; // score가 무슨 변수인지 캐치가 가능하다.
</script>

네이밍 컨벤션

네이밍 컨벤션이란 하나 이상의 영어 단어로 구성된 식별자를 만들 때 가독성 좋게 단어를 한눈에 구분하기 위해 규정한 명명 규칙이다.

이것 또한 다양한 방식이 존재한다.

  • 카멜 케이스(Camel Case) : 낙타의 등처럼 보이는 컨벤션 방식이다. 단어가 바뀔 때마다 대문자로 구분하여 작성한다.
<script>
	var camelCase = "camel"
</script>
  • 스네이크 케이스(Snake Case) : 뱀이 바닥에 기어다니는 것처럼 언더스코어(_)를 사용하여 단어 간의 구분을 한다.
<script>
	var snake_case = "snake"
</script>
  • 파스칼 케이스(Pascal Case) : 모든 단어의 시작을 모두 대문자로 작성하는 컨벤션 방식
<script>
	var PascalCase = "pascal"
</script>

다양한 네이밍 컨벤션 중 자바스크립트에서 가장 많이 사용하는 것은 "카멜 케이스"와 "파스칼 케이스"이다.
카멜 케이스는 주로 "변수"나 "함수"의 이름에 주로 사용된다.
파스칼 케이스는 "생성자 함수"나 "클래스 이름"에 주로 사용된다.

주로 사용하는 것을 따라가는 것이 아무래도 협업이나 가독성을 높이는데 중요하기 때문에 이 두 가지 네이밍 컨벤션을 사용하는 것을 권장한다.

profile
untiring_dev - Notion 페이지는 정리 중!

0개의 댓글