var로 let과 const를 구현할 수 있을까?

Yeji·2023년 12월 21일
0

🔖 Before start

자바스크립트 변수를 설명하면서 "var만을 이용해서 let과 const를 구현할 수 있을까요?"란 질문을 받았다.
한 번도 생각해보지 않은 주제였는데, 꽤 흥미로웠다.
면접이 끝나고도 계속 아른거려서 나름대로 생각한 내용을 기록하려 한다.

우선 가장 기초적인 var, let, const의 차이점은 다음과 같다.

키워드전역스코프재선언재할당
var
let
const

기본적으로 자바스크립트는 함수 레벨 스코프이기 때문에 var 로 선언된 변수는 전역 스코프를 갖는다. (함수가 아니기 때문) 그리고 그런 var의 단점을 보완하고자 이후에 나온 letconst는 블록 레벨 스코프를 갖는다.

또한 var은 재선언 재할당 모두 가능하고 let은 재할당만 가능하며, const는 재선언 재할당 모두 불가하다.

💡 고민

크게 두 가지의 생각을 했다.

1️⃣ letconst의 블록 레벨 스코프
2️⃣ 재선언, 재할당

어떻게 하면 var만으로 이 두 가지를 구현할 수 있을까... 생각했고 다음과 같은 결론을 냈다.

1️⃣ 함수 레벨 스코프를 이용해 지역 스코프를 보장
2️⃣ 클래스의 getter, setter 참고

그리고 다음은 구현 과정에서 참고한 키워드에서 나타날 수 있는 오류다.

var

console.log(foo1) // undefined
var foo1 = 1
console.log(foo1) // 1

let

console.log(foo2) // Reference Error : Cannot access 'foo2' before initialization
let foo2
console.log(foo2) // undefined
foo2 = 2
console.log(foo2) // 2

const

console.log(foo3) // Reference Error : Cannot access 'foo2' before initialization
const foo3 // SyntaxError : Missing initializer
foo3 = 1 // TypeError: Assignment to constant variable

🕹️ 구현

let

  • 즉시 실행 함수를 통해 value의 스코프 보장
  • 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

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)
}

💦 한계

getset 메서드를 사용하지 않고 바로 createLet, createConst에 접근했을 경우 발생할 수 있는 오류를 근본적으로 막지 못한다. var로 선언되었기 때문에 소스코드 평가 과정에서 undefined로 초기화된 값을 참조해버릴 수 있기 때문이다.

또한 해당 값의 재선언을 막지 못한다. var 키워드의 한계다. 현재 내 생각으로는 아무리 생각해도 어렵다. 실제로 letconst를 어떻게 구현했을까 ...

구현 가능 하신 분 hoxy ... ?

profile
채워나가는 과정

0개의 댓글

관련 채용 정보