자바스크립트(JavaScript) 언어의 특성 몇 가지 정리

2022. 8. 11. 20:55Front-end/JavaScript


자바스크립트는 느슨한 타입(loosely typed)의 동적(dynamic) 언어다.
자바스크립트의 변수는 어떤 특정 타입과 연결되지 않으며, 모든 타입의 값으로 할당 및 재할당이 가능하다.

 

자바스크립트는 타입이 매우 유연한 언어다. 너무 유연해서 탈이다

함수와 연산자에 전달되는 값은 대부분 적절한 자료형으로 자동 변환된다. 이런 과정을 형 변환이라고 한다.

Window.alert() 메서드가 전달받은 값의 자료형과 관계없이 문자열로 변환하여 보여주는 것이나, 수학 관련 연산자가 전달받은 값을 숫자로 변환하는 경우가 형 변환의 대표적인 예라고 볼 수 있다.

 

전달받은 값을 의도를 갖고 원하는 타입으로 변환(명시적 변환)하는 경우도 형 변환이라고 할 수 있다.

자바스크립트 엔진은 필요에 따라 암시적 변환, 명시적 변환을 실행한다.

암시적 변환 : 자바스크립트 엔진이 필요에 따라 자동으로 데이터 타입을 변환시키는 것
명시적 변환 : 개발자가 의도를 가지고 데이터 타입을 변환시키는 것

 

자바스크립트는 엄격한 비교와 유형 변환 비교를 모두 지원하므로, 어떤 연산자가 어떤 비교조건에 사용되는지가 중요하다. 
'==='은 변수의 타입까지 고려하는 반면,  '=='은 변수의 값만을 고려한다.

'==' : 두 변수의 값을 비교한다
'===' : 두 변수의 값과 타입까지 비교한다

 

문제점 : 실행 도중에 변수에 예상치 못한 타입이 들어와 타입 에러가 발생할 수 있다.
동적 타입 언어는 런타임 시 확인할 수밖에 없기 때문에, 코드가 길고 복잡해질 경우 타입 에러를 찾기가 어렵다. 

 

보완 방법 : 타입스크립트(TypeScipt)를 사용해 변수에 타입을 명시해준다.

타입스크립트(TypeScript)는 자바스크립트(JavaScript)를 기반으로 정적 타입 문법을 추가한 프로그래밍 언어다.

 

undefined은 변수를 선언하고 값을 할당하지 않은 상태, null은 변수를 선언하고 빈 값을 할당한 상태(빈 객체)이다. 
즉, undefined는 자료형이 없는 상태이다.

typeof를 사용해 자료형을 확인해보면 null은 object로, undefined는 undefined가 출력되는 것을 확인할 수 있다.

console.log(typeof null); // object
console.log(typeof undefined); // undefined

 

 



기본형 타입(Primitive Type) 참조형 타입(Reference Type)
숫자(Number)
문자열(String)
불리언(Boolean)
null
undefined
심볼(Symbol)
객체(Object)
배열(Array)
함수(Function)
날짜(Date)
정규표현식(RegExp)
Map
WeakMap
Set
WeakSet
기본형 데이터는 값을 그대로 할당하는 것이다.
메모리 내에 고정된 크기로 저장되고, 원시 데이터 값 자체를 보관한다.
참조형은 기본형 데이터의 집합이다.
참조형 데이터는 값이 지정된 주소의 값을 할당한다.

 

불변 객체변하지 않는 객체를 말한다. 즉, 이미 할당된 객체가 변하지 않는다는 뜻이다.

자바스크립트 const 선언 방식과 Object.freeze() 메서드를 사용해 불변 객체를 만들 수 있다.

 

const 선언은 블록 범위의 상수를 선언한다. 상수의 값은 재할당할 수 없으며 다시 선언할 수도 없다.

const user = {};
user.name = "kh";

console.log(user);  // {"kh"}

ES6에서의 const는 할당된 값이 상수가 되는 것이 아닌 바인딩된 값이 상수가 된다. 그래서 user 변수가 상수가 되기 때문에 const 키워드로 선언된 user 변수에는 객체 재할당은 불가능하지만 객체의 속성은 변경 가능하다.

 

객체 재할당이 불가능 한 이유는 변수와 값(객체) 사이의 바인딩 자체가 변경이 되기 때문에 상수인 user 변수는 재할당이 불가능한 것이고, 객체의 속성이 변경 가능한 이유는 실제 객체가 변경은 되지만 객체와 변수 user 사이의 바인딩은 변경이 되지 않기 때문에 객체의 속성은 변경 가능한 것이다.

 

