다음과 같이 변수가 선언되었다.
var 이름; let 나이; const 성별;
이때 var키워드는 재선언이 가능하고, let,const키워드는 재선언이 불가능하다.
다음과 같이 변수에 값이 할당되었다.
let 이름 = 'Kim'; 이름 = 'Park'; //가능 const 나이 = 30; 나이 = 40; //에러
이때 var,let으로 만든 변수에는 재할당이 가능하고, const로 만들면 값 재할당이 불가능하다.(const는 constant로 바뀌지 않느 일정한 값(상수))
만약 const로 오브젝트를 만든다면?
다음과 같이 할당된 객체값 속 '이름'의 값을 변경하는 것이 가능하다.
이는 const변수 자체를 재할당하는 것이 아닌, 변수 속 값에 대한 변경이기 때문이다.const 오브젝트 = { 이름 : 'Kim' } 오브젝트.이름 = 'Park'; //가능
만약 수정 불가능한 오브젝트를 만들고 싶다면?
const 사람 = { 이름 : 'Kim' } Object.freeze(사람); 사람이라는 객체는 수정불가능 설정 사람.이름 = 'Park'; //불가능
var 변수는 존재범위가 function이다. 함수 안에 선언되면 그 함수 안에서만 사용이 가능하다. 즉, 함수 안에서 var로 작성된 선언문이 한번 실행되면 그 함수가 종료되기 전까지 유효.
(함수 이외의 {}문, 또는 어디든 전역변수로 적용된다.)function 함수(){ var 이름 = 'Kim'; console.log(이름); //가능 } console.log(이름); //에러
let, const 변수는 존재범위가 대부분의 {}(중괄호)(for,if,function등)이다.
다음과 같이 if문 안에서는 사용이 가능하지만, 바깥에서는 사용이 불가능하다.if ( 1 == 1 ){ let 이름 = 'Kim'; console.log(이름); //가능 } console.log(이름); //에러
자바스크립트는 변수나 함수를 선언하면 Hoist이라는 현상이 일어난다.
변수나 함수의 선언부분을 변수의 범위 맨 위로 끌고가서 먼저 해석하는 것이다.아래의 경우, 첫번째 콘솔창에서 undefined(정해지지 않은 값), 두번째 콘솔창에서 kim이 출력된다.
일반적으로는 첫번째 콘솔의 이름은 선언과 할당이 이루어지지 않았다고 생각할 수 있지만, 그 위에 var 이름; 과 같이 변수가 선언되어있다고 생각하면 된다.<script> console.log(이름); var 이름 = 'Kim'; console.log(이름); </script>
이렇게도 선언 가능하다는 정도로 알고 넘어가자.
var 이름 = 'Kim', 나이 = 20, 성별 = '남';
변수는 바깥에 있는 경우 안쪽에서 자유롭게 사용이 가능하다는 특징이 있다. 이 것을 전문적인 개발 용어로는 '참조가능'이라고 하고 자바스크립트에서는 클로저(closure)현상이라고 한다.
아래의 코드는 함수를 기준으로 바깥에 변수가 선언되어 있고, 함수 안쪽에서 나이를 출력하려해도 잘 값이 출력될 것이다.
그리고, 전역에서 변수를 선언하는 개념은 window객체에 오브젝트 선언을 해주는 것과 같은 개념이다. 따라서, 'window.나이'는 전역변수 선언과도 같은 맥락이다. 물론 함수도 선언가능하다. 따라서, 큰 프로젝트 안에서 수백가지 변수 선언이 이루어질 때, 구분을 위해 전역변수는 'window.변수'로 많이 표기한다는 것 잊지말자.<script> var 나이 = 20; (window.나이 = 20) function 함수(){ console.log(나이) } </script>
함수(); function 함수() { console.log(안녕); let 안녕 = 'Hello!'; }
함수를 함수선언보다 위에서 호출하였지만, 호이스팅에 의해서 function 함수(){}가 상단으로 이동하므로 함수호출에는 이상이 없다.
그리고 함수 내의 코드를 보면 앞서 보았듯이 변수 선언이 콘솔창 위로 이동하여 콘솔창에서 undefined라는 값이 출력한다고 생각할 수도 있다.
하지만, let,const의 경우 호이스팅은 되지만 undefined가 아닌 에러를 출력한다.
선언과 할당 사이에 시간차가 있어서 생기는 현상인데, let과 const는 엄격하게 사용되는 변수라고 알고 있자. (자세한 설명 참고)
함수(); var 함수 = function() { console.log(안녕); var 안녕 = 'Hello!'; }
1번의 경우 function 함수(){} 자체가 호이스팅되어 함수호출이 이상 없이 되었다. 하지만 2번의 경우 var 함수 = function(){}는 선언부분만 호이스팅 되기 때문에 var = 함수만 상단으로 이동한다. 따라서, 함수를 호출하는 코드에서는 선언은 되었지만, 선언된 것이 함수가 아니라고 생각하고, 함수가 아닌 일반변수에 소괄호를 붙였다고 생각하고 에러가 출력되는 것이다.
let a = 1; var 함수 = function() { a = 2; } console.log(a);
당연히 1이 출력된다. 반드시 함수를 만들어놓고 사용하려면 호출이 되어야 하고, 호출이 됬었다면 let변수는 재할당이 가능하므로 2가 출력됬을 것이다.
let a = 1; var b = 2; window.a = 3; window.b = 4; console.log(a + b);
b의 경우 var b =2 와 window.b = 4가 동일한 기능을 하기 때문에, b가 4로 재할당되었다고 볼 수 있다.
하지만, a의 경우 let 변수로 1을 할당하고, 글로벌 변수로 3을 할당했다. 이때 조금 더 범위가 작고 가까운 1을 참조하여 사용하게 된다. 따라서, a는 1이 출력된다.
for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, i*1000 ); }
위의 코드에서는 1초 후에 i값이 하나씩 반복하여 출력하는 것을 원하고 있다. 이때, setTimeout에 의해서 시간이 지나고 출력이 되기 때문에 반복문과 동시에 실행이 되지 않는다. 즉, 1초가 지나는 시점에 반복문은 이미 i가 0부터 4까지 반복실행을 마치고, i는 4라는 전역변수로 남아있게 된다. 따라서, 4만 반복해서 출력된다.
따라서, for반복문 안에서는 i변수를 만들때 let으로 선언한다. let변수의 범위는 중괄호이고, for문 역시 중괄호에 해당한다. 따라서, i값이 for반복문 안에 남아있기 때문에, 0,1,2,3,4가 차례로 출력할 수 있게 된다.
<div style="display : none">모달창0</div> <div style="display : none">모달창1</div> <div style="display : none">모달창2</div> <button>버튼0</button> <button>버튼1</button> <button>버튼2</button> <script> var 버튼들 = document.querySelectorAll('button'); var 모달창들 = document.querySelectorAll('div'); for (var i = 0; i < 3; i++){ 버튼들[i].addEventListener('click', function(){ 모달창들[i].style.display = 'block'; }); } </script>
위의 코드는 각각 버튼태그를 클릭시 거기에 맞는 모달창이 출력되게 하는 코드이다. 려기서 document.querySelectorAll은 jQuery의 $('') 셀렉터와 매우 유사한 것으로 동시에 여러 요소를 찾아 배열과 비슷한 자료형에 담아주는 것을 말한다. 즉, 비슷한 요소의 버튼태그,div태그들의 정보를 담아준다. 따라서, 반복문을 통해 각각 인덱스를 부여하여 출력시켜준다.
이때, '모달창들'에 대한 값은 클릭이 되면 이루어지는 코드로 늦게 실행이 된다. 따라서, 앞서 본 var의 전역변수 성질로 인해 i는 이미 3이라는 값을 가지고 할당되어 진다.
따라서, var 대신 let을 사용하여 {}안에서 i값들을 사용하면 되겠다.