[JS-책 편김에 끝까지] 변수

짱쫑·2023년 2월 6일
0

javascript

목록 보기
2/10
post-thumbnail

메모리 Memory

변수를 이해하기 전에 먼저 메모리에 대해서 이해할 필요가 있다.
메모리는 데이터를 저장할 수 있는 메모리 셀(Memory cell)의 집합체이다.
셀(Cell)은 컴퓨터 메모리의 가장 작은 저장 단위를 말하는데 0 또는 1일 수 있는 단일 비트의 정보를 저장하는 기본 요소이다. 메모리 셀은 워드, 캐시 라인 및 페이지와 같은 더 큰 메모리 단위로 구성된다(101동이라는 아파트가 메모리, 101호는 셀).

변수 Variable

변수란 값을 저장하는 공간이자 자료를 저장할 수 있는 이름이 주어진 기억장소이다.
Javascript에서 변수는 var, let, const 키워드와 변수의 이름으로 선언할 수 있다.

키워드는 자바스크립트 코드를 해석하고 실행하는 자바스크립트 엔진이 수행할 동작을 규정한 일종의 명령어다. 자바스크립트 엔진은 키워드를 만나면 자신이 수행해야 할 약속된 동작을 수행하는데 예를들어 var 키워드를 만나면 자바스크립트 엔진은 뒤에 오는 변수 이름으로 새로운 변수를 선언한다.

let a = 0; 이라고 변수를 선언해보면

let = 키워드
a = 변수 이름 //변수 이름을 식별자(identifier)라고도 한다
= = 할당연산자
0 = 할당값
; = 선언문의 끝

let a = 0; : 변수 선언과 값의 할당

메모리 셀에 0이라는 데이터가 저장되고, 그 셀의 주소를 a가 가리키게 된다(변수이름을 메모리 주소로 쓰면 일단 엄청 길고, 어떤 데이터를 담고 있는지 유추하기도 상당히 힘들어진다. 때문에 변수이름을 잘 지으라고 하는것도 이러한 이유가 있기 때문이다).

  • 변수의 재할당
let a = 0; //변수의 선언과 값의 할당
a = 1; //재할당
let b; //변수의 선언
b = 2; //값의 할당

101호(a)라는 셀에 0이 들어가 있지만 다시 101호를 찾아내서 1을 할당한다(세입자가 바뀜).
102호(b)라는 세입자가 없는 빈 집이 있는데, 102호를 찾아서 2를 할당한다.

변수의 선언은 코드가 순차적으로 읽히는 런타임 이전 시점에 실행되지만 값의 할당은 런타임에 실행된다.

변수이름 (식별자) 네이밍 규칙

식별자는 어떤 값을 구별해서 식별해낼 수 있는 고유한 이름을 말하는데 식별자에도 규칙이 존재한다.

  • 식별자는 특수문자를 제외한 문자, 숫자, 언더스코어(_), $기호를 포함할 수 있다.
  • 식별자는 특수문자를 제외한 문자, 언더스코어, 달러기호로 시작해야 한다. 숫자로 시작하는 것은 허용하지 않는다.
  • 예약어는 식별자로 사용하지 않는다.

❗️ 예약어 (*는 식별자로 사용 가능하지만 strict mode(엄격모드)에서는 사용 불가)

await break case catch class cosnt
continue debugger default delete do else
enum export extends false finally for
function if implements * import in instanceof
interface * let * new null package * private *
protected * public * return super static * switch
this throw true try typeof var
void while with yield *

참조

ES5부터 식별자를 만들 때 유니코드 문자를 허용하므로 알파벳 외의 한글,한자,일본어 등의 식별자도 사용할 수 있지만 권장하지는 않는다.
또한 자바스크립트는 대소문자를 구별하므로 var apple;과 var Apple;은 별개의 변수이다.