비록 재할당은 불가능하지만 객체의 속성을 변경함으로 인해 변수에 바인딩된 객체의 내용까지 변경이 되기 때문에 불변 객체라고 보기는 힘들다. 이번엔 Object.freeze() 메서드를 함께 사용해보자.

 

Object.freeze() 메서드는 객체를 동결한다. 동결된 객체는 더 이상 변경될 수 없다. 즉, 동결된 객체는 새로운 속성을 추가하거나 존재하는 속성을 제거하는 것을 방지하며 존재하는 속성의 불변성, 설정 가능성(configurability), 작성 가능성이 변경되는 것을 방지하고, 존재하는 속성의 값이 변경되는 것도 방지한다. 또한, 동결 객체는 그 프로토타입이 변경되는 것도 방지한다. freeze()는 전달된 동일한 객체를 반환한다.

const obj = {
  prop: 42
};

Object.freeze(obj);

obj.prop = 33; // Throws an error in strict mode

console.log(obj.prop); // expected output: 42

Object.freeze(obj)를 사용해 바인딩된 변수를 동결 객체로 만들었다. 이제 obj 객체는 객체의 속성을 변경하는 시도는 불가능하다. Object.freeze() 메서드는 동결된 객체를 반환하지만 객체의 재할당은 가능하다. 그래서 Object.freeze()도 불변 객체라고 할 수는 없을 것 같다.

 

결론적으로 불변 객체는 const와 Object.freeze()를 조합하여 만들 수 있다.

(const의 재할당 불가 + Object.freeze()의 객체 속성 변경 불가)

const 선언 방식으로 바인딩된 변수를 상수화 시키고 Object.freeze()로 해당 변수를 동결 객체로 만들면 객체의 재할당과 객체의 속성 둘 다 변경이 불가능한 불변 객체가 된다.

 

📌얕은 복사(Shallow Copy)

  • 객체를 복사할 때 해당 객체만 복사하여 새 객체를 생성한다.
  • 복사된 객체의 인스턴스 변수는 원본 객체의 인스턴스 변수와 같은 메모리 주소를 참조한다.
  • 즉, 해당 메모리 주소의 값이 변경되면 원본 객체 및 복사 객체의 인스턴스 변수 값은 같이 변경된다.
const obj = { vaule: 1 }
const copyObj = obj;

copyObj.vaule = 2;

console.log(obj.vaule); // 2
console.log(obj === copyObj); // true

obj 객체를 새로운 copyObj 객체에 할당했으며 이를 참조 할당이라 부른다. 복사 후 copyObj 객체의 value 값을 변경했더니 기존의 obj.value 값도 같이 변경된 것을 알 수 있다. 두 객체를 비교해도 true로 나온다. 이렇게 자바스크립트의 참조 타입은 얕은 복사가 된다고 볼 수 있다. 데이터가 그대로 생성되는 것이 아닌 해당 데이터의 참조 값(메모리 주소)을 전달하여 결국 한 데이터를 공유하는 것이다.

 

📌깊은 복사(Deep Copy)

  • 객체를 복사할 때, 해당 객체와 인스턴스 변수까지 복사하는 방식이다.
  • 전부를 복사하여 새 주소에 담기 때문에 참조를 공유하지 않는다.
let a = 1;
let b = a;

b = 2;

console.log(a); // 1
console.log(b); // 2
console.log(a === b); // false

변수 a를 새로운 b에 할당했고 b의 값을 변경해도 기존 a의 값은 변경되지 않는다. 두 값을 비교하면 false가 출력되며 서로의 값이 단독으로 존재하는 것을 알 수 있다. 이렇게 자바스크립트의 원시 타입은 깊은 복사가 된다. 독립적인 메모리에 값 자체를 할당하여 생성하는 것이라 볼 수 있다.

 

 



