Front-JS-Basic-02-변수(Variable)

SeungWoo Yoo ·2023년 2월 7일

JS-Basic

목록 보기
2/3

1. 컴퓨터 구성요소

컴퓨터를 구성하는 가장 중요한 요소 3가지는 하드디스크, CPU, 메모리입니다.

컴퓨터에서 문서 파일을 실행시키면, 다음과 같은 과정이 진행됩니다.

  1. 하드디스크에 저장된 폴더 안에 들어와서 파일을 선택하고, 어떤 것을 여는지를 CPU가 처리
    1. 하드디스크에 있는 문서 파일을 인식하고 메모리 상으로 가지고 옴
    2. 파일을 열고 처리할 수 있는 어플리케이션을 모니터에 출력
  2. 사용자가 수정하는 내용들을 메모리 상에 주기적으로 업데이트하면서 작업을 처리
  3. 작업한 내용을 저장하고 어플리케이션을 종료하면, 메모리 상에 있는 데이터를 하드디스크 안에 다시 저장

JS-Basic-2-1

어플리케이션을 열고 무언가를 처리하는 데는 메모리 상에 데이터를 보관하고, 읽고, 쓰는 등의 작업을 합니다.

  • 메모리는 ‘메모리 셀’이라고 불리는 단위로 동작하며,
  • 각각의 메모리 셀은 1 Byte(=8 Bit) 단위로 구성됨

컴퓨터에서 여러 개의 어플리케이션을 사용하면, 어플리케이션 마다 필요한 메모리들이 할당됩니다.
사용자가 앱을 많이 열어서 메모리가 더 필요하다면, (A앱과 B앱이 있다고 가정)

  • A앱을 사용 중일 떄는, B앱은 사용하지 않기 때문에 B앱은 잠시 하드디스크에 저장합니다.
  • c.f. 만약 내 컴퓨터 메모리보다 앱이 더 많은 메모리를 요구한다면, 에러가 발생하고 앱이 정상 동작하지 않음

JS-Basic-2-2

어플리케이션이 메모리에 올라왔을 때, Code, Data, Stack, Heap의 4개의 구조로 구성됩니다.

  • Code : 개발자들이 작성하는 코드를 저장하는 공간
  • Data : 어플리케이션이 전반적인 필요로 하는 변수, 데이터 등을 저장하는 공간
  • Stack : 어플리케이션이 함수를 호출하는 실행 순서를 저장하는 공간
  • Heap : 어플리케이션에서 단순한 데이터가 아니라 여러 개의 데이터타입을 묶은 복잡한 데이터(객체)를 저장하는 공간

1.1 비트와 바이트

컴퓨터는 0과 1밖에 이해하지 못합니다. 컴퓨터가 처리할 수 있는 가장 작은 정보 단위는 비트(Bit)입니다.

  • Bit는 0 또는 1이라는 정보를 담을 수 있음
  • 신호가 없고 있는 등의 정보만 처리
  • 사람은 10개의 손가락을 이용해 숫자 1~10까지 10진수를 다루지만, → 10진수
  • 컴퓨터는 신호가 있고 없고의 딱 2가지만 다룸 → 2진수

2진수(Binary Digit)들이 모여 좀 더 큰 범위의 데이터를 다룰 수 있습니다.

경우의 수 공식을 이용해보면, 한 비트당 2가지 경우를 나타낼 수 있으므로

  • 1bit는 2가지 정보를 표현
  • 2bit는 4가지의 정보를 표현
  • 3bit는 8 (2x2x2)가지 정보를 표현
  • 8bit는 총 256개의 다른 정보를 나타낼 수 있습니다.

컴퓨터에서 데이터를 처리할 떄, 가장 기본적인 단위를 1 Byte라고 애기하는데,
1 Byte8 Bit로 구성되어 있기 때문에, 256가지의 다른 정보를 담을 수 있습니다.


1.2 진수 변환

1.2.1 10진수 → 2진수

// 10진수 29를 2진수로 바꾸려면?
// 1. 29를 2로 계속 나눗셈!
// 2. 나머지를 연결하면 2진수

