- 인터프리터가 코드를 실행하기 전에 함수, 변수, 클래스 또는 임포트의 선언문을 해당 범위의 맨 위로 이동시키는 과정
- 변수 호이스팅(Variable Hoisting)은 JavaScript에서 변수 선언이 코드의 맨 위로 끌어올려지는 동작을 나타냅니다. JavaScript 엔진이 코드를 실행하기 전에 변수 선언을 모두 수집하고 메모리에 할당하는 방식으로 작동합니다.
- 주로 JavaScript에서 호이스팅은 주로 변수 호이스팅과 함수 호이스팅으로 구분됨
1) 변수 호이스팅 : 변수 선언을 현재 스코프의 맨 위로 끌어올림. 변수 호이스팅은 주로
var
키워드로 선언된 변수에서 나타나며, let 및 const로 선언된 변수에서는 호이스팅이 발생하지만 블록 스코프를 따르기 때문에 범위가 블록 내로 제한됨
2) 함수 호이스팅 : 함수 선언문은 해당 함수를 현재 스코프의 맨 위로 끌어올린다. 이것은 함수를 선언하기 전에 함수를 호출할 수 있도록 한다. 함수 호이스팅은 모든 종류의 함수 선언에 적용되며, 함수 표현식에서는 호이스팅이 발생하지 않는다.
- null: null은 JavaScript에서 값이 없음을 나타내는 특별한 값이다. 변수나 객체 프로퍼티 등을 명시적으로 값이 없음을 나타내고자 할 때 사용된다.
- undefined : undefined는 변수가 선언되었지만 값이 할당되지 않았을 때 나타나는 상태입니다. 또한 함수의 매개변수 중 값이 주어지지 않은 경우나, 객체의 프로퍼티가 존재하지 않는 경우에도 발생합니다.
- undeclared: 변수가 선언되지 않은 상태를 나타낸다. 이런 변수는 스코프 내에서 찾을 수 없으므로 사용하려고 하면 ReferenceError가 발생한다.
이런 상태들을 확인하는 방법- null 확인: null인지 확인하려면 일치 연산자(===)를 사용하여 null과 비교. typeof 연산자를 사용하여 null을 확인하면 'object'가 반환되므로, null과 다른 객체 유형을 구분하기 위해 추가적인 검사가 필요.
- undefined 확인: undefined인지 확인하려면 일치 연산자(===)나 동등 연산자(==)를 사용하여 undefined와 비교합니다. typeof 연산자를 사용한 비교
- undeclared 확인: "undeclared" 변수인지 확인하려면 변수를 사용하기 전에 선언하거나, 변수가 선언되었는지 여부를 조건문 등을 사용하여 확인합니다. 이때 typeof를 사용하면 변수가 선언되지 않은 경우 'undefined'를 반환함
- 선언(Declaration)은 변수의 이름을 지정하는 것이며, 할당(Assignment)은 변수에 값을 저장하는 것입니다. 변수 선언과 값의 할당은 실행 시점이 다릅니다. 변수 선언은 소스코드가 순차적으로 실행되는 시점인 런타임 이전에 먼저 실행되지만 값의 할당은 소스코드가 순차적으로 실행되는 시점은 런타임에 실행이 됩니다.
- 변수 선언 (Variable Declaration): 변수를 정의하고 생성하는 단계를 말합니다. 이것은 변수의 이름을 만들고, 메모리에 공간을 할당하며, 해당 변수가 어떤 유형의 값을 저장할 것인지를 지정하는 것을 포함합니다. 변수 선언은 var, let, const 등의 키워드를 사용하여 이루어진다.
- 변수 할당 (Variable Assignment): 변수에 값을 저장하거나 갱신하는 단계를 말합니다. 이것은 변수에 값을 할당하거나 다른 값을 다시 할당하는 것을 의미합니다.
- var (Function-Scoped):
var 키워드로 선언된 변수는 함수 스코프를 가집니다. 함수 내에서 선언된 변수는 함수 전체에서 접근할 수 있습니다.- let (Block-Scoped):
let 키워드로 선언된 변수는 블록 스코프를 가집니다. 블록 내에서 선언된 변수는 블록 내에서만 접근 가능합니다.
호이스팅으로 인해 변수가 선언하기 전에는 접근할 수 없으며, 이때 값은 undefined입니다.
중복 선언은 불가능하며, 같은 스코프 내에서 변수 이름을 재사용하면 에러가 발생합니다.
호이스팅으로 인해 변수가 선언하기 전에도 사용할 수 있으며, 이때 값은 undefined입니다.
중복 선언이 가능하며, 나중에 선언한 값으로 변수가 재할당됩니다.- const (Block-Scoped, Immutable):
const 키워드로 선언된 변수는 let과 마찬가지로 블록 스코프를 가집니다. 블록 내에서 선언된 변수는 블록 내에서만 접근 가능합니다.
const로 선언된 변수는 재할당이 불가능하며, 값을 변경할 수 없습니다. 단, 객체나 배열 같은 복합 데이터 타입을 가진 변수는 객체 또는 배열 내의 내용은 변경 가능합니다.- const는 값을 변경할 수 없는 상수를 선언할 때 사용하며, let은 재할당 가능한 변수를 선언할 때 사용됩니다.
- 변수 호이스팅은 var로 선언된 변수에서 가장 두드러지게 나타납니다. var로 선언된 변수는 함수 스코프를 따르며 블록 스코프를 무시합니다. 반면, let과 const는 블록 스코프를 따르며 블록 내에서만 호이스팅됨
- 변수의 초기화는 변수를 선언한 후에 해당 변수에 값을 할당하는 프로세스를 나타냅니다.
- 1) 변수 선언 : 변수를 정의하고 생성하는 단계로 변수의 이름을 만들고, 메모리에 공간을 할당하며, 해당 변수가 어떤 유형의 값을 저장할 것인지를 지정한다.
- 2) 값 할당 : 변수를 초기화하려면 값을 변수에 할당합니다. 이 값을 변수에 저장하면 변수는 해당 값을 가지게 됩니다.
- 동시에 선언과 초기화 가능
- 변수를 초기화하지 않고 사용하려고 하면 변수의 값은 undefined가 됨.
- 초기화하지 않은 변수를 사용 시, 예상치 못한 동작과 버그를 유발할 수 있으므로 주의해야 함
- 변수의 값이 없으면 주로 undefined로 나타나지만 의도적으로 값이 없음을 나타내고자 할 때 명시적으로 null을 할당합니다.
- 변수나 객체 프로퍼티 등에 "값이 없음" 또는 "비어 있음"을 명시적으로 나타내려고 할 때, 주로 null을 사용하는 것이 권장됨. 일반적으로 null을 사용하여 명시적으로 "값이 없음"을 나타냄
- undefined는 변수를 초기화하지 않은 상태로 자동으로 발생한다.
- JavaScript에서 "Truthy"와 "Falsy" 값은 조건문, 논리 연산, 제어 구조 등과 관련된 문맥에서 값의 참 또는 거짓 여부를 나타내는 개념입니다. Truthy 값은 조건식이 참으로 간주되는 값이고, Falsy 값은 조건식이 거짓으로 간주되는 값이다.
- Truthy 값: true, 0이 아닌 모든 숫자, 객체/배열(빈 객체와 빈 배열 포함), 함수, 문자열
- Falsy 값: false, 숫자 0, 빈 문자열 (''), null, undefined, NaN
- 메모리 관리: 데이터 타입은 데이터를 어떻게 저장하고 관리할지 결정하며, 메모리를 효율적으로 사용함
- 데이터 유효성 검사: 데이터 타입을 확인하여 데이터의 유효성을 검사하고, 런타임 오류를 방지함
- 연산과 함수 호출: 데이터 타입은 어떤 연산과 함수가 특정 데이터에 적용 가능한지 결정함
- 가독성과 유지 보수성: 명시적인 데이터 타입은 코드를 이해하고 유지 보수하기 쉽게 만듭니다.
- 타입 추론: 몇몇 언어는 타입을 자동으로 추론하여 코드를 간결하게 작성할 수 있게 도와줍니다.
- 데이터 타입은 프로그램이 데이터를 효과적으로 관리하고 처리할 수 있도록 필수적인 도구입니다. 올바른 데이터 타입을 사용하고 이해하면 코드의 안정성, 가독성 및 유지 보수성을 향상시킬 수 있다.
- 타입 확인 시점:
- 정적 타입 언어에서는 변수의 데이터 타입이 컴파일 시간에 결정됩니다. 즉, 변수의 데이터 타입은 컴파일러가 코드를 컴파일하는 동안 결정되며, 이후에는 변경되지 않는다. Java, C++, C# 등
- 동적 타입 언어에서는 변수의 데이터 타입이 실행 시간에 결정됩니다. 변수에 할당된 값에 따라 데이터 타입이 동적으로 변경될 수 있다. JavaScript, Python, Ruby 등
- 타입 오류 감지:
- 정적 타입 언어에서는 컴파일 시간에 타입 오류를 감지 가능, 타입 불일치 발생 시, 컴파일 오류 -> 런타임 오류를 방지하고 코드의 안정성을 높일 수 있다.
- 타입 불일치 발생 시, 런타임 오류 발생
- 코드의 가독성과 유지 보수성
- 정적 타입 언어는 명시적인 타입 정보를 제공하므로 코드의 가독성이 향상되고 유지 보수하기 쉬움
- 동적 타입 언어는 명시적인 타입 선언이 필요하지 않아서 코드가 간결할 수 있다. 그러나 가독성과 유지 보수성이 저하될 수 있다.
+) 정적 타입 언어와 동적 타입 언어의 각각의 단점을 해결하기 위해 다음과 같은 방법과 기술들이 사용된다.
정적 타입 언어는 타입 추론 기능 도입, 주석 등으로 해결
동적 타입 언어는 타입 스크립트같은 정적 타입 체계 도입, JavaScript에서는 Jest, Mocha 등의 테스트 프레임워크와 Flow, TypeScript 등의 타입 검사 도구를 사용하여 코드의 안정성을 높임, 주석 등 활용
- 원시형 데이터: 간단한 값(숫자, 문자, 불리언)을 저장하는 변수. 값 자체가 변수에 저장됨.
- 참조형 데이터: 복잡한 데이터 구조(배열, 객체, 함수)를 저장하는 변수. 변수에는 데이터의 위치(참조)가 저장됨.
명시적 타입 변환 (타입 캐스팅)과 암묵적 타입 변환의 차이에 대해서 말해주세요.
- 명시적 타입 변환(타입 캐스팅)은 개발자가 의도적으로 데이터의 타입을 변환하는 것이며, 암묵적 타입 변환은 언어나 컴파일러가 자동으로 데이터의 타입을 변환하는 것입니다.
단축 평가란 무엇이며, 논리곱, 논리합 연산자가 혼합 되어 있을 경우, 우선순위가 높은 것은?
- 단축 평가(Short-Circuit Evaluation)는 논리식을 평가할 때 특정 조건을 충족하면 남은 부분을 평가하지 않고 바로 결과를 반환하는 것을 의미함. 주로 논리곱(&&)과 논리합(||) 연산자와 함께 사용됨.
- 논리곱(&&)과 논리합(||) 연산자가 혼합된 경우, 논리곱(&&) 연산자가 논리합(||) 연산자보다 높은 우선순위를 가집니다.
단축 평가의 장단점은?
- 단축 평가(Short-Circuit Evaluation)는 논리 연산에서 사용되는 패턴으로, 특정 조건을 충족하면 남은 부분을 평가하지 않고 바로 결과를 반환하는 것을 의미한다.
- 장점 :
효율성: 불필요한 계산을 건너뛰어 코드 실행 속도를 향상시킵니다.
에러 방지: 잠재적인 에러 조건을 방지할 수 있습니다.
가독성 향상: 코드를 간결하게 만들어 가독성을 향상시킵니다.- 단점 :
지나치게 사용하면 코드의 의도 파악의 어려움
잘못 사용하면 버그가 발생할 수 있습니다.
코드 의존성 증가: 의존성이 높아져 코드를 테스트하고 유지 관리하기 어려워질 수 있습니다.
옵셔널 체이닝에 대해 설명해주세요.
- 객체의 속성을 안전하게 접근할 수 있도록 도와주는 문법적인 요소이다.
- 주로 JavaScript와 TypeScript에서 사용되며, 객체 내에 중첩된 속성이나 메서드를 접근할 때 속성이 존재하지 않는 경우 에러를 방지하고 코드를 더 안전하게 만듭니다.
- 옵셔널 체이닝은 물음표(?.)를 사용하여 객체의 속성을 접근하며, 만약 해당 속성이 존재하지 않으면 undefined를 반환
- 옵셔널 체이닝은 중첩된 속성을 접근할 때 속성이 존재하지 않아도 코드를 에러 없이 실행할 수 있게 해주므로 유용함
- 이 기능은 코드를 간결하게 만들고 예외 상황을 처리하기 쉽게 해주며, 특히 객체의 속성을 동적으로 접근하는 경우에 유용하게 활용됨
null 병합 연산자에 대해 설명해주세요.
- null 병합 연산자(Nullish Coalescing Operator)는 JavaScript의 새로운 연산자로, 주로 값이 null 또는 undefined일 때 기본값을 설정하는 데 사용됩니다. 이 연산자는 ??로 표시됨
- 기본적으로 null 병합 연산자는 왼쪽 피연산자를 평가하고, 그 값이 null 또는 undefined인 경우 오른쪽 피연산자를 반환합니다. 그렇지 않으면 왼쪽 피연산자의 값을 반환합니다.
- 주로 변수나 객체의 속성에 기본값을 설정하는 데 사용됩니다. 변수가 null 또는 undefined인 경우에만 기본값이 할당됨
콜백 함수(callback function)에 대해서 설명해 주세요.
- 콜백 함수(callback function)는 다른 함수 내에서 실행되는 함수를 가리키며, 주로 비동기 작업을 다루거나 다른 함수에 어떤 동작을 수행하도록 지정할 때 사용됩니다.
- 특징 :
- 다른 함수 내에서 실행: 콜백 함수는 다른 함수 내에서 실행되는 함수입니다.
- 비동기 작업 처리: 비동기 작업을 다루거나 이벤트 처리와 같은 비동기 상황에서 주로 사용됩니다.
- 인자로 전달: 다른 함수에 인자로 전달되어 실행되며, 필요한 시점에 호출됩니다.
- 유연성: 코드의 유연성을 높이며, 동작을 사용자 정의하거나 다른 함수에 위임할 수 있습니다.
고차 함수와 curry 함수에 대해서 설명해주세요
- 고차 함수 (Higher-Order Function):
- 고차 함수는 다른 함수를 인자로 받거나 함수를 반환하는 함수
- 커리 함수 (Currying):
- 다항 함수(여러 인자를 받는 함수)를 단항 함수의 연속으로 변환하는 기법
- 이렇게 변환된 함수들을 순차적으로 호출하여 원래 다항 함수를 호출하는 것과 동일한 결과를 얻을 수 있다.
- 커리 함수는 함수의 재사용성을 높이고 일부 매개변수를 고정하여 유연하게 활용할 수 있는 장점을 제공합니다. 함수형 프로그래밍에서 주로 사용되며, 코드의 가독성과 유지보수성을 개선하는 데 도움이 된다.
매개변수와 인자(argument)의 차이는 무엇인가요?
- 매개변수는 함수를 정의할 때 함수의 선언부에 나열되는 변수이다.
- 인자는 함수를 호출할 때 매개변수에 전달되는 값들이다.
- 함수를 호출할 때 인자의 개수와 매개변수의 개수는 일치해야 한다.
함수 표현식으로 정의한 함수를 함수 표현식 이전에 호출할 수 있나요? 그 이유는 무엇인가요?
- 함수 표현식(Function Expression)으로 정의한 함수를 함수 표현식 이전에 호출할 수 없습니다.
- 함수 선언은 스크립트가 로드되는 시점에서 호이스팅(Hoisting)되어 함수를 선언부와 별도로 인식하므로 함수 선언 이전에도 호출할 수 있습니다.
- 하지만 함수 표현식은 변수에 함수를 할당하는 것이므로 변수가 선언되기 전에 함수를 호출하려고 하면 에러가 발생합니다.(호이스팅 불가능)
Pure Function (순수 함수)의 규칙과 사용하는 이유에 대해서 설명해 주세요.
- 특정한 규칙을 따르는 함수
- 규칙
- 오로지 입력 매개변수만을 사용하여 결과를 계산함 -> 함수 내부에서 외부 상태를 변경하거나 다른 데이터에 접근하지 않아야 함
- 동일한 입력 값에 대해 항상 동일한 출력 값을 반환함
- 사용하는 이유
- 같은 입력에 대해서 항상 같은 출력을 반환하므로 코드의 동작이 예측 가능
- 부작용이 없기 때문에 코드가 안정적이며, 외부 상태에 의존하지 않아서 버그가 발생할 가능성이 줄어듦
- 순수 함수는 외부 상태나 다른 자원에 영향을 주지 않으므로 단위 테스트를 쉽게 작성하고 실행할 수 있음
- 부작용이 없어서 여러 함수를 병렬로 실행하기 쉽고, 병렬 처리를 통해 성능을 향상시킬 수 있음
- 같은 입력에 대한 결과를 캐시하고 재사용할 수 있어서 성능을 최적화할 수 있음
- 순수 함수를 사용하면 코드의 예측 가능성과 안정성을 높이며, 유지 보수가 쉬워지고 테스트가 용이해지므로 프로그램을 더 견고하게 만들 수 있습니다.
전역변수의 문제점 2가지 이상 말해 주세요.
- 네임 스페이스 충돌: 전역변수를 많이 사용하면 변수 이름이 겹칠 수 있어서 예상치 못한 문제를 일으킬 수 있습니다.
- 예측 불가능한 상태 변경: 어디서든 접근 가능한 전역변수는 다른 부분에서 의도치 않게 값을 변경할 수 있어서 코드를 이해하고 디버깅하기 어렵게 만듭니다.
전역 변수를 활용해서 개발해본 경험을 들어주세요
- 직원 관리 서비스를 만들 때 맨 처음 랜딩 페이지를 보여주고 없애는 코드가 전역 스코프에서 정의되어 있습니다. (맨 처음 랜딩 페이지 관련 로직을 전역 스코프에서 처리)
전역 변수를 최소화하기 위한 방법은 어떤 것들이 있나요?
- 모듈 시스템 사용: 코드를 모듈로 나누고, 변수와 함수를 모듈 내부에 캡슐화하여 전역 변수를 피합니다.
- 클로저 활용: 함수 내에서 변수를 비공개로 유지하고, 클로저를 사용하여 해당 변수에 접근합니다.
- 네임스페이스 객체: 하나의 전역 네임스페이스 객체를 만들어 변수와 함수를 그 안에 저장하여 전역 변수 사용을 최소화합니다.
- IIFE (즉시 호출 함수 표현식): IIFE를 사용하여 코드 블록 내에서 작업하고 전역 범위를 오염시키지 않도록 합니다.
- ES6 let과 const: ES6의 let과 const를 사용하여 블록 스코프 변수를 선언하여 전역 변수 사용을 줄입니다
지역 변수와 전역 변수의 생명 주기에 대해 설명해 주세요.
- 지역 변수와 전역 변수의 생명 주기(lifecycle)는 변수가 생성되고 소멸되는 시간을 나타냅니다.
- 지역 변수는 함수 내에서 생성되며 함수가 실행되면 생기고 종료되면 사라집니다. 전역 변수는 프로그램 시작 시 생성되며 프로그램이 종료되거나 명시적으로 제거될 때까지 존재합니다. 지역 변수는 함수 내부에서만 접근 가능하고, 전역 변수는 프로그램 전체에서 접근 가능합니다. 코드의 관리와 오류 방지를 위해 가능한 경우 지역 변수를 사용하는 것이 좋습니다.
var, let, const 로 지역 변수를 선언하는 방법에 대해서 설명해 주세요.
- var: 오래된 방식으로 함수 스코프를 가지며 호이스팅이 발생합니다. 변수가 함수 내에서만 유효하며 초기화되지 않으면 undefined로 취급됩니다.
- let: ES6에서 도입된 블록 스코프 변수로, {} 내에서만 유효합니다. 호이스팅이 발생하지만 초기화되지 않은 상태로 호이스팅됩니다.
- const: 블록 스코프 변수로, 한 번 할당된 값은 변경할 수 없는 상수로 취급됩니다.
- 일반적으로는 let과 const를 사용하며, 필요한 경우 변수 값을 변경할 필요가 없는 상황에서는 const를 사용합니다.
객체의 프로퍼티와 메서드의 역할에 대해서 설명해주세요
- 프로퍼티 (Properties):
객체의 상태나 데이터를 나타냅니다.
이름(키)과 값(value)으로 구성되며, 객체의 특징을 표현합니다.
다양한 데이터 유형을 가질 수 있으며, 점 표기법 또는 대괄호 표기법을 사용하여 접근할 수 있습니다.- 메서드 (Methods):
객체의 동작을 정의합니다.
함수의 형태를 가지며, 객체의 상태를 조작하거나 특정 작업을 수행하는 데 사용됩니다.
다른 메서드나 프로퍼티에 접근할 수 있으며 호출할 수 있습니다.
ES6에서 추가된 객체 리터럴의 확장 기능은?
- 단축 속성명 (Shorthand Property Names):
객체 프로퍼티의 키와 값이 동일한 경우, 키를 한 번만 작성할 수 있습니다.- 계산된 속성명 (Computed Property Names):
객체의 속성명을 변수 또는 표현식을 사용하여 동적으로 생성할 수 있습니다.- 메서드 축약 (Method Shorthand):
객체 내부에서 함수를 정의할 때 함수 키워드를 생략할 수 있습니다.- 객체 디스트럭처링 (Object Destructuring):
객체의 프로퍼티를 개별 변수로 추출할 수 있습니다.- 중첩된 객체 리터럴 (Nested Object Literals):
객체 리터럴 내에서 다른 객체를 중첩하여 정의할 수 있습니다.
객체 리터럴이란 무엇인가요?
- 객체 리터럴(Object Literal)은 JavaScript에서 객체를 간편하게 생성하고 초기화하는 방법입니다. 중괄호 {} 안에 프로퍼티와 값 쌍을 작성하여 객체를 정의하며, 이를 통해 데이터와 동작을 묶어서 표현할 수 있습니다. 객체 리터럴은 JavaScript에서 객체를 생성하는 일반적인 방법 중 하나이며, 코드를 더 읽기 쉽고 구조화된 형태로 표현하는 데 사용됩니다.
인스턴스란 무엇인가요?
- 인스턴스(Instance)는 객체 지향 프로그래밍(OOP)에서 특정 클래스(Class)의 실제 구현된 예시를 나타냅니다. 클래스는 객체의 설계도이며, 클래스로부터 생성된 개별 객체를 인스턴스라고 합니다. 인스턴스는 클래스에 정의된 특성과 동작을 공유하면서도 서로 다른 값들을 가질 수 있으며, 클래스와 함께 객체를 구조화하고 재사용성을 높이는 데 사용됩니다.
네이티브 객체와 호스트 객체에 대해 설명해 주세요.
- 네이티브 객체(Native Objects)는 JavaScript 언어 자체에 내장된 객체로, JavaScript 언어의 표준 일부입니다. 이러한 객체들은 모든 JavaScript 환경에서 사용 가능하며, 예를 들어 Array, String, Number 등이 있습니다.
- 호스트 객체(Host Objects)는 JavaScript 코드가 실행되는 환경(브라우저, Node.js 등)에서 제공하는 객체로, 환경에 특화된 기능을 제공합니다. 브라우저에서는 document, window, XMLHttpRequest가 호스트 객체의 예시이며, Node.js에서는 fs, http, process 등이 있습니다.
- 네이티브 객체는 JavaScript 언어의 일부이며 언제나 사용 가능하며, 호스트 객체는 실행 환경에 따라 다르며 해당 환경에서만 사용 가능합니다. 이 둘은 JavaScript 프로그램에서 필수적으로 상호작용하며, 다양한 애플리케이션과 웹 페이지를 개발하는 데 사용됩니다.