스코프는 변수, 함수, 클래스가 접근할 수 있는 유효 범위로 참조 대상 식별자(identifier, 변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 구분하여 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙이다. 

 

자바스크립트에서 스코프를 구분해보면 다음과 같이 두 가지로 나눌 수 있다.

전역 스코프 (Global scope)
코드 어디에서든지 참조할 수 있다.

지역 스코프 (Local scope or Function-level scope)
함수 코드 블록이 만든 스코프로 함수 자신과 하위 함수에서만 참조할 수 있다.

모든 변수는 스코프를 갖는다. 변수의 관점에서 스코프를 구분하면 다음과 같이 두 가지로 나눌 수 있다.

전역 변수 (Global variable)
전역에서 선언된 변수이며 어디에든 참조할 수 있다.

지역 변수 (Local variable)
지역(함수) 내에서 선언된 변수이며 그 지역과 그 지역의 하부 지역에서만 참조할 수 있다.

변수는 선언 위치에 의해 스코프를 가지게 된다. 즉, 전역에서 선언된 변수는 전역 스코프를 갖는 전역 변수이고, 지역(자바스크립트의 경우 함수 내부)에서 선언된 변수는 지역 스코프를 갖는 지역 변수가 된다.

 

전역 스코프를 갖는 전역 변수는 전역에서 참조할 수 있다. 지역에서 선언된 지역 변수는 그 지역과 그 지역의 하부 지역에서만 참조할 수 있다.

 

호이스팅은 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미한다.
  • 호이스팅은 코드를 실행하기 전 변수 선언/함수 선언을 해당 스코프의 최상단으로 끌어올리는 것이 아니다.
  • 호이스팅은 코드가 실행하기 전 변수 선언/함수 선언이 해당 스코프의 최상단으로 끌어올려진 것 같은 현상을 말한다.
  • 자바스크립트 엔진은 코드를 실행하기 전 실행 가능한 코드를 형상화하고 구분하는 과정(*실행 컨텍스트를 위한 과정)을 거친다.
  • 자바스크립트 엔진은 코드를 실행하기 전 실행 컨텍스트를 위한 과정에서 모든 선언(var, let, const, function, class)을 스코프에 등록한다.
  • 코드 실행 전 이미 변수 선언/함수 선언이 저장되어 있기 때문에 선언문보다 참조/호출이 먼저 나와도 오류 없이 동작한다. (정확히는 var 키워드로 선언한 변수와 함수 선언문일 경우 오류 없이 동작한다. 이는 선언이 파일의 맨 위로 끌어올려진 것처럼 보이게 한다.)
  • *실행 컨텍스트는 실행 가능한 코드가 실행되기 위해 필요한 환경을 의미하고 실행되기 전 이러한 실행 컨텍스트 과정(코드를 구분하는 과정)을 거친다.
이 호이스팅이라는 용어를 자바스크립트 실행 컨텍스트에 의한 위에 설명한 현상을 호이스팅이라고 부른다는 것으로 이해하면 되겠다. 그 현상이란 선언이 코드 실행보다 먼저 메모리에 저장되는 과정으로 인한 현상을 말한다.

그래서 자바스크립트 실행 컨텍스트에 대한 이해하는 것이 호이스팅을 이해하는데 도움이 된다. (scope, hoisting, this, function, closure 등의 동작원리를 담고 있는 자바스크립트 핵심원리이다. 코드를 보고 실행 컨텍스트를 이해할 수 있어야 코드 독해, 디버깅을 할 수 있다.)
  • 자바스크립트의 모든 선언에는 호이스팅이 일어난다.
  • 그런데 let, const, class를 이용한 선언문을 호이스팅이 발생하지 않는 것처럼 동작한다.
  • var 키워드로 선언된 변수와는 달리 let 키워드로 선언된 변수를 선언문 이전에 참조하면 참조 에러(ReferenceError)가 발생한다.
  • 이는 let 키워드로 선언된 변수는 스코프의 시작에서 변수의 선언까지 *일시적 사각지대(Temporal Dead Zone; TDZ)에 빠지기 때문이다.
여기서 중요한 지점은 이 호이스팅이라는 용어가 ‘선언이 먼저 메모리에 저장되었다.’는 것을 의미하기 때문에 즉, ‘선언이 끌어올려진다’는 의미이기 때문에 모든 선언은 호이스팅이 일어난다는 말은 참이 된다.

즉, 호이스팅이 파일의 맨 위로 끌어올려진 것 같은 현상을 의미할 때 선언문 이전에 참조해서 에러를 발생시킨다고 호이스팅이 일어나지 않은 것은 아니라는 의미이다.
  • 왜냐하면 정말 선언은 끌어올려진 것이 맞다. (표현하면 그렇고 정확히는 선언이 코드 실행 전에 메모리에 저장되었다는 의미이다.)
  • 그런데 왜 오류가 나는가 하면 var 키워드는 선언과 함께 undefined로 초기화되어 메모리에 저장되는데 let과 const는 초기화되지 않은 상태로 선언만 메모리에 저장되기 때문이다.
  • 초기화되지 않으면 변수를 참조할 수 없다. 그래서 참조 에러를 일으키는 것이다.
  • let과 const에도 호이스팅이 일어나기 때문에 에러를 일으키는 것이다.
  • 호이스팅이 일어나지 않는다면 아래 코드에서 에러가 발생하지 않을 것이다.
  • 선언이 호이스팅되었기 대문에 블록 스코프에서 foo를 찾을 수 없는 것이다.
let foo = 1;
{
  console.log(foo);
  let foo = 2;
}

호이스팅이 ‘현상’을 의미하는 것이라면 변수 키워드 중 var 만이 에러 없이 변수 선언이 상단으로 끌어올려지는 것 같은 ‘현상’이 일어나기 때문에 var 만이 호이스팅이 일어난다고 생각했다.
하지만 위 예시에서 알 수 있었고 자바스크립트 엔진이 동작하는 방식을 알고 보니 let 키워드에서도 상단으로 끌어올려진 것 같은 ‘현상(즉, 호이스팅)’이 발생했기 때문에 에러가 발생하는 것이라는 것을 알게 되었다.
(에러가 난다고 호이스팅이 되지 않은 것이 아닌, 호이스팅이 발생했기 때문에 에러가 발생한 것이다.)

 

TDZ (Temporal Dead Zone)

TDZ는 const, let, class 구문의 유효성에 영향을 미치는 중요한 개념이다. TDZ는 선언 전에 변수를 사용하는 것을 허용하지 않는다. 즉, 초기화되지 않은 변수가 있는 곳을 Temporal Dead Zone이라고 한다.

 

변수의 생성 단계와 호이스팅 그리고 TDZ (접은 글 참조)
더보기
  • 변수는 3단계에 걸쳐 생성된다.

1단계: 선언 단계(Declaration phase)

  • 변수를 실행 컨텍스트의 변수 객체에 등록한다.
  • 이 변수 객체는 스코프가 참조하는 대상이 된다.

2단계: 초기화 단계(Initialization phase)

  • 변수 객체에 등록된 변수를 위한 공간을 메모리에 확보한다.
  • 이 단계에서 변수는 undefined로 초기화 된다.

3단계: 할당 단계(Assignment phase)

  • undefined로 초기화된 변수에 실제 값을 할당한다.

var 키워드로 선언한 변수는 선언 단계와 초기화 단계가 한 번에 이뤄진다. 즉, 스코프에 변수를 등록(선언 단계)하고 메모리에 변수를 위한 공간을 확보한 후, undefined로 초기화한다. 따라서 변수 선언문 이전에 변수에 접근하여도 스코프에 변수가 존재하기 때문에 에러가 발생하지 않는다. 다만 undefined를 반환한다. 이후 변수 할당 문에 도달하면 비로소 값이 할당된다.

let 키워드로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 진행된다. 즉, 스코프에 변수를 등록(선언 단계)하지만 초기화 단계는 변수 선언문에 도달했을 때(코드 실행 후) 이뤄진다. 초기화 이전에 변수에 접근하려고 하면 참조 에러가 발생한다. 이는 아직 변수가 초기화되지 않았기 때문이다. 즉, 변수를 위한 메모리 공간이 아직 확보되지 않았기 때문이다. 따라서 스코프의 시작 지점부터 초기화 시작 지점까지는 변수를 참조할 수 없다. 스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 일시적 사각지대(Temporal Dead Zone; TDZ)라고 부른다.

 

함수 선언식 (function declartion)

함수명이 정의되어 있고 별도의 할당 명령이 없는 것으로 일반적인 프로그래밍 언어에서의 함수 선언과 비슷한 방식

function sum(a,b) {
    return a + b;
}

함수 표현식 (function Expression)

정의한 함수를 별도의 변수에 할당하는 것으로 유연한 자바스크립트 언어의 특징을 활용한 선언 방식

const sum = function(a,b) {
    return a + b;
}

함수 선언식과 표현식의 호이스팅

함수 선언식은 호이스팅에 영향을 받지만, 함수 표현식은 호이스팅에 영향을 받지 않는다.

foo1(); // 함수 선언식은 호이스팅이 일어난다
foo2(); // 함수 표현식은 호이스팅이 안된다

function foo1() {
  console.log('함수 선언식');
}

let foo2 = function() {
  console.log('함수 표현식');
}

위 코드 실행 시 출력 내용

foo2(); // 함수 표현식이라서 호이스팅이 안된다
^

ReferenceError: Cannot access 'foo2' before initialization

 

Execution Context(실행 컨텍스트)는 scope와 hoisting, this, closure 등을 관통하는 가장 근본적인 개념이다. 자바스크립트 코드의 실행 흐름과 코드에 대한 정보가 Execution Context로 관리되기 때문에 Execution Context를 이해하지 못하면 부수적인 개념들에 대해서도 완벽하게 이해할 수 없다.

 

자바스크립트 엔진이 코드를 실행하기 위해선 코드에 대한 정보들이 필요하다. 코드에 선언된 변수와 함수, 스코프, this, arguments 등을 묶어, 코드가 실행되는 위치를 설명한다는 뜻의 Execution Context(실행 컨텍스트)라고 부른다. 자바스크립트 엔진은 Execution Context를 객체로 관리하며 코드를 Execution Context 내에서 실행한다.

 

Execution Context(실행 컨텍스트)의 종류는 대표적으로 두 가지가 있다.

  1. Global Execution Context
    자바스크립트 엔진이 처음 코드를 실행할 때 한 개만 정의되는 전역 컨텍스트로 Global Execution Context가 생성된다. 생성 과정에서 전역 객체인 Window Object (Node는 Global)를 생성하고 this가 Window 객체를 가리키도록 한다. 전역 실행 컨텍스트는 Call Stack에 가장 먼저 추가되며 앱이 종료될 때 삭제된다.
  2. Function Execution Context
    자바스크립트 엔진은 함수가 호출될 때마다 호출된 함수를 위한 Execution Context를 생성한다.
    모든 함수는 호출되는 시점에 자신만의 Execution Context를 가진다. 함수 실행 컨텍스트는 매 실행시마다 정의되며 함수 실행이 종료(return)되면 Call Stack에서 제거됩니다.

 

Call Stack(콜 스택) - 코드가 실행되면서 생성되는 Execution Context를 저장하는 자료구조

자바스크립트 엔진이 처음 코드를 실행할 때, Global Execution Context를 생성하고 이를 Call Stack에 삽입(push)한다.

그 후 엔진이 함수를 호출할 때마다 함수를 위한 Function Execution Context를 생성하고 이를 Call Stack에 삽입(push)한다.

자바스크립트 엔진은 Call Stack의 Top(가장 최근에 실행된)에 위치한 함수를 실행하며 함수가 종료되면 Call Stack에서 제거(pop)하고 제어를 다음 Top(스택의 후입 선출에 의한 과정)에 위치한 함수로 이동한다.

자바스크립트 엔진은 생성된 Context를 관리하는 목적의 Call Stack을 갖고 있다. 자바스크립트는 단일 스레드 형식이기 때문에 런타임에 단 하나의 Call Stack이 존재한다.

 

Call Stack은 최대 stack 사이즈가 정해져 있다. Call Stack에 쌓인 Context Stack이 최대치를 넘게 될 경우 ‘RangeError: Maximum call stack size exceeded’라는 에러가 발생한다. 이 에러를 흔히 Stack Overflow(스택 오버플로)라고 부른다.

 

스코프 체인

스코프에 식별자가 없으면 상위 스코프에서 다시 찾아 나간다. 
이 현상을 스코프 체인이라고 하며 스코프가 중첩되어있는 모든 상황에서 발생한다.

더보기

자바스크립트에서 전역 변수는 전역 객체의 property이다.

지역 변수는 그런 규정이 없지만 변수를 각 함수 호출과 연관된 객체(call object)의 property로 생각할 수 있다.

 

지역 변수를 어떤 객체의 property로 생각한다면, 자바스크립트의 모든 코드는 스코프 체인을 갖고 있다. 

스코프 체인은 해당 코드의 유효 범위 안에 있는 변수를 정의하는 객체의 체인, 리스트다.

 

자바스크립트가 변수 값을 얻으려고 할 때(variable resolution, 변수 해석) 스코프 체인에서 변수를 찾는다. 스코프 체인은 위에서 말했다시피 객체의 리스트이므로, 첫 번째 객체에서 해당 변수를 찾고, 없으면 그다음 객체에서 해당 변수를 찾고, 그래도 없으면 그다음 객체에서 찾는 식이다. 리스트의 끝까지 탐색했는데도 그 변수가 없다면 reference error가 발생하는 것이다.

 

최상위 자바스크립트 코드(어떠한 함수에도 속하지 않는 코드)의 스코프 체인에는 하나의 객체만 있고, 그것이 전역 객체이다. 중첩되지 않은 함수의 스코프 체인은 두 개의 객체로 이루어진다. 하나는 함수의 매개변수와 지역 변수를 정의하는 객체고, 다른 하나는 전역 객체다.

 

함수가 정의될 때, 함수는 스코프 체인을 저장하고, 함수가 호출될 때 함수는 지역 변수를 보관하는 새로운 객체를 만들고 그 객체를 기존에 만들어둔 스코프 체인에 추가한다.

 

변수 은닉화

외부 객체로부터 '속성 값(데이터, 멤버 변숫값)'을 감추는 특성이다.

더보기

IIFE(즉시 실행 함수 호출)을 활용을 하면, 함수를 통해 변수에 대한 접근을 은닉화를 할 수 있다.

(function () {
  let a = 'a';
})();

console.log(a); // ReferenceError: a is not defined

함수 외부에서 a를 출력해보면, 아직 정의되지 않았다(a is not defined)는 에러 메시지를 확인할 수 있다. 이러한 방식과 같이 직접적으로 변경되면 안 되는 변수에 대한 접근을 막는 것을 은닉화라고 한다.

 

클로저를 통한 은닉화

자바스크립트에서 일반적인 객체지향 프로그래밍 방식으로 prototype를 사용하는데 객체 안에서 사용할 속성을 생성할 때 this 키워드를 사용한다.

하지만 prototype을 통한 객체를 만들 때의 문제가 하나 있다. Private variables에 대한 접근 권한 문제다.

function hi(name) {
  this._name = name;
}

hi.prototype.say = function () {
  console.log(`hi, ${this._name}`);
};

let a = new hi("kh");
let b = new hi("ys");

a.say(); // hi, kh
b.say(); // hi, ys

a._name = "anonymous";
a.say(); // hi, anonymous

위 코드에서 hi() 함수를 통해 생성된 객체들은 모두 _name이라는 변수를 가진다. 변수명 앞에 underscore(_)를 포함했기 때문에 일반적인 자바스크립트 네이밍 컨벤션을 생각해 봤을 때 이 변수는 Private variable으로 쓰고 싶다는 의도를 알 수 있다.

하지만 여전히 외부에서도 쉽게 접근 가능한 것을 확인할 수 있다. 이 경우 클로저를 사용해 외부에서 직접적으로 변수에 접근할 수 있도록 은닉화할 수 있다.

function hi(name) {
  let _name = name;
  return function () {
    console.log(`hi, ${this._name}`);
  };
}

let a = new hi("kh");
let b = new hi("ys");

a(); //hi, kh
b(); //hi, ys

이렇게 a와 b라는 클로저를 생성함으로써 함수 내부적으로 접근이 가능하도록 만들 수 있다.

 

function a() {
  let temp = "a";

  return temp;
}

console.log(temp) // ReferenceError: temp is not defined

const result = a();
console.log(result); // a

 위 코드에서 함수 내부적으로 선언된 temp에는 직접적으로 접근을 할 수 없다. 함수 a를 실행시켜 그 값을 result라는 변수에 담아 클로저를 생성함으로써 temp의 값에 접근이 가능하다. 이렇게 함수 안에 값을 숨기고 싶은 경우 클로저를 활용해볼 수 있다.

 

 



let b = 1;
function test() {
  const a = 1;
  let b = 100;
  b++;
  console.log(a, b);
  // const, let 선언 변수는 블럭 스코프에서 유효함으로 지역 변수 값을 출력
}

// console.log(a); 전역 스코프를 갖는 a라는 변수가 존재하지 않아 에러

console.log(b); // 1
// 전역 변수 b의 값을 출력

test(); // 1, 101
// 함수 내부 지역 변수 a, b의 값을 출력

console.log(b); // 1
// 전역 변수 b의 값을 출력

console.log(a)의 주석을 풀고 실행 시

console.log(a);
            ^

ReferenceError: a is not defined

다음과 같이 에러를 발생한다.

반응형