2 | 29
2 | 14  ----- 1
2 |  7  ----- 0
2 |  3  ----- 1
     1  ----- 1
     
29를 2진수로 바꾸면, `11101`

1.2.2 2진수 → 10진수

// 2진수 `11101`을 다시 10진수로 바꾸려면?
// 1. 오른쪽부터 2^0부터 적고, 각 자리의 비트와 곱셈
// 2. 각 자리의 곱셈한 결과를 다 더하면 10진수

  1    1    1    0    1  
  *    *    *    *    *
2^4  2^3  2^2  2^1  2^0
------------------------
 16 +  8 +  4 +  0  + 1 = 29

1.3 메가와 메비의 차이

PC용단축이름용량
BByte
kilobyteKB1024 Byte2102^{10} Bytes
megabyteMB1024 KByte2202^{20} Bytes
gigabyteGB1024 MByte2302^{30} Bytes
terabyteTB1024 GByte2402^{40} Bytes

윈도우, 맥, 리눅스 같은 PC 운영체제에서는 1024씩 곱해서 2진수 단위로 저장합니다.

외장디스크, USB용단축이름용량PC용 용량
BByte
kilobyteKB1000 Byte1000 Bytes1024 Byte
megabyteMB1000 KByte100021000^2 Bytes
gigabyteGB1000 MByte100031000^3 Bytes
terabyteTB1000 GByte100041000^4 Bytes1024 GByte

외장디스크나 USB1000씩 곱해서 10진수 단위로 저장합니다.
옛날에는 컴퓨터의 용량과 하드디스크의 크기도 적었기 때문에 이런 차이가 큰 문제가 되지 않았습니다.
KB 단위는 10진수 1000, 2진수 1024는 24Byte밖에 차이가 나지 않았습니다.
그러나 TB 단위에서는 24GByte나 차이가 나게 됩니다.

그래서 100MB로 표기된 하드디스크나 USB 등을 구매해서 운영체제에 꼽으면,
실제 저장할 수 있는 사이즈는 95.37MB라고 뜹니다.
이는 10진수 표기법과 2진수 표기법으로 계산된 결과가 다르기 때문입니다.
(c.f. 옛날에는 이걸로 제조사에 항의하는 일이 많았다고 함)

IEC 1998 표기법단축이름용량
BByte
kibibyteKB1024 Byte2102^{10} Bytes
mebibyteMB1024 KByte2202^{20} Bytes
gibibyteGB1024 MByte2302^{30} Bytes
tebibyteTB1024 GByte2402^{40} Bytes

이런 혼란을 잠재우고자 1998년 IEC 단체에서 다른 표기법을 제안합니다.

  • KB, MB는 기존의 사람들이 쓰는 10진수로 남겨두고,
  • Binary형태로 애기할 떄는, 뒤에 2진수(binary)를 붙여서 kibibyte, mebibyte라고 부르자고 약속을 하게 되었습니다.
  • (c.f. 물론 아직 사람들이 kilobyte와 kibibyte를 혼동해서 부르곤 합니다.)

1.4 문자 인코딩

지구 상에 존재하는 수 많은 언어들을 0과 1로 표현할 수 있었을까요?
예전에는 각각의 나라별로 EUC-KR, EUC-JP 등 언어마다 다양한 텍스트 인코딩이 존재했는데,
서로 다른 인코딩 규격때문에 웹사이트가 깨지거나 한글 문서가 읽어지지 않는 문제점 등이 많이 발생했습니다.

이것을 해결하기 위해 나온 것이 UTF-8(Unicode Transformation For mat, 8bit)입니다.

  • 기존 ASCII 코드뿐만 아니라 모든 Unicode 코드를 나타낼 수 있는 웹사이트에서 기본적으로 사용
  • 통상적으로 가장 많이 사용하는 텍스트 인코딩
  • ‘가변길이 유니코드 인코딩’ 방식으로 길이가 정해져 있지 않고, 필요에 의해서 길어질 수 있음
  • 모든 ASCII 코드는 7 bit로 나타낼 수 있기 때문에 1 Byte로 표현하고, Unicode 코드는 2 ~ 4 Byte로 표현
  • 1 Byte로 표현할 수 있다면 그대로 데이터를 표현하고,
    • 만약 2 Byte 이상이 필요하다면, 총 문자를 나타내는데 몇 Byte가 필요한지 힌트를 줌
  • c.f. Rob Pike, Ken Thompson(Go언어 창시자들)이 개발

