🔖 Before start
자바스크립트 변수를 설명하면서 "var만을 이용해서 let과 const를 구현할 수 있을까요?"란 질문을 받았다.
한 번도 생각해보지 않은 주제였는데, 꽤 흥미로웠다.
면접이 끝나고도 계속 아른거려서 나름대로 생각한 내용을 기록하려 한다.
우선 가장 기초적인 var
, let
, const
의 차이점은 다음과 같다.
키워드 | 전역스코프 | 재선언 | 재할당 |
---|---|---|---|
var | ✅ | ✅ | ✅ |
let | ❌ | ❌ | ✅ |
const | ❌ | ❌ | ❌ |
기본적으로 자바스크립트는 함수 레벨 스코프이기 때문에 var
로 선언된 변수는 전역 스코프를 갖는다. (함수가 아니기 때문) 그리고 그런 var
의 단점을 보완하고자 이후에 나온 let
과 const
는 블록 레벨 스코프를 갖는다.
또한 var
은 재선언 재할당 모두 가능하고 let
은 재할당만 가능하며, const
는 재선언 재할당 모두 불가하다.
크게 두 가지의 생각을 했다.
1️⃣ let
과 const
의 블록 레벨 스코프
2️⃣ 재선언, 재할당
어떻게 하면 var
만으로 이 두 가지를 구현할 수 있을까... 생각했고 다음과 같은 결론을 냈다.
1️⃣ 함수 레벨 스코프를 이용해 지역 스코프를 보장
2️⃣ 클래스의 getter, setter 참고
그리고 다음은 구현 과정에서 참고한 키워드에서 나타날 수 있는 오류다.
console.log(foo1) // undefined
var foo1 = 1
console.log(foo1) // 1
console.log(foo2) // Reference Error : Cannot access 'foo2' before initialization
let foo2
console.log(foo2) // undefined
foo2 = 2
console.log(foo2) // 2
console.log(foo3) // Reference Error : Cannot access 'foo2' before initialization
const foo3 // SyntaxError : Missing initializer
foo3 = 1 // TypeError: Assignment to constant variable
get
메서드로 value 값에 접근set
메서드로 value 값 할당var createLet = (function () {
var value
return {
get: function () {
return value
},
set: function (newValue) {
value = newValue
},
}
})()
📍 값을 할당하지 않았을 경우
console.log(createLet.get()) // undefined
📍 원시 타입 할당
createLet.set(2)
console.log(createLet.get()) // 2
createLet.set(3)
console.log(createLet.get()) // 3
📍 객체 타입 할당
createLet.set([1])
console.log(createLet.get()) // [1]
createLet.get().push(3)
console.log(createLet.get()) // [1,3]
const
는 선언과 동시에 할당이 이루어지기 때문에 변수를 선언할 때 값을 필수로 할당해야 한다.
value === undefined
) SyntaxError ~
를 콘솔에 출력한다.TypeError ~
를 콘솔에 출력한다.var createConst = (function () {
var value = 'required value' // 필수값
return {
get: function () {
if (value === undefined) throw new Error('Missing initializer')
return value
},
set: function () {
throw new Error('Assignment to constant variable')
},
}
})()
📍 값을 할당하지 않았을 때
var createConst = (function () {
var value // 값 할당 없음
return {
get: function () {
if (value === undefined) throw new Error('Missing initializer')
return value
},
set: function () {
throw new Error('Assignment to constant variable')
},
}
})()
try {
createConst.get()
} catch (error) {
console.log(error) // Error: Missing initializer
}
📍 재할당 시도했을 때
var createConst = (function () {
var value = 'initial value'
return {
get: function () {
if (value === undefined) throw new Error('Missing initializer')
return value
},
set: function () {
throw new Error('Assignment to constant variable')
},
}
})()
try {
createConst.set('new value')
} catch (error) {
console.log(error) // Error: Assignment to constant variable
}
📍 원시 타입 할당
var value = 'primitive type'
try {
console.log(createConst.get()) // primitive type
} catch (error) {
console.log(error)
}
📍 객체 타입 할당
객체 타입 데이터는 const
로 선언되어도 메모리의 힙영역에 저장되기 때문에 내부 값을 변경할 수 있다.
var value = { key: 'key', value: 'value' }
try {
console.log(createConst.get()) // { key: 'key', value: 'value' }
createConst.get().key = 'new key'
console.log(createConst.get()) // { key: 'new key', value: 'value' }
} catch (error) {
console.log(error)
}
get
과 set
메서드를 사용하지 않고 바로 createLet
, createConst
에 접근했을 경우 발생할 수 있는 오류를 근본적으로 막지 못한다. var
로 선언되었기 때문에 소스코드 평가 과정에서 undefined
로 초기화된 값을 참조해버릴 수 있기 때문이다.
또한 해당 값의 재선언을 막지 못한다. var
키워드의 한계다. 현재 내 생각으로는 아무리 생각해도 어렵다. 실제로 let
과 const
를 어떻게 구현했을까 ...
구현 가능 하신 분 hoxy ... ?