네이밍컨벤션(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 옵저버블

4가지가 많이 쓰인다고는 하지만 주로 카멜케이스와 파스칼케이스를 사용한다.
또한, 이모티콘 사용과 여러 개의 변수를 의미없이 (예를들어 a,b,c / 1,2,3) 구분하는 것을 지양하는 것이 좋다. 최대한 의미있고 구체적으로 이름을 짓는 것이 좋다.

데이터 타입 Datatype

변수에는 다양한 타입의 데이터를 담을 수 있다.
자바스크립트에서는 데이터 타입을 두 가지로 나눌 수 있다.
바로 원시(primitive)타입과 객체(object)타입이다.

원시타입은 딱 하나의 단일한 데이터를 담을 수 있고, 객체타입은 복합 데이터를 담을 수 있다.

- 원시타입 primitive type

원시타입에는 number, string, boolean, null, undefined, Symbol

  • number
    C나 자바의 경우 정수와 실수를 구분하기 위해 int, long, float, double 등과 같이 다양한 숫자 타입을 제공하지만 자바스크립트에서는 하나의 숫자 타입만 제공한다.
    모든 수를 실수로 처리하며(이는 정수로 표시된다 해도 사실을 실수라는 것을 의미함 즉, 정수로 표시되는 수끼리 나누더라도 실수가 나올 수 있다.), 정수만을 표현하기 위한 데이터 타입이 별도로 존재하지 않는다.

    let integer = 123; //정수
    let negative = -123; //음수
    let double = 1.23; //실수
    
    let binary = 0b0100001; //2진수
    let octal = 0o101; //8진수
    let hex = 0x41; //16진수
    
    console.log(0 / 123); //0
    console.log(123 / 0); //Infinity 양의 무한대
    console.log(123 / -0); //-Infinity 음의 무한대
    console.log(123 / 'text'); //Nan (Not a Number) 산술 연산 불가
    
    //빅인트 bigInt
    let bigInt = 1234567890123456789012334567890n; //빅인트는 n을 붙여야함 
  • string
    문자열 타입은 텍스트 데이터를 나타내는 데 사용하며 0개 이상의 16비트 유니코드 문자의 집합으로 전 세계 대부분의 문자를 표현할 수 있다.
    문자열은 홑따옴표, 겹따옴표, 백틱을 사용한다.

let string = '하잉'; //홑따옴표
let string = "하잉"; //겹따옴표
let string = `하잉`; //백틱(꺽새)
let string = '홑따옴표로 감싼 문자열 내의 "겹따옴표"는 문자열로 인식된다';
let string = "겹따옴표로 감싼 문자열 내의 '홑따옴표'는 문자열로 인식된다";
	- 템플릿 리터럴
    	백틱키를 이용하는 것을 템플릿 리터럴이라고 한다. 
        
         ```
         let first = "zzang";
         let last = "zzong";

         //표현식 삽입
         console.log('My name is ' + first + ' ' + last + '.');
         //My name is zzang zzong

         //템플릿 리터럴
         console.log(`My name is ${first} ${last}.`); 
         // My name is zzang zzong;
         // 템플릿 리터럴은 변수, 혹은 계산식도 추가할 수 있고 띄어쓰기도 가능하다
      	```

	- 이스케이프 시퀀스
    
        |이스케이프 시퀀스|의미|
        |---|---|
        |\0|Null|
        |\b|백스페이스|
        |\f|폼 피드. 프린터로 출력할 경우 다음 페이지의 시작 지점으로 이동|
        |\n|개행 Line Feed. 다음 행으로 이동|
        |\r|개행 Carriage Return. 커서를 처음으로 이동|
        |\t|탭(수평)|
        |\v|탭(수직)|
        |\uXXXX|유니코드|
        |\'|홑따옴표|
        |\"|겹따옴표|
        |\\|백슬래시|
      
        * [LF, CR의 차이](https://ko.wikipedia.org/wiki/%EC%83%88%EC%A4%84_%EB%AC%B8%EC%9E%90)


- boolean

불리언 타입의 값은 논리적 참, 거짓을 나타내는 true, false 뿐이다.

	let trueValue = true; // true
 let falseValue = false; //false
 
 ex)
 let isFree = true;
 let isActivated = false;
 let isEntrolled = true;
 console.log(isActivated); // false
 
 //Falshy값
 console.log(!!0); //false
 console.log(!!-0); //false
 console.log(!!''); //false
 console.log(!!null); //false
 console.log(!!undefined); //false
 console.log(!!NaN); //false
 
 //Truthy값
 console.log(!!1); //true
 console.log(!!-1); //true
 console.log(!!'text'); //true
 console.log(!!{}); //true
 console.log(!!Infinity); //true
 
 * !!은 값을 trues나 false로 변환시켜줌
	```
- undefined
	undefined 타입의 값은 undefined가 유일하다.
 ```
 let variable;
 console.log(variable); //undefined
 ```
 undefined는 직역하면 '정의되지 않은'인데 자바스크립트에서 정의란 변수에 값을 할당하여 변수의 실체를 명확히 하는 것을 말한다.
 
 
- null
	null 타입의 값은 null이 유일하다. 자바스크립트는 대소문자도 구분하기 때문에 NULL, Null은 다르다.
 프로그래밍 언어에서 null은 변수에 값이 없다는 것을 의도적으로 명시할 때 사용한다. **변수에 null을 할당하는 것은 변수가 이전에 참조하던 값을 더 이상 참조하지 않겠다는 의미**다. 
 ```
	let variable = 0;
 console.log(variable); //0 
 
 variable = null;
 console.log(variable); //null
	```

- Symbol 
	Symbol타입은 변경 불가능한 원시타입의 값이다. 다른 값과 중복되지 않는 유일무이한 값이다. 즉, 주로 이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티 키를 만들기 위해 사용한다. 
	```
	class Counter {
 	count = 0;
     
     add() {
     	this.count += 1;
         return this;
     }
     
     get() { return this.count; }
 }
 
 class BetterCounter extends Counter {
 	count = function() { ... }; // conflict
자바스크립트 객체 내부 필드는 기본적으로 전체 공개이다(public). 즉, 누구나 코드를 덮어 씌울 수 있다는 의미다. Symbol 대신에 count라는 문자열 키값을 사용했다. 이를 라이브러리로 배포했다면 다른 프로그래머가 Count라이브러리를 써서 상속으로 통해 사용했다 가정하면 자연스럽게 count라는 변수를 선언해서 코드를 작성했다면 로직상의 문제가 없지만 제대로 작동을 하지 않을 것이다. 그 이유는 원래 Count 클래스에 있던 숫자값 count가 사라졌기 때문이다. 덮어씌운 것이다. 이를 복잡한 로직이 있는 라이브러리라면 얘기는 달라진다. 이처럼 Symbol은 다른 언어에서의 private이나 enum과 비슷하다. 

- 객체타입 object type

객체타입에는 object(array), function

- 객체 
	객체는 여러가지 상태와 행동(함수)을 묶어서 표현할 수 있는 '복합 데이터'라고 볼 수 있다. 이 복합 데이터는 { key: value }로 표현할 수 있는데 value안에서 또 원시데이터와 객체를 담을 수 있다. 
    
    앞서 말했지만 원시타입은 변수에 값을 할당하면 메모리 셀에 값 자체가 들어가고 변수는 메모리 셀의 주소를 가리키게 된다. 원시타입은 어디에 선언되었냐에 따라 data나 stack에 저장된다. 그러나 객체는 이와 조금 다르다.
    객체는 key와 value형태로 여러개가 엮이다보니 사이즈가 정해져 있지 않다. 즉, 메모리 셀안에 한번에 들어갈수가 없다. 그렇다보니 객체는 Heap에 할당이 되는데, Heap은 데이터의 사이즈가 정해져있지않고, 동적으로 사이즈가 늘었다 줄었다 하는 데이터들이 들어갈 수 있는 장소다.  
    객체를 선언하고 할당하면 객체는 힙 어딘가에 저장되고, 메모리셀 하나 안에 커다란 객체가 들어갈 수 없기 때문에 여러 개의 셀에 할당이 된다. 변수의 이름은 메모리 셀을 가리키는데, 그 메모리 셀 안에는 실제 객체가 들어가 있는 메모리 셀의 주소를 가리킨다(짱쫑이라는 객체를 선언하면 0x000A, 0x000B, 0x000C 의 여러개의 메모리 셀에 객체의 key, value가 저장되고 짱쫑이라는 객체 이름은 0x00003이라는 메모리 셀 주소를 가리키고 0x00003안에는 실제 객체가 담겨있는 첫 주소 0x000A가 담긴다). 그래서 짱쫑이라는 객체안에 담긴 값에 접근하게 되면 그 과정은 짱쫑이라는 객체가 가리키는 주소를 찾아서 그 안에 담긴 데이터 그러니까 실제 데이터가 담긴 주소를 찾아서 원하는 값을 찾는 것이다. 
    

let const 키워드

// let 재할당 가능
let a = 1;
a = 2;

// const 재할당 불가능
// 상수 혹은 상수변수

const text = 'hello';
//text = 'hi'; // TypeError: Assignment to constant variable

// 상수
const MAX_NUMBER = 5;

// 재할당 불가능한 상수변수 혹은 변수
const zzangzzong = {
	gender: 'male',
    position: 'front',
    emoji: '🥺',
};

console.log(zzangzzong); //{gender: 'male', position: 'front', emoji: '🥺'}

// but!
zzangzzong.gender = 'female';
zznagzzong.position = 'back';

console.log(zzangzzong); //{ gender: 'female', position: 'back', emoji: '🥺'}

zzangzzong이라는 변수 자체에 다른 오브젝트로 할당은 되지 않지만 결국 zzangzzong이라는 변수는 메모리 주소로 할당되어 있기 때문에 객체에 직접 접근해서 변수의 내용은 변경이 가능하다.

객체는 Heap에 저장되어 있고 변수는 그냥 Heap의 메모리 셀의 주소가 담겨있는 메모리 주소를 가리키고 있기 때문이다. 즉, zzangzzong이 가리키고 있는 메모리 셀 안의 데이터는 변경이 불가능하지만 Heap에 담겨있는 데이터는 변경이 가능하다.

profile
不怕慢, 只怕站

0개의 댓글