
해당 글은 프론트 개발자의 기본기 다지기의 첫번째 글입니다.
해당 내용은 개발자(기초는 떼고 오는..)를 위한 내용이기에 문법이나 기초적인 내용은 다루지 않는다.
하지만 처음부터 너무 어려우면 부담스러우니 변수로 가볍게 시작해보자!
어딜가나 변수는 처음이니까...
먼저 자바스크립트의 변수 선언 방식을 보자
var a = 1
var b = ''
var c = {}

굉장한 친구다. 자료형이 무엇이든 var를 붙이면 된다.
아니 사실 안붙혀도 된다.
d = 1
e = ''
f = {}

그렇다면 var과 그냥 선언한 변수는 똑같은가?
function a(){
var b = 'hello'
}
a()
console.log(b)
function a(){
b = 'hello'
}
a()
console.log(b)

두 코드는 다른 결과를 나타낸다. 이유는 변수의 범위 때문이다.
var는 function 안에서 일반 변수는 전역에서 사용이 가능하다.
그냥 선언한 변수가 전역에서 사용이 가능한 것도 신기하지만
어디서 선언을 하든, 전역이다
function이 하나의 범위인것도 참으로 신기한 부분이다.
대부분 언어는 스코프를 범위로 둔다.
따라서 다음과 같은 사용이 가능하다.
if(true){
var test = 'hello'
}
console.log(test)

if 스코프 안에서 선언한 test변수를 밖에서도 접근이 가능하다!
하지만 이는 다른 언어에서 온 개발자들에게는 크게 환영받기 힘든 것이 사실이다.
(나도 스코프 밖에서 사용이 되길래 전역인줄..)
그 때문인지 새로운 범위를 가진 변수선언이 생겨났다. (자그마치 2015년이 되어서야! ES6)
그 친구들은 cosnt, let 이다.
let은 다른 언어들과 비슷하게 같거나 상위 스코프에서 선언된 것만 사용 가능하다.
if(true){
let test = 'hello'
}
console.log(test)

const도 동일한 범위를 가진다. 다른 점이라면 수정을 못한다는 것?
if(true){
const test = 'hello'
}
console.log(test)
const test = '123'
test = 'hh'

javascript의 독특한 점은 이뿐만이 아니다. 또 다른 점은 호이스팅(Hoisting)이다.
호이스팅이란, 선언된 변수들을 해당 범위 최상단으로 올리는 것을 말한다.
console.log(a)
var a = ''
console.log(b)
let b = ''

분명 두 친구 다 먼저 사용하고 나중에 선언을 하였지만 var로 선언된 a는 호이스팅이 되어 콘솔을 찍었을떄 undefined가 된다.
javascript에서 undefined란, 변수가 선언되었지만 초기 값이 없을때 실행프로그램이 넣어주는 초기화 값이다.
변수는 선언되고 안에 값은 없는 것이다.
하지만 b변수의 경우 아에 정의되지 않았다고 오류를 뿜는다.
여기서 재밌는 사실! 사실 이번 챕터는 변수지만 함수의 호스팅도 잠시 이야기 하자면
foo();
foo2();
function foo() { // 함수선언문
console.log("hello");
}
var foo2 = function() { // 함수표현식
console.log("hello2");
}

함수 선언문은 호이스팅이 되지만 함수 표현식은 호이스팅이 되지 않는다!
정확하게는 둘다 호이스팅이 된다. 하지만 함수 표현식은 함수 자체가 아닌 변수만 호이스팅이 된다는거..

호이스팅 우선순위는 다음과 같다.
변수 선언 > 함수 선언문 > 변수값 할당
따라서 다음과 같은 결과가 나타나게 된다.
var myName = "hi";
function myName() {
console.log("yuddomack");
}
function yourName() {
console.log("everyone");
}
var yourName = "bye";
console.log(typeof myName);
console.log(typeof yourName);

함수가 변수 대입보다 위로 호이스팅 되기 때문에 나중에 myName은 함수 → 변수로 값이 바뀌게 된다.
이러한 변수의 범위를 이용하여 JS에 없는 private 변수를 만들 수 있다.
그러기 위해서는 그 전에 closure에 대해 배워야 한다.
다음 코드를 한번 살펴보자
function makeAdder(x) {
var y = 1;
return function(z) {
y = 100;
return x + y + z;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
//클로저에 x와 y의 환경이 저장됨
console.log(add5(2)); // 107 (x:5 + y:100 + z:2)
console.log(add10(2)); // 112 (x:10 + y:100 + z:2)
//함수 실행 시 클로저에 저장된 x, y값에 접근하여 값을 계산
해당 코드를 실행하면 어떠한 결과가 나올것으로 예상되는가?
놀랍게도..

이것이 왜 놀라운가?
add5 변수(정확하게는 함수 포인터를 가진 변수)와 add10변수는 함수의 포인터는 물론이거니와, 함수에 들어가는 매개변수의 값들까지도 가지고 있다는 것이다.
이것이 가능한 이유? C#이나 C++등의 언어들은 코드는 코드 영역지만 JS에서 함수는 힙에 저장이 된다.
따라서 매개변수까지 통재로 힙에 저장해 버리는 것.
var test = 100
function makeAdder(x) {
var y = 1;
return function(z = test) {
y = 100;
return x + y + z;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5()); //205
console.log(add10()); //210
test = 10
console.log(add5()); // 115
console.log(add10()); // 120
console.log(add5(5)); //110
console.log(add10(10)); //120

다음과 같이 지역 변수들이 저장 된다.
이때 전역변수는 같이 저장되지 않는다.
var test = 100
y = 0;
function makeAdder(x) {
y++;
return function(z = y) {
return x + y + z;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5()); //9 2(y) + 5 + 2(y)
console.log(add10()); //14 4(2y) + 10

이때 var변수는 function 범위 안에서만 유요함으로 function안에서 var 변수를 선언하면 그 값이 그대로 보존이 되며 다른 곳에서 함수를 실행해도 해당 값은 보존된다.
이러한 성질을 이용하면 다음과 같은 코드를 작성 할 수 있다.
var counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
};
})();
console.log(counter.value()); // logs 0
counter.increment();
counter.increment();
console.log(counter.value()); // logs 2
counter.decrement();
console.log(counter.value()); // logs 1

여기서 privateCounter는 var 변수이기에 외부에서 접근을 못한다. 하지만 내부 getter 및 setter로 값을 증가 또는 감소 시킬 수 있으며 불러오는 것도 가능하다.
다음 시간엔 이렇게 놀라운 자바스크립트를 실행하는 엔진들에 대해 알아보자.
잘 봤습니다!
var 과 let, const의 차이에 대해서 좀 더 다뤘으면 좋았을 것 같다는 생각도 드네요.
스코프의 차이와 TDZ 관련된 내용이 떠올라서요.
앞으로도 잘 보겠습니다 감사합니다!