https://m.blog.naver.com/tcloe8/221549773024
hoist
1. 동사 (흔히 밧줄이나 장비를 이용하여) 들어[끌어]올리다
2. 명사 (화물장애인을 들어올리기 위한) 승강 장치
네이버 사전에서 hoist 라는 단어를 찾으면 아래와 같다.
개발자가 아래와 같은 코드를 작성했다고 치자.
if(true){
var name = 'kim kimkim';
}
console.log(name);
변수는 일반적으로 블록 스코프{ } 안에서 유효하기 때문에 블록이 종료된 이후의 console.log에 name이 제대로 출력되지 않을 것이라 생각할 것이다. 하지만 콘솔에 kim kimkim이 출력되는 것을 확인 할 수 있다.
자바스크립트에서의 변수 호이스팅은 정의된 변수의 선언문을 유효 범위의 최상단으로 끌어올리는 것이다. 변수의 선언과 할당이 동시에 일어나지 않고 분리되는 것이다.
즉, 변수가 함수 내에서 정의된 경우 : 선언이 함수의 최상위로 호이스트 됨
변수가 함수 바깥에서 정의된 경우 : 선언이 전역 컨텍스트의 최상위로 호이스트 됨
호이스팅 된 변수의 경우 선언이 할당과 동시에 일어나는 것이 아니라, 선언부만 최산단으로 호이스트되어 가장 먼저 해석된다는 점이 중요하다.
선언은 변수를 초기화하는 구문을 말하고 할당은 변수에 값이 부여되는 것을 말한다.
호이스팅에 의해 이 두 가지가 분리될 수 있는데, 아래 코드로 확인해 보자.
아래 코드를 보면 data라는 변수는 아직 초기화되지 않았다.
function HoistD(){
console.log(data);
var data = 100;
console.log(data);
}
HoistD();
다른 언어라면 초기화되지 않은 변수를 호출하니 오류가 날 것이다.
그런데 이 자바스크립트에서는 오류대신 undefined가 출력된다.
윗줄의 console.log 코드가 바로 아래에 있는 var data = 100; 에서 data를 hoist하기 때문이다.
변수가 function 안에서 정의된 경우
이 변수의 선언(여기서는 var data = 100;)이 함수의 최상단으로 이동되기 때문이다.
선언 : 자바스크립트 엔진 구동 시 최상단으로 호이스트 됨
할당 : 런타임 과정에서 이루어지기 때문에 호이스팅 되지 않음 (원래 위치에서 할당)
if(true){
var name = 'kim kimkim';
}
console.log(name);
//개발자가 작성한 코드
var name; //변수의 선언이 최상단으로 호이스트 됨. 할당은 따라오지 않음.
if(ture){
var name = 'kim kimkim'; //앞에서 선언한 변수를 여기서 할당함.
}
console.log(name);
//변수의 선언이 호이스트 된 코드
선언은 유효 범위의 최상단으로 호이스트 된다. 여기서 유효 범위는 정확히 어디까지일까?
변수 선언을 하는 var는 let이나 const와는 다른 유효 범위를 가지고 있다.
var는 function-scope이고 let과 const는 block-scope이다.
즉, var는 단순히 블록 {}이 이나라 함수 function 함수명(){} 안에서 유효하다.
var 변수는 function-scope이므로 function 내의 선언들은 유효 범위(function)의 최상단으로 호이스트 된다.
function varScope(){
if(true){
var name = 'kim';
}
console.log(name);
}
function varScope2(){
for(var i=0; i<5; i++){
//do something
}
console.log(i);
}
if(true){var score = 100;}
console.log(score);
//개발자가 작성한 코드
var score; //한 단계 높은 function이 없어서 스크립트 최상단으로 선언이 호이스트 됨
function varScope(){
var name; //function 안에서 선언이 호이스트 됨
if(true){
name = 'kim'; //name에 값이 할당됨
}
console.log(name);
}
function varScope2(){
var i; //function 안에서 선언이 호이스트 됨
for(i=0; i<5; i++){ //i에 값이 할당됨
//do something
}
if(true){score = 100;} //score가 할당됨
console.log(score);
//호이스팅 된 코드
맨 마지막 if 구문은 function 밖에서 선언되었다.
이런 경우 global-scope가 적용되는데, global-scope도 function-scope처럼 작용하기 때문에 변수를 최상단으로 이동시킨다.
이 코드에서 선언된 변수는 전역 컨텐스트의 최상단으로 호이스트 되었다.
//내 주석 - global-scope도 하나의 function-scope로 본다는 이야기인 듯?
함수 역시 호이스팅 된다.
함수의 선언 부분이 함수 실행 부분보다 뒤에 있더라도 자바스크립트 엔진이 호이스팅해 준다.
즉, 함수 선언 부분을 맨 위로 끌어올린 채로 해석한다.
단, 함수 선언만 끌어올릴 뿐, 변수 값은 끌어올리지 않는다.
다음 예제를 살펴보자.
sayHello(); //출력 hello
function sayHello(){
console.log('hello');
}
sayHello() 함수가 선언되기 전에 함수 실행 코드가 먼저 쓰였다.
자바스크립트 엔진에서 sayHello() 함수의 선언 부분을 호이스팅하여 global 객체에 등록시키므로(global-scope) hello가 정상적으로 출력된다.
아래 예제도 살펴보자.
sayHello(); //syntax Error
var sayHello = function(){ console.log("hello); }
//개발자가 쓴 코드
// 함수 선언식
function sayHello(){
// do something
}
// 함수 표현식 등의 이름으로 부른다.
var sayHello = function(){
//do something
}
var sayHello는 변수이기 때문에 에러가 발생한다.
선언과 할당이 분리되기 때문이다.
선언과 할당 중에 선언 부분만이 최상단으로 호이스트 되고 할당 부분은 그 자리에서 실행된다.
var sayHello;
sayHello();
sayHello = function(){ console.log("hello"); }
//호이스팅 된 코드
순서로 보면 sayHello의 선언이 이루어지고 바로 sayHello를 호출하지만 그 내용에는 함수고 뭐고 아무것도 없는 상태다.
변수 및 함수 선언 시 선언 구문이 유효 범위의 최상단으로 호이스트 된다는 것을 배웠다.
그렇다면 변수 선언과 함수 선언의 우선 순위는 어떨까?
"변수 선언 먼저 -> 그 다음 함수 선언 호이스트" 순이다.
변수 선언이 더 높은 우선 순위를 가진다.
아래 코드에서 typeof의 결과값이 어떻게 변하는지 과정을 생각해 보자.
function myName(){
console.log('hello');
}
function yourName(){
console.log('everyone');
}
var myName = 'kim';
var yourName = 'bye';
console.log(typeof myName);
console.log(typeof yourName);
//개발자가 작성한 코드
typeof 의 결과가 어떻게 나올까?
호이스팅을 감안하여 typeof가 어떤 과정으로 변할지 생각해 보자.
var myName;
var yourName;
function myName(){
console.log('hello');
}
function yourName(){
console.log('everyone');
}
myName = 'kim';
yourName = 'bye';
console.log(typeof myName);
console.log(typeof yourName);
//호이스팅 된 코드
코드 결과를 확인해 보면 두 typeof 모두 'String'을 출력한다.
변수가 선언 -> 함수 선언 -> 마지막으로 값을 kim, bye로 할당했기 때문이다.
//https://www.youtube.com/watch?v=GprF-5Jro08
const test02 = (function(){ //do something })();
const test03 = function(){ //do something };
function test04() { //do something }
import { test05 } from './here';
아래 순서로 적용 범위가 넓다.
test02 -> test03 -> test04 -> test05
test02는 그 자리에서 한 번 실행하고 뒤에서 다시 쓸 수 없음.
그냥 어떤 값을 얻기 위한 로직 블록 정도 역할.
const 유효 범위는 블록 단위.
그 블록 바깥에까지 영향을 미치는 것을 방지함.
고려할 요소가 줄어드니까 뒤 이이서 코드 읽을 때 더 편해지겠지.
test03은 함수를 만들어서 어떤 변수에 넣어 놨으므로 다시 쓸 수 있음.
단, 그 아래로만 가능. 호이스팅 되더라도 선언 부분만 올라가고 할당 부분은 남아있기 때문.
const의 유효 범위, 같은 블록 내에서 자주 쓸 것 같은 함수라면 이렇게 선언해 놓고 아래에서 계속 부르면 좋지.
test04는 해당 자바스크립트 내에서 다 불러다 쓸 수 있음.
호이스팅 될 때 함수 자체를 끌고 옴. (단 변수값은 끌오오지 않음)
test05는 다른 자바스크립트에서 불러다 쓸 수 있음.
아래로 갈수록 영향력이 큼. 그만큼 여기저기서 불러다 쓰고 있을 가능성이 크므로 고치거나 할 때 주의해야겠지.
필요에 따라서 함수 선언 방식을 다르게 하는 게 좋은 코드가 되겠지.