UTF-16이라는 다른 방식도 있는데 이것도 가변길이이지만 기본적으로 2 Byte를 사용합니다.
그래서 1 Byte를 사용할 떄도 2 Byte를 사용하기에 통상적으로 UTF-8이 가장 보편적으로 사용되고 있습니다.


2. 변수 선언(Variable Declarations)

변수(Variables)값을 저장하는 공간을 의미합니다.

  • 컴퓨터적으로는 자료를 저장할 수 있는 이름이 주어진 기억장소
  • JS는 총 3가지 변수 생성 문법을 제공합니다.
    • var, let : 변수 선언
    • const : 상수 선언

1.1 var

  • 변수만드는걸 선언
  • 변수에 뭐 집어넣는걸 할당
  • 재선언 가능, 재할당 가능
// 1. 선언
var age;
var age; // 재선언 가능

// 2. 할당
age = 20;
age = 30; // 다른 값으로 재할당 가능

1.2 변수를 쓰는 이유

메모리는 각각의 메모리 셀마다 메모리 주소라는 것이 있습니다.
그런데 변수에 이름을 사용하지 않고, 메모리의 주소를 사용한다면 어떨까요?

JS-Basic-2-3

let 0x000006 = 0; // 무엇을 의미하는지 알 수 없다.

// 변수명(Variable Name) = 식별자(Idetifier)
let age = 0;

이것의 문제점은 너무 길고 메모리의 주소가 어떤 것을 의미하는지 알 수 없습니다.
그래서 변수를 사용해 프로그래머가 보기 쉽게 사용합니다.


1.3 let과 const

  • let과 const는 2015 ES6가 나오면서 등장한 변수 문법입니다.
  • 그래서 그 이전까지는 변수와 상수 구분없이 var키워드만을 사용했습니다.

3. var vs let

var와 let은 크게 3가지 관점에 다릅니다.

  • 스코프(Scope, 범위) : 코드가 변수에 접근할 수 있는 범위
  • 중복선언(Variable Redeclaration)
  • 호이스팅(Hoisting)

3.1 스코프(Scope, 범위)

스코프는 크게 3개로 구분합니다.

  • Function Scope(함수 범위)
    • 함수 내부에서만 변수에 접근이 가능
    • var키워드로 선언한 변수
  • Block Scope(블록 범위)
    • 블록 내부에서만 변수에 접근이 가능
    • let키워드로 선언한 변수
    • cf. 다른 대부분의 언어는 변수를 선언하게 되면, 블록 범위를 가집니다.
  • Global Scope(전역 범위) : 변수가 어느 곳에도 속하지 않은 최상위에 선언한 변수

3.1.1 Function Scope(함수 범위)

function main() {
  var x = 'hi';
}

// 함수 밖에 접근하면, ReferenceError: x is not defined
console.log(x);
function main() {
  if (true) {
    var x = 'hi';
  }
  console.log(x); // 그런데 블록 밖에서 호출했는데도 값에 접근이 가능하다?
  // 이것이 가능한 이유는 var 키워드로 선언한 변수는 자동으로 Function Scope를 갖습니다.
  // 즉, 함수 내부라면 어디서든지 접근이 가능합니다.
}

main(); // hi

3.1.2 Block Scope(블록 범위)

그러면 var 키워드를 let으로 바꿔보겠습니다.

function main() {
  if (true) {
    let x = 'hi';
  }
  console.log(x); // ReferenceError: x is not defined
  // let은 Block Scope이기 때문에 블록 내부에서만 접근이 가능합니다.
}

main();

다른 예를 들어보면,

