간단한 연산(10+20)에서 컴퓨터의 동작
<조건>
1. 10, +, 20의 의미를 알아야 함(리터럴과 연산자)
2. 10+20이라는 식의 의미도 해석(파싱)할 수 있어야 함
<동작>
메모리를 사용하여 + 연산자의 좌변과 우변의 숫자를 기억한다.
→ CPU가 10+20을 연산한다.
→ 연산된 결과 값을 임의의 메모리 주소에 저장한다.
메모리
: 데이터를 저장할 수 있는 메모리 셀의 집합체
크기: 1byte
각 메모리 셀은 고유의 메모리 주소를 가진다.(0~메모리 크기만큼)
메모리에 저장된 값은 재사용할 수 없다.
왜? 메모리에 저장된 값을 재사용하고 싶다면 메모리 공간에 직접 접근해야 함.
그러나 이것은 치명적인 오류를 발생시킬 가능성이 매우 높음(실수로 운영체제 값 변경하면 시스템 오류 발생 가능)
& 값이 저장될 메모리 주소는 코드가 실행될 때 메모리의 상황에 따라 임의로 결정되므로 코드 실행 이전엔 값이 저장된 메모리 주소를 알 수 없음.
변수
: 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름
변수는 위의 상황에서 저장된 값을 읽어 들여 재사용하기 위한 것.
즉, 메모리를 간접적으로 참조하기 위해 붙인 상징적인 값
변수는 하나의 값을 저장하기 위한 메커니즘이나, 배열/객체와 같은 자료구조 사용시 관련 있는 여러 값을 그룹화하여 하나의 값처럼 사용 가능.
<용어>
할당: 변수에 값을 저장하는 것
참조: 변수에 저장된 값을 읽어 들이는 것
식별자
: 어떤 값을 구별하여 식별할 수 있는 고유한 이름
식별자는 메모리 공간에 저장되어 있는 어떤 값을 구별하기 위해 메모리 주소 기억
식별자라는 용어는 메모리 상에 존재하는 어떤 값을 식별할 수 있는 이름을 모두 칭함.
변수 선언(=변수 생성)
: 값을 저장하기 위한 메모리 공간 확보 후 변수 이름과 확보된 메모리 공간 주소 연결
확보된 메모리 공간은 확보가 해제되기 전까진 누구도 사용할 수 없도록 보호됨=안전
변수를 사용하려면 선언이 반드시 필요 ( var, let, const )
<!--let과 const는 var의 단점을 보완하기위해 도입되었으나 여러 이유로 인해 ES6에선 여전히 var을 쓸 수 있다.
따라서 ES6은 하위 호환성을 지니며 ES5 기반 위에 새 기능을 추가한 것과 같다.-->
변수는 선언되면 실행 컨텍스트에 key/value
형식인 객체로 등록 및 관리됨.
실행 컨텍스트 : js 엔진이 소스코드를 평가하고 실행하기 위해 필요한 환경 제공, 코드 실행 결과를 실제로 관리하는 영역
초기화 : 변수가 선언된 이후 최초로 값을 할당하는 것(초기화 x 시, 쓰레기 값이 남아있을 수 있음)
쓰레기 값 : 이전에 다른 애플리케이션이 사용하고 남아있던 값
변수 선언 시, 변수에는 암묵적으로 undefined
라는 값이 할당됨.
변수 선언의 실행 시점과 변수 호이스팅
변수 선언은 런타임이 아니라 소스 코드 평가 과정에서 먼저 실행
→ 이후에 선언문 제외하고 소스코드를 한 줄씩 순차적으로 실행
∴ 변수 선언 이전에 변수를 사용해도 동작됨.
//예시
console.log(score); //undefined
var score;
변수 호이스팅 : 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 js 고유의 특징
값의 할당
값을 할당할 때는 =
을 사용(좌변에 우변을 할당한다)
//[1]
var score;
score = 80;
//[2]
var score = 80;
[1]과 [2]는 완전히 같은데, [2]와 같이 작성하여도 [1]과 같이 변수 선언과 값의 할당을 나누어 각각 실행함.
선언은 실행 이전, 할당은 런타임에 실행됨.
변수에 값 할당 시, undefined이 저장되어 있던 메모리 공간을 지우고 80을 새로 저장하는 게 아니라 새로운 메모리 공간을 확보하여 거기에 80 저장.
값의 재할당
: 이미 값이 할당되어 있는 변수에 새로운 값을 다시 할당히는 것
할당과 마찬가지로 이전 값이 저장되어 있던 메모리 공간을 지우고 거기다 재할당하는 게 아니라 새로운 메모리 공간 확보 후 그 공간에 재할당.
이때 앞의 불필요한 값은 가비지 콜렉터에 의해 메모리에서 자동 해제
가비지 콜렉터 : 메모리 공간을 주기적으로 검사하여 더 이상 사용되지 않는 메모리 해제
unmanaged language vs managed language
unmanaged language: 메모리 제어를 개발자가 주도
managed language: 개발자가 명시적으로 메모리 할당 및 해제 불가
식별자 네이밍 규칙
1) 특수문자 에외한 문자, 숫자, _, $ 포함 가능
2) 단, 숫자로 시작 불가
3) 예약어는 식별자로 사용 불가
예약어 : 프로그래밍 언어에서 사용되고 있거나 사용될 예정인 단어
쉼표로 구분하여 여러 변수를 한 번에 선언 가능
식별자에 유니코드 허용(영어 외 언어 사용 가능)
대소문자 구분
존재 목적을 쉽게 이해하기 위해 의미를 명확히 하는 게 좋음
네이밍 컨벤션 : 하나 이상의 영단어로 구성된 식별자를 만들 때 가독성 좋게 단어를 한눈에 구분하기 위해 규정한 규칙
변수/함수 - 카멜 케이스(firstName), 생성자 함수/클래스 이름 - 파스칼 케이스(FirstName)
값
: 표현식이 평가되어 생성된 결과
변수 = 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름
∴ 변수에 할당되는 것은 값
var sum = 1+2;
위에서 sum이 기억하는 메모리 공간에 저장되는 것은 1+2가 아닌 3
∴ 1+2는 할당 전에 평가되어 값을 생성해야 함.
리터럴
: 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법
js 엔진은 런타임에 리터럴을 평가해 값 생성
표현식
:값으로 평가될 수 있는 문
표현식이 평가되면 새로운 값을 생성하거나 기존 값 참조
값으로 평가될 수 있는 문은 모두 표현식
표현식과 표현식이 평가된 값은 동치
∴ 값이 위치할 수 있는 자리에 표현식도 위치할 수 있음.
문(=명령문)
: 프로그램을 구성하는 기본 단위이자 최소 실행 단위
토큰 : 문법적 의미를 지니며 문법적으로 더 이상 나눌 수 없는 코드의 기본 요소(≒국어의 형태소)
var sum = 1+2; //전체는 문, var/sum/=/1/+/2/;은 토큰
세미콜론
0개 이상의 문을 중괄호로 묶은 코드 블록엔 세미콜론 X (자체 종결성)
문의 끝에 붙는 세미콜론은 생략 가능함(세미콜론 자동 삽입 기능이 있어서)
그러나 가끔 개발자의 예측이 맞지 않는 경우가 있어서 사용을 권장하는 편
표현식인 문과 표현식이 아닌 문
변수에 할당 가능하면 표현식, 불가능하면 표현식 X
var tmp = var x; //불가
var tmp = 300; //가능
var x = 300; //할당문은 그 자체로 표현식
var tmp = x = 300; //가능
위에서 할당문은 할당한 값으로 평가됨
∴ x=300
은 할당한 값 300
으로 평가됨 → tmp엔 300 할당
표현식이 아닌 문 실행 시
undefined
출력 = 완료 값
완료값은 평가 결과가 아니므로 변수에 할당하거나 참조할 수 없음.
구분 | 데이터 타입 | 설명 |
---|---|---|
숫자 타입 | 숫자. 정수/실수 구분 X | |
문자열 타입 | 문자열 | |
원시 | 불리언 타입 | 논리적 참/거짓 |
타입 | undefined 타입 | var로 선언된 변수에 암묵적으로 할당되는 값 |
null 타입 | 값이 없다는 것을 의도적으로 명시할 때 사용하는 값 | |
심벌 타입 | ||
---------- | ----------------- | --------------------------------------------------------- |
객체 타입 | 객체, 함수, 배열 등 |
숫자 타입
모든 수를 실수로 처리(정수처럼 보여도 사실은 실수임)
Infinity/-Infinity/NaN(산술 연산 불가)도 존재
문자열 타입
''
, ""
, 백틱
으로 텍스트를 감쌈.
js에서 문자열은 원시 타입 → 문자열이 생성되면 그 문자열을 변경할 수 없음
템플릿 리터럴
편리한 문자열 처리 기능 제공
런타임에 일반 문자열로 변환되어 처리됨
백틱 사용해 표현
멀티라인 문자열
일반 문자열에서는 개행 허용 X → escape sequence(\로 시작하는)
사용 필요
LF와 CR
LF: Line Feed, 커서를 정지한 상태에서 종이를 내리는 것
CR: Carriae Return, 종이를 움직이지 않고 커서를 맨 앞으로 이동하는 것
∴ CRLF: 맨 앞으로 커서 이동 후 종이 내리기 (=우리가 아는 줄바꿈)
템플릿 리터럴 내에서는 escape sequence 없이 줄바꿈 허용, 공백 적용 O
표현식 삽입
${}
으로 표현식을 감싸 삽입
평가 결과가 문자열이 아니더라도 문자열로 타입 강제 변환 후 삽입
일반 문자열에서 삽입하면 문자열 취급함.
undefined 타입
var로 선언한 변수를 undefined로 초기화
∴ undefined 반환 = 초기화되지 않은 변수
변수에 값이 없다는 걸 명시하고 싶으면 null
할당
null 타입
: 변수에 값이 없다는 걸 의도적으로 명시할 때
변수에 null 할당 = 이전에 참조하던 값을 더 이상 참조하지 않겠다.
(이전에 할당되어 있던 값에 대한 참조를 명시적으로 제거)
심벌 타입
: 변경 불가능한 원시 타입의 값
객체의 유일한 프로퍼티 키를 만들기 위해 사용
외부 노출 및 중복 X
//예시
var key = Symbol('key');
var obj = {};
obj[key] = 'value';
console.log(obj[key]); // value
객체 타입
js를 이루고 있는 거의 모든 것
데이터 타입의 필요성
1) 값을 저장할 때 확보해야 하는 메모리 공간의 크기를 결정하기 위해
2) 값을 참조할 때 한 번에 읽어 들여야 할 메모리 공간의 크기를 결정하기 위해
3) 메모리에서 읽어들인 2진수를 어떻게 해석할지 결정하기 위해
동적 타이핑
정적 타입 언어: 변수를 선언할 때 변수에 할당할 수 있는 값의 종류(데이터 타입)를 사전에 선언(=명시적 타입 선언)
➖ 변수 타입 변경 불가
➖ 변수에 선언한 타입에 맞는 값만 할당 가능
➖ 컴파일 시점에 타입 체크 → 타입 일관성 강제 → 에러↓
동적 타이핑 : 선언이 아닌 할당에 의해 타입 결정 / 재할당에 의해 언제든 동적으로 변수 타입 변경
아무튼 기본적으로 변수는 타입을 갖지 않음
동적 타입 언어는 유연성은 높으나 신뢰성은 떨어짐
➖ 복잡한 프로그램에서는 변화하는 변수 값 추적이 어려움
➖ 값을 확인하기 전에 타입 확신 불가
➖ 개발자의 의도와 상관 없이 js 엔진에 의해 강제 타입 변환되기도 함
<변수 사용 시 주의 사항>
1) 변수는 꼭 필요한 경우에 한해 제한적으로 사용
2) 변수의 스코프는 최대한 좁게 만들어 변수의 부작용 억제
3) 전역 변수는 최대한 사용하지 않도록 함
4) 변수보다는 상수를 사용 → 값의 변경 억제
5) 변수 이름은 변수의 목적이나 의미를 파악할 수 있도록 네이밍