๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

[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() {} โš ๏ธ ๋ณ€์ˆ˜ ํ• ๋‹น์œผ๋กœ ์ทจ๊ธ‰๋จ
โ””โ”€ ๋ณ€์ˆ˜ ์ด๋ฆ„๋งŒ ๋Œ์–ด์˜ฌ๋ ค์ง€๊ณ , ํ•จ์ˆ˜ ๋ณธ๋ฌธ์€ ๋Œ์–ด์˜ฌ๋ ค์ง€์ง€ ์•Š์Œ

๋ฉด์ ‘ ํฌ์ธํŠธโ€‹

์ด๋Ÿฐ ์œ ํ˜•์˜ ๋ฌธ์ œ์— ๋‹ตํ•  ๋•Œ ๊ถŒ์žฅ์‚ฌํ•ญ:

  1. Hoisting ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์„ค๋ช…: ์ƒ์„ฑ๊ณผ ์‹คํ–‰ ๋‘ ๋‹จ๊ณ„๋กœ ๋‚˜๋‰จ
  2. ์šฐ์„ ์ˆœ์œ„ ๊ฐ•์กฐ: ํ•จ์ˆ˜ ์„ ์–ธ > ๋ณ€์ˆ˜ ์„ ์–ธ
  3. ๋Œ์–ด์˜ฌ๋ฆผ ํ›„์˜ ์ฝ”๋“œ ๊ทธ๋ฆฌ๊ธฐ: ๋ฉด์ ‘๊ด€์—๊ฒŒ ์ดํ•ด๋„๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ
  4. ๋ชจ๋ฒ” ์‚ฌ๋ก€ ์–ธ๊ธ‰: let/const๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ var์˜ Hoisting ๋ฌธ์ œ ํšŒํ”ผ

๋ฉด์ ‘ ๋‹ต๋ณ€ ์˜ˆ์‹œ:

"์ด ๋ฌธ์ œ๋Š” Hoisting์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. JavaScript์—์„œ ํ•จ์ˆ˜ ์„ ์–ธ์˜ ๋Œ์–ด์˜ฌ๋ฆผ ์šฐ์„ ์ˆœ์œ„๋Š” ๋ณ€์ˆ˜ ์„ ์–ธ๋ณด๋‹ค ๋†’์Šต๋‹ˆ๋‹ค.

์‹คํ–‰ ๊ณผ์ •์€ ๋‘ ๋‹จ๊ณ„๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค:

  1. ์ƒ์„ฑ ๋‹จ๊ณ„: function foo() {}๊ฐ€ ์™„์ „ํžˆ ์ตœ์ƒ๋‹จ์œผ๋กœ ๋Œ์–ด์˜ฌ๋ ค์ง€๊ณ , ๋‹ค์Œ์œผ๋กœ var foo ์„ ์–ธ์ด ๋Œ์–ด์˜ฌ๋ ค์ง€์ง€๋งŒ ๊ธฐ์กด ํ•จ์ˆ˜๋ฅผ ๋ฎ์–ด์“ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  2. ์‹คํ–‰ ๋‹จ๊ณ„: console.log(foo) ์‹œ์ ์—์„œ foo๋Š” ํ•จ์ˆ˜์ด๋ฏ€๋กœ [Function: foo]๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ์ดํ›„ foo = '1'์—์„œ foo๊ฐ€ ๋ฌธ์ž์—ด๋กœ ๋ฎ์–ด์จ์ง‘๋‹ˆ๋‹ค.

๋ชจ๋ฒ” ์‚ฌ๋ก€๋Š” let/const๋กœ var๋ฅผ ๋Œ€์ฒดํ•˜๊ณ , ํ•จ์ˆ˜ ์„ ์–ธ์„ ์ตœ์ƒ๋‹จ์— ๋ฐฐ์น˜ํ•˜์—ฌ ์ด๋Ÿฌํ•œ ํ˜ผ๋ž€์„ ํ”ผํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค."


๊ด€๋ จ ์ฃผ์ œโ€‹