function main() {
  let x = 'hello';
  if (true) {
    let x = 'hi';
    // let 블록범위이기 때문에 x는 블록 내부에서만 유효하다.
  }
  console.log(x); // hello
}

main();

for문 역시 블록이기 때문에 마찬가지입니다.

function main() {
  for (let i = 0; i < 2; i++) {
    console.log(i);
  }
  console.log(i); // ReferenceError: i is not defined
}

main();

3.1.3 Global Scope(전역 범위)

var aVar = 'varHello'; // var키워드로 선언한 변수는 window 전역 객체의 속성이 된다.
let aLet = 'letHello'; // let키워드는 window 전역객체에 등록되지 않는다.

// window 전역 객체는 브라우저의 정보를 갖고있는 유일한 객체입니다.
// window 객체는 코드, 모든 라이브러리들이 공유하므로,
// window 객체에 속성을 추가하는 것은 위험할 수 있습니다.
// 왜냐하면 여러 곳에서 접근을 할 수 있고 값을 변경할 수 있기 때문입니다.
// 그래서 var 키워드를 쓰는 것은 위험한 것입니다.
console.log(window);

3.2 중복 선언

var x = '안녕하세요';

// 코드 수천 줄이 있다고 가정
var x = '하이'; // 어떤 개발자가 변경, 값을 덮어씌워 버림, 코드를 헷갈리게 만듬

console.log(x); // 하이

var키워드는 같은 이름으로 중복 선언 가능합니다.

let x = '안녕하세요';

// 코드 수천 줄이 있다고 가정
let x = '하이'; // SyntaxError : x가 이미 선언됨

console.log(x); 

let키워드는 같은 이름으로 중복 선언 불가능합니다.

  • 에러가 나온다는 것은 좋은 것입니다.
    • 훨씬 더 안전하게 코딩 가능
  • 에러가 나오지 않은 채 오류가 발생하는 경우가 가장 무서운 경우임

3.3 호이스팅 (Hoisting, 끌어올리다)

  • 자바스크립트 엔진이 코드를 실행하기 전, 변수, 함수, 클래스의 선언문을 끌어 올리는 것
  • 다시 말해, 변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮김
  • 자바스크립트 엔진 = 번역기, Interpreter
console.log(num); // undefined

var num = 10;

console.log(num); // 10

아직 아무것도 할당되지 않은 변수에 접근하는 것은 의미없는 일입니다.

// 에러 : num을 초기화하기 전에 접근할 수 없다.
console.log(num); // ReferenceError : 'num' before initialization

let num = 10;

console.log(num);

// let으로 선언된 변수는 호이스팅되어서 선언문이 맨 위로 끌어올려지기는 하는데,
// 코드 상에 선언문에 접근하기 까지는
// num은 TDZ(Temporal Dead Zone; 일시적 사각지대)에 들어갑니다.
// JS는 TDZ에 들어가있는 변수에는 접근을 허용하지 않습니다.
// 이것 덕분에 변수 선언문 전에 접근하는 이상한 일을 막을 수 있습니다.

4. const

  • Block Scope
  • 중복 선언 불가
  • 선언문 이전 접근 불가
  • 상수 선언이라 한 번 값을 할당하면, 또 다시 할당 연산자로 값을 다시 할당하는 것은 불가능
    • 재할당 X
    • 선언만 할 수 없음
    • 선언 시 꼭 초기화를 해줘야 함
const price = 3000;
price = 4000;  // 에러 : 값의 재할당 불가능

const에 객체를 할당하면, 속성을 바꾸는 것은 가능합니다.

  • 이게 가능한 이유는, 새로운 객체를 할당하는 게 아니라
  • 내부적인 속성은 유지하면서 내부적인 속성을 바꾸는 것이라 가능한 것입니다.
const a = {
  x: 1,
  y: 2,
};

// 객체 속성을 바꾸는 것은 가능함
a.x = 3;
console.log(a); // Object { x: 3, y: 2 }

근데 객체의 속성을 변경하는 것도 막고 싶으면, (=객체의 불변성을 유지하고 싶으면) freeze()를 사용하면 됩니다.

