[Medium] ๐ var, let, const
๊ฐ์โ
JavaScript์๋ ๋ณ์๋ฅผ ์ ์ธํ๋ ์ธ ๊ฐ์ง ํค์๋๊ฐ ์์ต๋๋ค: var, let, const. ๋ชจ๋ ๋ณ์ ์ ์ธ์ ์ฌ์ฉ๋์ง๋ง, ์ค์ฝํ, ์ด๊ธฐํ, ์ค๋ณต ์ ์ธ, ์ฌํ ๋น, ์ ๊ทผ ์์ ๋ฑ์์ ์ฐจ์ด๊ฐ ์์ต๋๋ค.
์ฃผ์ ์ฐจ์ด์ โ
| ๋์ | var | let | const |
|---|---|---|---|
| ์ค์ฝํ | ํจ์ ์ค์ฝํ ๋๋ ์ ์ญ | ๋ธ๋ก ์ค์ฝํ | ๋ธ๋ก ์ค์ฝํ |
| ์ด๊ธฐํ | ์ ํ | ์ ํ | ํ์ |
| ์ค๋ณต ์ ์ธ | ํ์ฉ | ๋ถํ | ๋ถํ |
| ์ฌํ ๋น | ํ์ฉ | ํ์ฉ | ๋ถํ |
| ์ ์ธ ์ ์ ๊ทผ | undefined ๋ฐํ | ReferenceError ๋ฐ์ | ReferenceError ๋ฐ์ |
์์ธ ์ค๋ช โ
์ค์ฝํโ
var์ ์ค์ฝํ๋ ํจ์ ์ค์ฝํ ๋๋ ์ ์ญ ์ค์ฝํ์ด๋ฉฐ, let๊ณผ const๋ ๋ธ๋ก ์ค์ฝํ(ํจ์, if-else ๋ธ๋ก, for ๋ฃจํ ํฌํจ)์
๋๋ค.
function scopeExample() {
var varVariable = 'var';
let letVariable = 'let';
const constVariable = 'const';
console.log(varVariable); // 'var'
console.log(letVariable); // 'let'
console.log(constVariable); // 'const'
}
scopeExample();
console.log(varVariable); // ReferenceError: varVariable is not defined
console.log(letVariable); // ReferenceError: letVariable is not defined
console.log(constVariable); // ReferenceError: constVariable is not defined
if (true) {
var varInBlock = 'var in block';
let letInBlock = 'let in block';
const constInBlock = 'const in block';
}
console.log(varInBlock); // 'var in block'
console.log(letInBlock); // ReferenceError: letInBlock is not defined
console.log(constInBlock); // ReferenceError: constInBlock is not defined
์ด๊ธฐํโ
var์ let์ ์ ์ธ ์ ์ด๊ธฐํํ์ง ์์๋ ๋์ง๋ง, const๋ ๋ฐ๋์ ์ ์ธ ์ ์ด๊ธฐํํด์ผ ํฉ๋๋ค.
var varVariable; // ์ ํจ
let letVariable; // ์ ํจ
const constVariable; // SyntaxError: Missing initializer in const declaration
์ค๋ณต ์ ์ธโ
๊ฐ์ ์ค์ฝํ ๋ด์์ var๋ ๋์ผํ ๋ณ์์ ์ค๋ณต ์ ์ธ์ ํ์ฉํ์ง๋ง, let๊ณผ const๋ ํ์ฉํ์ง ์์ต๋๋ค.
var x = 1;
var x = 2; // ์ ํจ, x๋ ์ด์ 2
let y = 1;
let y = 2; // SyntaxError: Identifier 'y' has already been declared
const z = 1;
const z = 2; // SyntaxError: Identifier 'z' has already been declared
์ฌํ ๋นโ
var์ let์ผ๋ก ์ ์ธ๋ ๋ณ์๋ ์ฌํ ๋น์ด ๊ฐ๋ฅํ์ง๋ง, const๋ก ์ ์ธ๋ ๋ณ์๋ ์ฌํ ๋นํ ์ ์์ต๋๋ค.
var x = 1;
x = 2; // ์ ํจ
let y = 1;
y = 2; // ์ ํจ
const z = 1;
z = 2; // TypeError: Assignment to a constant variable
์ฐธ๊ณ : const๋ก ์ ์ธ๋ ๋ณ์๋ ์ฌํ ๋นํ ์ ์์ง๋ง, ๊ฐ์ฒด๋ ๋ฐฐ์ด์ธ ๊ฒฝ์ฐ ๊ทธ ๋ด์ฉ์ ์์ ํ ์ ์์ต๋๋ค.
const obj = { key: 'value' };
obj.key = 'new value'; // ์ ํจ
console.log(obj); // { key: 'new value' }
const arr = [1, 2, 3];
arr.push(4); // ์ ํจ
console.log(arr); // [1, 2, 3, 4]
์ ์ธ ์ ์ ๊ทผ (Temporal Dead Zone)โ
var๋ก ์ ์ธ๋ ๋ณ์๋ Hoisting๋์ด ์๋์ผ๋ก undefined๋ก ์ด๊ธฐํ๋ฉ๋๋ค. ๋ฐ๋ฉด, let๊ณผ const๋ก ์ ์ธ๋ ๋ณ์๋ Hoisting๋์ง๋ง ์ด๊ธฐํ๋์ง ์์ผ๋ฏ๋ก, ์ ์ธ ์ ์ ์ ๊ทผํ๋ฉด ReferenceError๊ฐ ๋ฐ์ํฉ๋๋ค.
console.log(x); // undefined
var x = 5;
console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 5;
console.log(z); // ReferenceError: Cannot access 'z' before initialization
const z = 5;
๋ฉด์ ๋ฌธ์ โ
๋ฌธ์ : setTimeout + var์ ๋ํ์ ํจ์ โ
๋ค์ ์ฝ๋์ ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ํ๋จํ์ธ์:
for (var i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, 0);
}
์ค๋ต (ํํ ์คํด)โ
๋ง์ ์ฌ๋๋ค์ด ์ถ๋ ฅ์ด 1 2 3 4 5๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ค์ ์ถ๋ ฅโ
6
6
6
6
6
์ ๊ทธ๋ด๊น?โ
์ด ๋ฌธ์ ๋ ์ธ ๊ฐ์ง ํต์ฌ ๊ฐ๋ ๊ณผ ๊ด๋ จ๋ฉ๋๋ค:
1. var์ ํจ์ ์ค์ฝํ
// var๋ ๋ฃจํ ๋ด์์ ๋ธ๋ก ์ค์ฝํ๋ฅผ ์์ฑํ์ง ์์
for (var i = 1; i <= 5; i++) {
// i๋ ์ธ๋ถ ์ค์ฝํ์ ์์ผ๋ฉฐ, ๋ชจ๋ ์ดํฐ๋ ์ด์
์ด ๊ฐ์ i๋ฅผ ๊ณต์
}
console.log(i); // 6 (๋ฃจํ ์ข
๋ฃ ํ i์ ๊ฐ)
// var์ ๊ฒฝ์ฐ
{
var i;
i = 1;
i = 2;
i = 3;
i = 4; // ๋ฃจํ ์ข
๋ฃ
}
2. setTimeout์ ๋น๋๊ธฐ ์คํ
// setTimeout์ ๋น๋๊ธฐ๋ก, ํ์ฌ ๋๊ธฐ ์ฝ๋ ์คํ์ด ์๋ฃ๋ ํ์ ์คํ๋จ
for (var i = 1; i <= 5; i++) {
setTimeout(function () {
// ์ด ์ฝ๋๋ Event Loop์ ํ์คํฌ ํ์ ๋ค์ด๊ฐ
console.log(i);
}, 0);
}
// ๋ฃจํ๊ฐ ๋จผ์ ์๋ฃ๋๊ณ (i๊ฐ 6์ด ๋จ), ๊ทธ ๋ค์์ setTimeout ์ฝ๋ฐฑ์ด ์คํ๋จ
3. Closure ์ฐธ์กฐ
// ๋ชจ๋ setTimeout ์ฝ๋ฐฑ ํจ์๊ฐ ๊ฐ์ i๋ฅผ ์ฐธ์กฐํจ
// ์ฝ๋ฐฑ์ด ์คํ๋ ๋, i๋ ์ด๋ฏธ 6์ด ๋์ด ์์
ํด๊ฒฐ ๋ฐฉ๋ฒโ
๋ฐฉ๋ฒ 1: let ์ฌ์ฉ (๊ถ์ฅ) โ
for (let i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, 0);
}
// ์ถ๋ ฅ: 1 2 3 4 5
// let์ ๊ฒฝ์ฐ
{
let i = 1; // ์ฒซ ๋ฒ์งธ ์ดํฐ๋ ์ด์
์ i
}
{
let i = 2; // ๋ ๋ฒ์งธ ์ดํฐ๋ ์ด์
์ i
}
{
let i = 3; // ์ธ ๋ฒ์งธ ์ดํฐ๋ ์ด์
์ i
}
์๋ฆฌ: let์ ๋งค ์ดํฐ๋ ์ด์
๋ง๋ค ์๋ก์ด ๋ธ๋ก ์ค์ฝํ๋ฅผ ์์ฑํ์ฌ, ๊ฐ setTimeout ์ฝ๋ฐฑ์ด ํ์ฌ ์ดํฐ๋ ์ด์
์ i ๊ฐ์ ์บก์ฒํฉ๋๋ค.
// ๋ฑ๊ฐ
{
let i = 1;
setTimeout(function () {
console.log(i);
}, 0);
}
{
let i = 2;
setTimeout(function () {
console.log(i);
}, 0);
}
// ... ์ดํ ๋์ผ
๋ฐฉ๋ฒ 2: IIFE (์ฆ์ ์คํ ํจ์) ์ฌ์ฉ
for (var i = 1; i <= 5; i++) {
(function (j) {
setTimeout(function () {
console.log(j);
}, 0);
})(i);
}
// ์ถ๋ ฅ: 1 2 3 4 5
์๋ฆฌ: IIFE๊ฐ ์๋ก์ด ํจ์ ์ค์ฝํ๋ฅผ ์์ฑํ๋ฉฐ, ๋งค ์ดํฐ๋ ์ด์
๋ง๋ค ํ์ฌ์ i ๊ฐ์ด ๋งค๊ฐ๋ณ์ j๋ก ์ ๋ฌ๋์ด Closure๋ฅผ ํ์ฑํฉ๋๋ค.
๋ฐฉ๋ฒ 3: setTimeout์ ์ธ ๋ฒ์งธ ์ธ์ ์ฌ์ฉ
for (var i = 1; i <= 5; i++) {
setTimeout(
function (j) {
console.log(j);
},
0,
i
); // ์ธ ๋ฒ์งธ ์ธ์๊ฐ ์ฝ๋ฐฑ ํจ์์ ์ ๋ฌ๋จ
}
// ์ถ๋ ฅ: 1 2 3 4 5
์๋ฆฌ: setTimeout์ ์ธ ๋ฒ์งธ ์ธ์ ์ดํ๋ ์ฝ๋ฐฑ ํจ์์ ์ธ์๋ก ์ ๋ฌ๋ฉ๋๋ค.
๋ฐฉ๋ฒ 4: bind ์ฌ์ฉ
for (var i = 1; i <= 5; i++) {
setTimeout(
function (j) {
console.log(j);
}.bind(null, i),
0
);
}
// ์ถ๋ ฅ: 1 2 3 4 5
์๋ฆฌ: bind๋ ์๋ก์ด ํจ์๋ฅผ ์์ฑํ๊ณ ํ์ฌ์ i ๊ฐ์ ์ธ์๋ก ๋ฐ์ธ๋ฉํฉ๋๋ค.
๋ฐฉ๋ฒ ๋น๊ตโ
| ๋ฐฉ๋ฒ | ์ฅ์ | ๋จ์ | ๊ถ์ฅ๋ |
|---|---|---|---|
let | ๊ฐ๊ฒฐ, ํ๋์ , ์ดํดํ๊ธฐ ์ฌ์ | ES6+ | 5/5 ๊ฐ๋ ฅ ๊ถ์ฅ |
| IIFE | ํธํ์ฑ ์ข์ | ๊ตฌ๋ฌธ์ด ๋ณต์ก | 3/5 ๊ณ ๋ ค ๊ฐ๋ฅ |
| setTimeout ์ธ์ | ๊ฐ๋จํ๊ณ ์ง์ ์ | ์ ์๋ ค์ง์ง ์์ | 4/5 ๊ถ์ฅ |
bind | ํจ์ํ ์คํ์ผ | ๊ฐ๋ ์ฑ์ด ๋ค์ ๋จ์ด์ง | 3/5 ๊ณ ๋ ค ๊ฐ๋ฅ |
์ฌํ ๋ฌธ์ โ
Q1: ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝํ๋ฉด?
for (var i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, i * 1000);
}
๋ต: ๋งค์ด 6์ด ์ถ๋ ฅ๋๋ฉฐ, ์ด 5๋ฒ ์ถ๋ ฅ๋ฉ๋๋ค(๊ฐ๊ฐ 1์ด, 2์ด, 3์ด, 4์ด, 5์ด์ ์ถ๋ ฅ).
Q2: ๋งค์ด ์์๋๋ก 1, 2, 3, 4, 5๋ฅผ ์ถ๋ ฅํ๋ ค๋ฉด?
for (let i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, i * 1000);
}
// 1์ด ํ 1 ์ถ๋ ฅ
// 2์ด ํ 2 ์ถ๋ ฅ
// 3์ด ํ 3 ์ถ๋ ฅ
// 4์ด ํ 4 ์ถ๋ ฅ
// 5์ด ํ 5 ์ถ๋ ฅ
๋ฉด์ ํฌ์ธํธโ
์ด ๋ฌธ์ ๊ฐ ํ ์คํธํ๋ ๊ฒ:
- var์ ์ค์ฝํ: ํจ์ ์ค์ฝํ vs ๋ธ๋ก ์ค์ฝํ
- Event Loop: ๋๊ธฐ vs ๋น๋๊ธฐ ์คํ
- Closure: ํจ์๊ฐ ์ธ๋ถ ๋ณ์๋ฅผ ์ด๋ป๊ฒ ์บก์ฒํ๋์ง
- ํด๊ฒฐ ๋ฐฉ๋ฒ: ๋ค์ํ ํด๋ฒ๊ณผ ์ฅ๋จ์ ๋น๊ต
๋ต๋ณ ์ ๊ถ์ฅ์ฌํญ:
- ๋จผ์ ์ ๋ต์ ๋งํจ (6 6 6 6 6)
- ์ด์ ๋ฅผ ์ค๋ช ํจ (var ์ค์ฝํ + setTimeout ๋น๋๊ธฐ)
- ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ ์ํจ (let ์ฐ์ , ๋ค๋ฅธ ๋ฐฉ๋ฒ๋ ์ค๋ช )
- JavaScript ๋ด๋ถ ๋ฉ์ปค๋์ฆ์ ๋ํ ์ดํด๋ฅผ ๋ณด์ฌ์ค
๋ชจ๋ฒ ์ฌ๋กโ
- ์ฐ์ ์ ์ผ๋ก
const์ฌ์ฉ: ์ฌํ ๋น์ด ํ์ ์๋ ๋ณ์์๋const๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋์ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋์ ๋๋ค. - ๋ค์์ผ๋ก
let์ฌ์ฉ: ์ฌํ ๋น์ด ํ์ํ ๊ฒฝ์ฐlet์ ์ฌ์ฉํฉ๋๋ค. var์ฌ์ฉ์ ํผํจ:var์ ์ค์ฝํ์ Hoisting ๋์์ด ์์์น ๋ชปํ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์์ผ๋ฏ๋ก, ํ๋ JavaScript ๊ฐ๋ฐ์์๋ ์ฌ์ฉ์ ํผํ๋ ๊ฒ์ด ์ข์ต๋๋ค.- ๋ธ๋ผ์ฐ์ ํธํ์ฑ ์ฃผ์: ๊ตฌํ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ง์ํด์ผ ํ๋ ๊ฒฝ์ฐ, Babel ๋ฑ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ
let๊ณผconst๋ฅผvar๋ก ํธ๋์คํ์ผํ ์ ์์ต๋๋ค.