[Medium] ๐ Hoisting
1. What's Hoisting ?โ
JS์ ์คํ์ ์์ฑ ๋จ๊ณ์ ์คํ ๋จ๊ณ, ๋ ๋จ๊ณ๋ก ๋๋ ์ ์์ต๋๋ค:
var name = 'Pitt';
console.log(name); // print Pitt
Hoisting ํน์ฑ์ผ๋ก ์ธํด, ์ ์ฝ๋๋ ์ค์ ๋ก ๋จผ์ ๋ณ์๋ฅผ ์ ์ธํ๊ณ ๊ทธ ๋ค์์ ๊ฐ์ ํ ๋นํ๋ ๊ฒ์ผ๋ก ์ดํดํด์ผ ํฉ๋๋ค.
// create
var name;
// execute
name = 'Pitt';
console.log(name);
๋ฐ๋ฉด function์ ๋ณ์์ ๋ค๋ฅด๊ฒ, ์์ฑ ๋จ๊ณ์์ ๋ฉ๋ชจ๋ฆฌ์ ํ ๋น๋ฉ๋๋ค. ํจ์ ์ ์ธ๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
getName();
function getName() {
console.log('string'); // print string
}
์ ์ฝ๋๊ฐ ์ ์์ ์ผ๋ก ์คํ๋์ด console.log๋ฅผ ์ถ๋ ฅํ ์ ์๋ ์ด์ ๋ ๋ค์ ๋ก์ง ๋๋ฌธ์ ๋๋ค. function์ด ๋จผ์ ์ต์๋จ์ผ๋ก ๋์ด์ฌ๋ ค์ง๊ณ , ๊ทธ ๋ค์์ function ํธ์ถ์ด ์ด๋ฃจ์ด์ง๋๋ค.
// create
function getName() {
console.log('string');
}
// execute
getName();
ํ์ง๋ง ์ฃผ์ํ ์ ์, ์ด๋ฌํ Hoisting ํน์ฑ์์ ํํ์์ ์ฌ์ฉํ ๋๋ ์์ฑ ์์์ ์ฃผ์ํด์ผ ํ๋ค๋ ๊ฒ์ ๋๋ค.
์์ฑ ๋จ๊ณ์์๋ function์ด ๊ฐ์ฅ ์ฐ์ ์ด๋ฉฐ, ๊ทธ ๋ค์์ด ๋ณ์์ ๋๋ค.
Correctโ
name = 'Yumy';
console.log(name); // print Yumy
var name;
// --- Equal to ---
// create
var name;
// execute
name = 'Yumy';
console.log(name); // print Yumy
Wrongโ
console.log(name); // print undefined
var name = 'Jane';
// --- Equal to ---
// create
var name;
// execute
console.log(name); // print undefined๏ผ์์ง ๊ฐ์ด ํ ๋น๋์ง ์์ ๊ธฐ๋ณธ๊ฐ์ธ undefined๋ง ๋ฐ์
name = 'Pitt';
2. What's name printed ?โ
whoseName();
function whoseName() {
if (name) {
name = 'Nini';
}
}
var name = 'Pitt';
console.log(name);
Answerโ
// create
function whoseName() {
if (name) {
name = 'Nini';
}
}
var name;
// execute
whoseName();
name = 'Pitt';
console.log(name); // print Pitt
name์ whoseName() ์์์ undefined๋ฅผ ๋ฐ๊ธฐ ๋๋ฌธ์ ์กฐ๊ฑด๋ฌธ์ผ๋ก ๋ค์ด๊ฐ์ง ์์ต๋๋ค.
ํ์ง๋ง ํจ์ ์ ์ธ๋ฌธ ์๋์ ๋ค์ ๊ฐ ํ ๋น์ด ์๊ธฐ ๋๋ฌธ์, ์ค๋ น function ๋ด์์ ์กฐ๊ฑด๋ฌธ์ ์ง์ ํ๋๋ผ๋ ์ต์ข ์ ์ผ๋ก๋ Pitt๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
3. ํจ์ ์ ์ธ vs ๋ณ์ ์ ์ธ: Hoisting ์ฐ์ ์์โ
๋ฌธ์ : ๊ฐ์ ์ด๋ฆ์ ํจ์์ ๋ณ์โ
๋ค์ ์ฝ๋์ ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ํ๋จํ์ธ์:
console.log(foo);
var foo = '1';
function foo() {}
์ค๋ต (ํํ ์คํด)โ
๋ง์ ์ฌ๋๋ค์ด ๋ค์๊ณผ ๊ฐ์ด ์๊ฐํฉ๋๋ค:
undefined์ถ๋ ฅ (var๊ฐ ๋จผ์ ๋์ด์ฌ๋ ค์ง๋ค๊ณ ์๊ฐ)'1'์ถ๋ ฅ (ํ ๋น์ด ์ํฅ์ ๋ฏธ์น๋ค๊ณ ์๊ฐ)- ์๋ฌ ๋ฐ์ (๊ฐ์ ์ด๋ฆ์ด ์ถฉ๋ํ๋ค๊ณ ์๊ฐ)
์ค์ ์ถ๋ ฅโ
[Function: foo]
์ ๊ทธ๋ด๊น?โ
์ด ๋ฌธ์ ๋ Hoisting์ ์ฐ์ ์์ ๊ท์น์ ํ ์คํธํฉ๋๋ค:
Hoisting ์ฐ์ ์์: ํจ์ ์ ์ธ > ๋ณ์ ์ ์ธ
// ์๋ณธ ์ฝ๋
console.log(foo);
var foo = '1';
function foo() {}
// ๋์ผํจ (Hoisting ํ)
// ๋จ๊ณ 1: ์์ฑ ๋จ๊ณ (Hoisting)
function foo() {} // 1. ํจ์ ์ ์ธ์ด ๋จผ์ ํธ์ด์คํ
๋จ
var foo; // 2. ๋ณ์ ์ ์ธ ํธ์ด์คํ
(๊ธฐ์กด ํจ์๋ฅผ ๋ฎ์ด์ฐ์ง ์์)
// ๋จ๊ณ 2: ์คํ ๋จ๊ณ
console.log(foo); // ์ด ์์ ์์ foo๋ ํจ์, ์ถ๋ ฅ [Function: foo]
foo = '1'; // 3. ๋ณ์ ํ ๋น (ํจ์๋ฅผ ๋ฎ์ด์)
ํต์ฌ ๊ฐ๋ โ
1. ํจ์ ์ ์ธ์ ์์ ํ ๋์ด์ฌ๋ ค์ง๋ค
console.log(myFunc); // [Function: myFunc]
function myFunc() {
return 'Hello';
}
2. var ๋ณ์ ์ ์ธ์ ์ ์ธ๋ง ๋์ด์ฌ๋ ค์ง๊ณ , ํ ๋น์ ๋์ด์ฌ๋ ค์ง์ง ์๋๋ค
console.log(myVar); // undefined
var myVar = 'Hello';
3. ํจ์ ์ ์ธ๊ณผ ๋ณ์ ์ ์ธ์ด ๊ฐ์ ์ด๋ฆ์ผ ๋
// ํธ์ด์คํ
ํ ์์
function foo() {} // ํจ์๊ฐ ๋จผ์ ํธ์ด์คํ
๋์ด ํ ๋น๋จ
var foo; // ๋ณ์ ์ ์ธ ํธ์ด์คํ
, ๊ธฐ์กด ํจ์๋ฅผ ๋ฎ์ด์ฐ์ง ์์
// ๋ฐ๋ผ์ foo๋ ํจ์
console.log(foo); // [Function: foo]
์ ์ฒด ์คํ ํ๋ฆโ
// ์๋ณธ ์ฝ๋
console.log(foo); // ?
var foo = '1';
function foo() {}
console.log(foo); // ?
// ======== ๋์ผํจ ========
// ์์ฑ ๋จ๊ณ (Hoisting)
function foo() {} // 1๏ธโฃ ํจ์ ์ ์ธ ํธ์ด์คํ
(์์ ํ ํธ์ด์คํ
๋จ, ํจ์ ๋ณธ๋ฌธ ํฌํจ)
var foo; // 2๏ธโฃ ๋ณ์ ์ ์ธ ํธ์ด์คํ
(foo๋ฅผ ๋ฎ์ด์ฐ์ง ์์, ์ด๋ฏธ ํจ์์ด๋ฏ๋ก)
// ์คํ ๋จ๊ณ
console.log(foo); // [Function: foo] - foo๋ ํจ์
foo = '1'; // 3๏ธโฃ ๋ณ์ ํ ๋น (์ด ์์ ์์ ํจ์๋ฅผ ๋ฎ์ด์)
console.log(foo); // '1' - foo๊ฐ ๋ฌธ์์ด์ด ๋จ
์ฌํ ๋ฌธ์ โ
๋ฌธ์ A: ์์์ ์ํฅโ
console.log(foo); // ?
function foo() {}
var foo = '1';
console.log(foo); // ?
๋ต:
[Function: foo] // ์ฒซ ๋ฒ์งธ ์ถ๋ ฅ
'1' // ๋ ๋ฒ์งธ ์ถ๋ ฅ
์ด์ : ์ฝ๋ ์์๋ Hoisting ๊ฒฐ๊ณผ์ ์ํฅ์ ๋ฏธ์น์ง ์์ต๋๋ค. ๋์ด์ฌ๋ฆผ ์ฐ์ ์์๋ ์ฌ์ ํ ํจ์ > ๋ณ์์ ๋๋ค.
๋ฌธ์ B: ๊ฐ์ ์ด๋ฆ์ ์ฌ๋ฌ ํจ์โ
console.log(foo); // ?
function foo() {
return 1;
}
var foo = '1';
function foo() {
return 2;
}
console.log(foo); // ?
๋ต:
[Function: foo] { return 2; } // ์ฒซ ๋ฒ์งธ ์ถ๋ ฅ (๋ค์ ํจ์๊ฐ ์์ ํจ์๋ฅผ ๋ฎ์ด์)
'1' // ๋ ๋ฒ์งธ ์ถ๋ ฅ (๋ณ์ ํ ๋น์ด ํจ์๋ฅผ ๋ฎ์ด์)
์ด์ :
// ํธ์ด์คํ
ํ
function foo() {
return 1;
} // ์ฒซ ๋ฒ์งธ ํจ์
function foo() {
return 2;
} // ๋ ๋ฒ์งธ ํจ์๊ฐ ์ฒซ ๋ฒ์งธ๋ฅผ ๋ฎ์ด์
var foo; // ๋ณ์ ์ ์ธ (ํจ์๋ฅผ ๋ฎ์ด์ฐ์ง ์์)
console.log(foo); // [Function: foo] { return 2; }
foo = '1'; // ๋ณ์ ํ ๋น (ํจ์๋ฅผ ๋ฎ์ด์)
console.log(foo); // '1'
๋ฌธ์ C: ํจ์ ํํ์ vs ํจ์ ์ ์ธโ
console.log(foo); // ?
console.log(bar); // ?
var foo = function () {
return 1;
};
function bar() {
return 2;
}
๋ต:
undefined; // foo๋ undefined
[Function: bar] // bar๋ ํจ์
์ด์ :
// ํธ์ด์คํ
ํ
var foo; // ๋ณ์ ์ ์ธ ํธ์ด์คํ
(ํจ์ ํํ์์ ๋ณ์ ์ด๋ฆ๋ง ํธ์ด์คํ
๋จ)
function bar() {
return 2;
} // ํจ์ ์ ์ธ ์์ ํ ํธ์ด์คํ
๋จ
console.log(foo); // undefined
console.log(bar); // [Function: bar]
foo = function () {
return 1;
}; // ํจ์ ํํ์ ํ ๋น
ํต์ฌ ์ฐจ์ด์ :
- ํจ์ ์ ์ธ:
function foo() {}โ ์์ ํ ๋์ด์ฌ๋ ค์ง (ํจ์ ๋ณธ๋ฌธ ํฌํจ) - ํจ์ ํํ์:
var foo = function() {}โ ๋ณ์ ์ด๋ฆ๋ง ๋์ด์ฌ๋ ค์ง๊ณ , ํจ์ ๋ณธ๋ฌธ์ ๋์ด์ฌ๋ ค์ง์ง ์์
let/const์์๋ ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์๋๋คโ
// โ var๋ ํธ์ด์คํ
๋ฌธ์ ๊ฐ ์์
console.log(foo); // undefined
var foo = '1';
// โ
let/const๋ TDZ(์ผ์์ ์ฌ๊ฐ์ง๋)๊ฐ ์์
console.log(bar); // ReferenceError: Cannot access 'bar' before initialization
let bar = '1';
// โ
let/const๋ ํจ์์ ๊ฐ์ ์ด๋ฆ์ด๋ฉด ์๋ฌ ๋ฐ์
function baz() {} // SyntaxError: Identifier 'baz' has already been declared
let baz = '1';
Hoisting ์ฐ์ ์์ ์์ฝโ
Hoisting ์ฐ์ ์์ (๋์ ์์๋๋ก):
1. ํจ์ ์ ์ธ (Function Declaration)
โโ function foo() {} โ
์์ ํ ๋์ด์ฌ๋ ค์ง
โโ ์ฐ์ ์์ ๊ฐ์ฅ ๋์
2. ๋ณ์ ์ ์ธ (Variable Declaration)
โโ var foo โ ๏ธ ์ ์ธ๋ง ๋์ด์ฌ๋ ค์ง๊ณ , ํ ๋น์ ๋์ด์ฌ๋ ค์ง์ง ์์
โโ ๊ธฐ์กด ํจ์๋ฅผ ๋ฎ์ด์ฐ์ง ์์
3. ๋ณ์ ํ ๋น (Variable Assignment)
โโ foo = '1' โ
ํจ์๋ฅผ ๋ฎ์ด์
โโ ์คํ ๋จ๊ณ์์ ๋ฐ์
4. ํจ์ ํํ์ (Function Expression)
โโ var foo = function() {} โ ๏ธ ๋ณ์ ํ ๋น์ผ๋ก ์ทจ๊ธ๋จ
โโ ๋ณ์ ์ด๋ฆ๋ง ๋์ด์ฌ๋ ค์ง๊ณ , ํจ์ ๋ณธ๋ฌธ์ ๋์ด์ฌ๋ ค์ง์ง ์์
๋ฉด์ ํฌ์ธํธโ
์ด๋ฐ ์ ํ์ ๋ฌธ์ ์ ๋ตํ ๋ ๊ถ์ฅ์ฌํญ:
- Hoisting ๋ฉ์ปค๋์ฆ ์ค๋ช : ์์ฑ๊ณผ ์คํ ๋ ๋จ๊ณ๋ก ๋๋จ
- ์ฐ์ ์์ ๊ฐ์กฐ: ํจ์ ์ ์ธ > ๋ณ์ ์ ์ธ
- ๋์ด์ฌ๋ฆผ ํ์ ์ฝ๋ ๊ทธ๋ฆฌ๊ธฐ: ๋ฉด์ ๊ด์๊ฒ ์ดํด๋๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ
- ๋ชจ๋ฒ ์ฌ๋ก ์ธ๊ธ: let/const๋ฅผ ์ฌ์ฉํ์ฌ var์ Hoisting ๋ฌธ์ ํํผ
๋ฉด์ ๋ต๋ณ ์์:
"์ด ๋ฌธ์ ๋ Hoisting์ ์ฐ์ ์์๋ฅผ ํ ์คํธํฉ๋๋ค. JavaScript์์ ํจ์ ์ ์ธ์ ๋์ด์ฌ๋ฆผ ์ฐ์ ์์๋ ๋ณ์ ์ ์ธ๋ณด๋ค ๋์ต๋๋ค.
์คํ ๊ณผ์ ์ ๋ ๋จ๊ณ๋ก ๋๋ฉ๋๋ค:
- ์์ฑ ๋จ๊ณ:
function foo() {}๊ฐ ์์ ํ ์ต์๋จ์ผ๋ก ๋์ด์ฌ๋ ค์ง๊ณ , ๋ค์์ผ๋กvar foo์ ์ธ์ด ๋์ด์ฌ๋ ค์ง์ง๋ง ๊ธฐ์กด ํจ์๋ฅผ ๋ฎ์ด์ฐ์ง ์์ต๋๋ค.- ์คํ ๋จ๊ณ:
console.log(foo)์์ ์์ foo๋ ํจ์์ด๋ฏ๋ก[Function: foo]๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค. ์ดํfoo = '1'์์ foo๊ฐ ๋ฌธ์์ด๋ก ๋ฎ์ด์จ์ง๋๋ค.๋ชจ๋ฒ ์ฌ๋ก๋
let/const๋กvar๋ฅผ ๋์ฒดํ๊ณ , ํจ์ ์ ์ธ์ ์ต์๋จ์ ๋ฐฐ์นํ์ฌ ์ด๋ฌํ ํผ๋์ ํผํ๋ ๊ฒ์ ๋๋ค."