const a = Object.freeze({
  x: 1,
  y: 2,
});

// Object.freeze()로 객체 속성을 바꾸는 것은 막을 수 있음
a.x = 3;
console.log(a); // Object { x: 1, y: 2 }

5. 변수 정리

종류재선언 여부재할당 여부
varFunction-scopedOO
let{Block-scoped}XO
const{Block-scoped}XX

결론 : var쓰지말고, let과 const만 쓰자.


6. Comment (주석)

주석은 코드 자체를 설명하는 것이 아니라, 왜(WHY)와 어떻게(HOW)를 설명하는것이 좋음

// 한 줄 주석 다는 법
/**
 * 여러 줄 주석 다는 법
 * 다음줄로 자동으로 넘어감
 */

6.1 JSDoc

// JS DOC은 함수 위에서 '/**'을 입력하면 자동완성됨
/**
 * 이름, 나이 입력하면 합쳐서 문자로 뱉어주는 함수
 * @param {string} name 문자 형태로 사람이름
 * @param {number} age 숫자 형태로 나이
 * @returns 두 개 합쳐서 문자로 뱉어줌
 * @version 1.3.0
 * @see https://naver.com
 * @readonly
 * @const {number}
 * @todo 내일까지 뺄셈 기능 추가
 * @deprecated 이제 이거 그만쓰고 다른거 쓰세요
 * @type {string | number}
 */
function sum(name, age) {
  return name + age;
}

// sum()에 마우스를 올려보면 JSDoc으로 적어둔 주석이 표시됨
sum('kim', 20);

7. Variable Nameing Rules(변수명 규칙)

변수의 이름을 지을 때는 저장된 값을 잘 나타낼 수 있는 의미있는 이름으로 짓기

  • 라틴문자(0-9, a-z, A-Z, ),
  • 대소문자를 구분함
  • 추천: camelCase (e.g. listThis)
  • 주석 등 설명할 떄 제외하고, 코드 작성할 때는 영어로
  • 예약어 ❌
  • 숫자로 시작 ❌
  • 특수문자 ❌ (_, $ 두가지는 예외)
  • 이모지 ❌
  • 여러 개의 변수를 1, 2, 3 숫자로 구분 ❌ → 최대한 의미있게, 구체적인 이름으로
// 1. 좋은 변수명 예시
let myAge = 20;

let backgroundAudio;
let windAudio;

// 2. 나쁜 변수명 예시
let number = 20;

let audio1;
let audio2;

7.1 명명 규칙(naming convention)

네이밍 컨벤션(naming convention)

  • 하나 이상의 영어 단어로 구성된 식별자를 만들 떄 가독성 좋게 단어를 한눈에 구분하기 위해 규정한 명명 규칙
  • 네이밍 컨벤션을 잘 지키면 읽기 좋은 이름을 만들 수 있음
  • 다음과 같은 4가지 유형의 네이밍 컨벤션이 자주 사용됨
    • 카멜 케이스 : 변수나 함수의 이름지을 때
    • 스네이크 케이스
    • 파스칼 케이스 : 생성자 함수, 클래스 이름지을 때
    • 헝가리언 케이스
// ⭐ 카멜 케이스 (camelCase) : 변수나 함수의 이름지을 때
var firstName;

// ❌ 스네이크 케이스 (snake_case)
var first_name;

// ⭐ 파스칼 케이스 (PascalCase) : 생성자 함수, 클래스 이름지을 때
var FirstName;

// ❌ 헝가리언 케이스 (typeHungarianCase)
var strFirstName; // type + identifier
var $elem = document.getElementById('myId'); // DOM 노드
var observable$ = fromEvent(document, 'click'); // RxJS 옵저버블

ECMAScript사양에 정의된 객체와 함수들도 카멜 케이스와 파스칼 케이스를 사용합니다.
코드 전체의 가독성을 높이려면 카멜 케이스파스칼 케이스를 따릅시다.

profile
Front-end 공부 중... 책 읽는 걸 좋아합니다.

0개의 댓글