오늘 한 것
개념 및 용어 정리
변수
- 만약 숫자 ‘10’을 메모리에 저장한다면 숫자 ‘10’에 접근할 때마다 복잡한 메모리 주소를 찾아 직접 접근해야한다. 하지만 메모리 주소에 직접 접근하는 것은 매우 위험하다. 잘 못 접근하게 되면 미지의 메모리를 변경할 수도 있기 때문이다.
- 위와 같은 이유로 프로그래밍 언어는 값을 메모리에 저장하고, 저장된 값을 읽어 들여 재사용하기 위해 변수라는 메커니즘을 제공한다.
- 변수는 값의 위치를 나타내는 상징적인 이름이며 식별자라고도 부른다.
1 | // 변수는 하나의 값을 저장하기 위한 수단이다. |
- 변수에 값을 저장하는 것을 할당(assignment), 변수에 저장된 값을 읽어 들이는 것을 참조(reference)라 한다.
- 안에 담긴 값의 의미를 반영하여 지은 변수 이름은 저장된 값의 의미를 명확히 할 수 있어 가독성을 높여준다.
- 코드는 컴퓨터에게 내리는 명령이면서 동시에 개발자를 위한 문서이기도 하다. 명확한 네이밍은 코드를 이해하기 쉽게 만들며 타인이 내 코드를 쉽게 해석할 수 있게 돕는다.
변수 선언
- 변수를 사용하려면 반드시 선언이 필요하다. 변수를 선언할 때는 var, let, const 키워드를 사용한다.
1 | var score; // 변수 선언 |
- 위와 같이 변수를 선언한 후 출력하면
undefined
값이 출력된다. 이는 현재 변수 안에 메모리 공간은 확보됐지만 어떤 값도 할당하지 않은 것이다. - 자바스크립트에서 변수를 선언하면 다음의 절차를 거친다
- 선언 단계 : 변수 이름을 등록해서 자바스크립트 엔진에 변수의 존재를 알린다.
- 초기화 단계 : 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화한다.
- 자바스크립트에서는 초기화 값으로 정의되지 않았다는 뜻인 undefined를 할당한다. 이것도 할당이라면 할당이지만 의도하지 않았다면 제대로된 값을 할당한 행위는 아니다.
호이스팅
1 | console.log(score); // undefined |
- 자바스크립트는 인터프리터 언어인 것을 저번에 설명하였다. 그렇다면
console.log(score)
구문을 실행하면var score
가 실행되기 전이기 때문에 변수 참조 에러(ReferenceError)가 발생해야하지만undefined
값이 출력됐다. - 그 이유는 변수 선언이 소스코드가 한 줄씩 순차적으로 실행되는 런타임(runtime)이 아니라 이전 단계에서 먼저 실행되기 때문이다.
- 자바스크립트 엔진은 런 타임에 진입하기 전 준비과정으로 모든 선언문(변수,함수 선언문 등)을 찾아 먼저 실행한다. 그렇기 때문에
var
로 선언된 변수인score
가 먼저 실행되어 위의 현상이 나타나는 것이다. - 이처럼 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 변수 호이스팅(variable hoisting)이라 한다.
- var, let, const, function, function*, class 키워드를 사용해서 선언하는 모든 식별자(변수, 함수, 클래스 등)는 호이스팅된다.
값 할당
1 | var score = 80; // 변수 선언과 값의 할당 |
- 변수 선언은 소스코드가 순차적으로 실행되는 시점인 런타임 이전에 먼저 실행되지만 값의 할당은 소스코드가 순차적으로 실행되는 시점인 런타임에 실행된다. 아래 코드를 보자.
1 | console.log(score); // undefined |
- 참고로 변수에 값을 할당할 때는 이전 값 undefined가 저장되어 있던 메모리 공간을 지우고 그 메모리 공간에 할당 값 80을 새롭게 저장하는 것이 아니라 새로운 메모리 공간을 확보하고 그 곳에 할당 값을 저장한다.(즉, 메모리 주소가 동일하지 않다.)
- 그 이유는 undefined값도 할당이라면 할당이라고 위에서 말했는데 변수에 값을 제대로 할당할 경우(사실은 처음이 아닌 ‘재할당’이다.) 새로운 메모리 공간을 확보하고 그 메모리 공간에 새로운 값을 저장하기 때문이다.
- 그렇다면 전에 값이 저장된 메모리 공간이 불필요하게 존재한다고 걱정할 수 있는데 이는 가비지 콜렉터라는 기능에 의해 자동 삭제된다. 단, 언제 삭제될지는 모른다.
변수 네이밍 규칙
- 식별자는 특수문자를 제외한 문자, 숫자, 언더스코어(_), 달러 기호($)를 포함할 수 있다.
- 단, 식별자는 특수문자를 제외한 문자, 언더스코어(_), 달러 기호($)로 시작해야 한다. 숫자로 시작하는 것은 허용하지 않는다.
- 예약어는 식별자로 사용할 수 없다.(예약어는 프로그래밍 언어에서 사용되고 있거나 사용될 예정인 단어를 말한다.)
- 영어 이외의 문자로도 명명할 수 있지만 권장하지 않는다.
- 자바스크립트는 대소문자를 구별한다.
- 주석이 필요없어도 의미를 알 수 있는 이름으로 짓자.
- 네이밍 컨벤션을 활용하자.
1 | // 카멜 케이스 (camelCase) |
리터럴
- 리터럴(literal)은 약속된 ‘기호를 사용해 값을 생성’하는 표기 방식(notaion)을 말한다.
- 이해할 수 있는 문자(아라비아 숫자, 알파벳, 한글 등) 또는 미리 약속된 기호(‘’, “”, ., [], {}, // 등)로 표기한 코드다.
1 | // 정수 리터럴 |
표현식
- 표현식(expression)은 값으로 평가될 수 있는 문(statement)이다. 즉, 표현식이 평가되면 새로운 값을 생성하거나 기존 값을 참조한다.
- 때문에 리터럴도 표현식이다.
1 | // 50 + 50은 리터럴과 연산자로 이뤄져 있다. 하지만 50 + 50도 평가되어 숫자 값 100을 생성하므로 표현식이다. |
문
문(statement)은 프로그램을 구성하는 기본 단위이자 최소 실행 단위이다. 문의 집합으로 이뤄진 것이 프로그램이며, 문을 작성하고 순서에 맞게 나열하는 것이 프로그래밍이다.
문은 여러 토큰으로 구성된다. 토큰(token)이란 문법적인 의미를 가지며, 더 이상 나눌 수 없는 코드의 기본 요소다. 예를 들어, 키워드, 식별자, 연산자, 리터럴, 세미콜론(;)이나 마침표(.) 등의 특수 기호는 문법적인 의미를 가지며, 문법적으로 더 이상 나눌 수 없는 코드의 기본 요소이므로 모두 토큰이다.
표현식은 문의 일부일 수도 있고 그 자체로 문이 될 수도 있다.
1 | // 변수 선언문은 값으로 평가될 수 없으므로 표현식이 아니다. |
- 표현식인 문과 표현식이 아닌 문을 구별하는 가장 간단하고 명료한 방법은 변수에 할당해 보는 것이다. 표현식인 문은 값으로 평가되므로 변수에 할당할 수 있다.
데이터 타입
자바스크립트(ES6)는 7개의 데이터 타입을 제공한다.
원시 타입(primitive type)
- 숫자(number) 타입: 숫자. 정수와 실수 구분 없이 하나의 숫자 타입만 존재
- 문자열(string) 타입: 문자열
- 불리언(boolean) 타입: 논리적 참(true)과 거짓(false)
- undefined 타입: var 키워드로 선언된 변수에 암묵적으로 할당되는 값
- null 타입: 값이 없다는 것을 의도적으로 명시할 때 사용하는 값
심벌(symbol) 타입: ES6에서 추가된 7번째 타입
- 객체 타입 (object/reference type): 객체, 함수, 배열 등
숫자 타입
- 자바스크립트는 하나의 숫자 타입만 존재한다.
- ECMAScript 사양에 따르면 숫자 타입의 값은 모든 수를 실수로 처리하며, 정수만 표현하기 위한 데이터 타입(integer type)이 별도로 존재하지 않는다.
1 | // 숫자 타입은 모두 실수로 처리된다. |
- 2진수, 8진수, 16진수는 아래와 같이 표기한다.
1 | var binary = 0b01000001; // 2진수 |
- 숫자 타입은 추가적으로 특별한 값들도 표현할 수 있다.
1 | // 숫자 타입의 세 가지 특별한 값 |
문자열
- 자바스크립트의 문자열은 원시 타입이며, 변경 불가능한 값(immutable value)이다. 때문에 문자열이 생성되면 그 문자열을 변경할 수 없다. C나 Java와는 문자열 타입이 다르다.
- 자바스크립트에서 일반적인 표기법은 작은따옴표를 사용한다. 하지만 작은따옴표(‘’), 큰따옴표(“”), 백틱(``)으로도 가능하다.
- 따옴표로 감싸지 않으면 키워드나 식별자로 인식한다.
1 | // 문자열 타입 |
템플릿 리터럴
템플릿 리터럴은 아래와 같이 문자열 처리 기능을 제공한다.
- 멀티라인 문자열(multi-line string)
- 표현식 삽입(expression interpolation)
- 태그드 템플릿(tagged template)
템플릿 리터럴은 백틱(``)으로 표현한다.
멀티라인 문자열
- 템플릿 리터럴 내에서는 이스케이프 시퀀스를 사용하지 않고도 줄바꿈이 허용되며, 모든 공백도 있는 그대로 적용된다.
1
2
3
4
5
6
7
8
9
10var template = `<ul>
<li><a href="#">Home</a></li>
</ul>`;
console.log(template);
/*
<ul>
<li><a href="#">Home</a></li>
</ul>
*/표현식 삽입
- 간단히 문자열을 삽입할 수 있다. 이를 통해 문자열 연산자보다 가독성 좋고 간편하게 문자열을 조합할 수 있다.
1
2
3
4
5
6
7
8var first = "Ung-mo";
var last = "Lee";
// ES6: 표현식 삽입
console.log(`My name is ${first} ${last}.`); // My name is Ung-mo Lee.
// 템플릿 리터럴이 아닌 일반 문자열에서의 표현식 삽입은 문자열로 취급된다.
console.log("1 + 2 = ${1 + 2}"); // 1 + 2 = ${1 + 2}
undefined
- undefined 타입의 값은 undefined가 유일하다.
- var 키워드로 선언한 변수는 undefined로 초기화된다.
1 | var foo; |
- 자바스크립트 엔진이 변수를 초기화할 때 쓰는 undefined를 개발자가 의도적으로 변수에 할당하는 것은 취지와 어긋나기 때문에 권장하지 않는다.
- 변수에 값이 없다는 것을 명시하고 싶은 때는 undefined를 할당하는 것이 아니라 null을 할당한다.
null
- null 타입의 값은 null이 유일하다. (대소문자 구별)
- null은 변수에 값이 없다는 것을 의도적으로 명시할 때 사용하며 변수 값에 대한 참조를 제거한다.
symbol
- 변경 불가능한 원시 타입의 값이다. 심벌 값은 절대 다른 값과 중복되지 않다.
- 주로 이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티 키를 만들기 위해 사용한다.
1 | // 심벌 값 생성 |
동적 타입 언어 / 정적 타입 언어
C나 Java의 경우 정적 타입(static/strong type) 언어이다. 변수를 선언할 때 데이터 타입을 명확하게 선언해야 한다.
정적 타입 언어는 변수의 타입을 변경할 수 없고 선언한 타입에 맞는 값만 할당할 수 있다. 정적 타입 언어는 컴파일 시점에 타입 체크를 수행한다.
자바스크립트는 동적 타입 언어로서 변수 타입을 선언하지 않고 var, let, const 키워드를 사용한다.
자바스크립트의 변수는 데이터 타입의 값이라도 자유롭게 할당할 수 있다.
자바스크립트 변수는 할당에 의해 타입이 결정된다. 또한 다른 타입 값을 재할당해 동적으로 타입을 바꿀 수 있다.
1 | var foo; |
변수의 타입이 동적으로 변하기 때문에 동적 타입 언어의 변수는 값의 변경에 의해 타입도 언제든지 변경될 수 있다. 따라서 변수 값을 확인하기 전에는 타입을 확신할 수 없다.
자바스크립트 엔진에 의해 암묵적으로 타입이 자동으로 변환되는 경우도 있기 때문에 동적 타입 언어는 유연성(flexibility)은 높지만 신뢰성(reliability)은 떨어진다.
이러한 동적 언어의 특징으로 아래와 같이 변수를 사용하길 권장한다.
- 변수는 꼭 필요한 경우에 한해 제한적으로 사용한다. 필요한 만큼 최소한으로 유지해야한다.
- 변수의 유효 범위(스코프)는 가능한 좁게 만들어 변수의 부작용을 억제해야 한다.
- 전역 변수는 최대한 사용하지 않도록 한다.
- 변수보다는 상수를 사용해 값의 변경을 억제한다.
- 변수 이름은 변수의 목적이나 의미를 파악할 수 있도록 네이밍한다.
오늘 느낀 것
- 용어 정리를 하면서 새롭게 배우는 것이 생각보다 많다. 사상누각되지 말자. 복습부터 새로 배우는 모든 것이 내 기본기가 된다.