티스토리 뷰
이 포스팅은 사실 [javascript] var가 let보다 빠르다...? 포스팅을 쓰던 중에,
부가설명이 필요해서 var과 let, const에 대한 내용을 별첨으로 정리하던 내용인데...
이게 또 쓰다보니 제법 길어져서 별도 포스팅으로 발행하게 되었습니다.
0. javascript에서 변수를 선언하기
아이들이 마음껏 뛰어놀 수 있는 놀이터처럼,
컴퓨터로 동작하는 모든 시스템은 메모리라는 놀이터에서 뛰어놀게 된다.
이 놀이터에서 뛰어놀기 위한 값들은 메모리의 한 켠에 적재되고,
적재된 값을 가리키는 변수 혹은 상수를 활용해서 개발자들은 시스템을 구축하게 된다.
Javascript도 당연히 변수를 정의하는 키워드가 존재한다.
ES6(2015)가 공시된 2015년 이전에는 var이라는 하나의 키워드만 존재했지만,
이때를 기점으로 변수를 정의하는 let과 상수를 정의하는 const라는 키워드가 추가되게 되었다.
변수/상수를 선언하는 방법은 여타 프로그래밍 언어와 크게 다르지않다.
아래와 같은 형식으로 이름을 짓고 그에 맞는 값을 할당하기만 하면된다.
let let_value = "let!";
var var_value = "var!";
const const_value = "const!";
사실 여기까지만해도, 이 3가지 키워드는 크게 차이가 없어보인다.
그냥 변수명 앞에 쓰여서 얘가 변수에요! 라고 선언해주는 역할이니까.
1. var
1-1. 굳이 쓰지않는다면 너는 var이어라
변수를 선언할 때, 굳이 var이나 let, const와 같은 키워드를 쓰지않아도 변수로써 정의된다.
이때 해당 변수는 var로 취급됨과 동시에 전역변수로써 등록된다.
function test(){
num = 10;
console.log('num >> ', num); // 10
}
위와같은 코드는 정상적으로 콘솔로그에 10이라는 값을 출력해준다.
1-2. 동명이인도 OK
여타 프로그래밍언어는 동일한 변수명에 대해 선언이 불가능하지만, javascript는 가능하다.
function same_name(){
var num = 10;
console.log('num >> ', num); // 10
var num = 20;
console.log('num >> ', num); // 20
var num = 30;
console.log('num >> ', num); // 30
}
바로 위와같은 형태인데, num이라는 이름을 가진 변수를 3번이나 정의했지만 아무런 에러없이 코드는 잘 실행된다. 다만, 이경우엔 당연하게도 세번째로 정의한 변수가 위의 첫번째, 두번째 변수명을 엎어쳤기 때문에 첫번째와 두번째로 선언한 num이라는 변수는 더이상 코드적으로 접근할 방법이 없으므로 추가적인 활용이 불가능하다(let과 const는 변수명의 중복이 불가능하다)
1-3. function scope
javascript의 var은 function scope를 가진다.
javascript의 함수를 실행하면, 실행 컨텍스트(Execution Context)가 생성되고 이에 따라 동작할 컨텍스트 스택(Context Stack)이 콜 스택(Call Stack)이라는 메모리상의 자료구조에 쌓이게 되는데, 이때 적재되는 스택의 단위는 function이다.
function outer(){
console.log('outer');
function inner(){
console.log('inner');
}
inner();
}
outer();
그래서 위와 같은 코드를 실행하게 되면, 대략 아래와 같은 순으로 실행 컨텍스트에 따라 Javascript가 동작하게 된다.
그리고 여기서 javascript가 'function'을 기준으로 동작한다는 매커니즘'에 기반해서 생각해보면, javascript의 태생부터 존재했던 var이라는 변수 선언 키워드의 scope도 동일하게 function scope라는 부분이 이해가 될 것이다.
한 문장으로 요약하자면,
javascript는 function을 기준으로 동작 하니까, javascript의 변수 선언 키워드인 var도 function scope.
그래서 아래와 같은 예시를 생각해보면,
function scope_var(){
// 코드 출처 : https://poiemaweb.com/js-scope
var x = 'global';
function foo() {
var x = 'local';
console.log(x); // local
function bar() {
console.log(x); // local
}
bar();
}
foo();
console.log(x); // global
}
scope_var();
x 라는 변수를 함수 여기저기에 활용하며 function scope의 예시를 보여주는 코드이다.
주의깊게 봐야 할 부분은 bar function 내부에서 사용한 x라는 변수다.
x는 bar function 내부에는 선언되지 않았지만, bar function 이 선언된 foo function 내부에 x 라는 이름의 변수가 선언되어 있다. 따라서 foo function 안쪽에 정의된 bar function 내에서 x 라는 변수를 활용하게 되면, foo function 이 가지는 scope를 기준으로 x를 가져와서 사용하게 된다(이러한 형태를 스코프 체인(Scope Chain)이라고도 한다)
이와같이 var로 선언한 변수는 function을 기준으로 scope를 가지게 된다.
2. let
2-1. Block Scope
C나 C++, JAVA와 같은 오래된 연식(?)의 프로그래밍언어에서의 변수들은 block scope를 가진다. 그리고 이를통해 개발에 입문한 (나와같은)사람들은 변수는 block scope를 가진다는 개념이 머릿속에 정립되어있기 때문에, javascript에 입문할 때 var가 가지고 있는 function scope 개념이 굉장히 헷갈리곤한다.
그래서인지 ES6(2015)에 let이라는 변수 선언용 키워드가 추가되었는데,
이 키워드는 var과는 다르게 block scope를 가지고 있다.
function sample(){
// 코드 출처 : https://poiemaweb.com/js-scope
var x = 0;
{
var x = 1;
console.log(x); // 1
}
console.log(x); // 1
let y = 0;
{
let y = 1;
console.log(y); // 1
}
console.log(y); // 0
}
sample();
block scope라는 것은 우리가 흔히 중괄호라고 부르는 { } 이 형태로 감싸진 내부에 scope가 맞춰지는 것이다. 그렇기 때문에, 위와 같은 코드에서 let변수 y는 각각 선언된 위치에 따른 scope가 다르기때문에 1과 0 이라는 서로 다른 결과를 콘솔에 출력하지만, var로 선언된 변수 x는 sample이라는 function으로 동일한 scope를 가지기 때문에, 중괄호 내부에 var x를 새롭게 선언함과 동시에 기선언되었던 x가 엎어쳐지게 됨으로써 동일한 1이라는 값을 콘솔에 출력하게 된다.
3. const
3-1. 상수
const도 let과 함께 ES6부터 추가된 키워드로써, block scope를 가지고있다.
const가 let 그리고 var와 다른점은, 최초 선언시 할당한 값을 변경할 수 없는 상수를 선언한다는 것이다.
const name = 'Grey';
name = 'Kai';
만약 위와같이, 상수로 정의한 name의 값을 변경하려한다면 아래와 같은 콘솔 에러를 확인할 수 있으며
이는, 말그대로 상수(constant variable)를 변경하려했기 때문에 발생하는 에러이다.
또한 const는 상수이기 때문에 아래와 같이 값을 할당하지 않는 것도 에러를 보여준다.
const name;
3-2. 객체가 const로 선언됐을 때?
const가 상수라고 했기때문에, 아래와 같은 경우에 종종 헷갈려하는 분들이 있다.
function sample(){
const obj = {
name: 'Grey',
age: 28
}
obj.age = 34;
console.log(obj.age); // 34
}
const는 상수라고 했는데, obj 내부의 age가 34로 변경되었고 아무런 에러도 발생하지 않는다. 이는 엄밀히 말하자면, obj라는 상수가 변경된 게 아니라, obj라는 객체를 참조하는 값이 가리키는 영역의 값...그러니까 한 단계를 더 거쳐서 메모리에 위치하고 있던 값을 변경하려 했고, 그 값이 변경된 것이다. 만약, 아래와 같이 obj라는 상수가 참조하는 값을 변조하려 한다면
function sample(){
const obj = {
name: 'Grey',
age: 28
}
obj = {
name: 'Grey',
age: 34
}
console.log(obj.age);
}
이와 같이 아주 시뻘건 에러로그를 콘솔에서 보게 된다.
4. 동적 타이핑(Dynamic typing)
Javascript의 변수 선언방식은, 기존 프로그래밍 언어들과 다른점은 변수의 자료형을 가리지않는다는 것이다.
// javascript
var num_value = 42; // number
var str_value = "str"; // string
var bool_value = true; // boolean
이러한 특성은 var뿐만 아니라 let, const도 동일하게 가지고 있는 점으로써, 위 코드에서 대입 연산자(=)를 통해 바인딩되는 값들의 타입은 number, string, boolean으로 전부 다르다. 하지만 var이라는 키워드를 통해 변수를 선언하는 부분은 동일한데, 이는 변수의 타입을 키워드로 특정짓지않아도 프로그램이 동작할 때 자동으로 해석해준다는 것이다.
예를들어, JAVA라면 위와 같은 변수들을 각각 선언할 때 아래와 같이 키워드를 구분해서 써줘야한다.
(아래 코드 중 JAVA의 String은 객체지만, 동일 형태의 데이터 타입 비교를 위해서니 양해바랍니다)
// java
int num_value = 42; // number
String str_value = "str"; // string
boolean bool_value = true; // boolean
이와같은 개념을 Javascript에서는 동적 타이핑(dynamic typing)이라고 정의하고있으며, 이는 Javasript가 느슨한 언어(loosely typed) 혹은 동적 언어(dynamic language)라는 개념에 근간을 두고있기 때문이다.
5. 호이스팅
var와 let, const로 선언한 변수/상수는 Javascript 실행시 호이스팅되지만,
var는 호이스팅때 undefined로 초기화되고 let과 const는 uninitialized로 초기화된다는 차이점을 가진다.
이에 대한 상세한 설명을 여기서 다루기엔 너무 주제를 벗어나기에 우선 저렇게 알아주기를 바라며...
혹시나 왜 그런지 궁금하신 분은 내가 작성했던 또 다른 포스팅인 [Javascript] class도 호이스팅이 되나요(feat. lexical environment) 를 참고하기 바란다.
6. 간략히 정리
그러니까 윗 내용들을 정리하자면 각각 아래와 같은 특징을 가진다.
var | let | const | |
형태 | 변수 | 변수 | 상수 |
호이스팅 | undefined | uninitialized | uninitialized |
스코프 | function | block | block |
동적 타이핑 | O | O | O |
변수명 중복선언 | 가능 | 불가능 | 불가능 |
참고사이트
'개발 > 프론트엔드(Front-end)' 카테고리의 다른 글
[Vue.js] Vue는 MVVM 패턴과 관련이 없지만 (3) | 2021.10.31 |
---|---|
[javascript] var가 let보다 빠르다? (5) | 2021.10.14 |
[CSS] opacity는 reflow가 발생 안 한다구요...? 정말?? (7) | 2021.09.09 |
[CSS] CSS Triggers (0) | 2021.09.04 |
[Javascript] class도 호이스팅이 되나요(feat. lexical environment) (7) | 2021.08.26 |