(리엑트 컴포넌트와 연관되어 있는 질문이긴 한데 실제 면접에서 자주 나오는 면접 질문이라고 해서 넣어봤습니다!)
- 클래스형 컴포넌트는 클래스로 작성이 되는데 this.state와 this.setState로 상태 관리를 하고 함수형 컴포넌트는 함수로 작성되는데 useState, useEffect, useContext 등과 같은 React Hooks를 사용합니다.
- 함수형 컴포넌트가 더 가독성이 좋고 간결합니다. 상태와 라이프사이클 관리에 더 유용한 면이 있기 때문에 리액트 프로젝트에서는 함수형 컴포넌트와 Hooks를 사용하는 것이 권장됩니다.
클래스는 함수와는 달리 호이스팅(hoisting)이 발생하지 않습니다. 클래스 선언이 함수나 변수 선언과는 다르게 동작하기 때문입니다. 클래스 선언은 명시적으로 선언되어야 하며, 클래스가 정의되기 전에 접근하려고 하면 초기화되지 않습니다. 클래스 내부의 메서드와 프로퍼티는 호이스팅되지 않고, 클래스가 실제로 선언된 위치에 도달해야 초기화됩니다.
- 생성자는 클래스의 인스턴스가 생성될 때 호출되며, 인스턴스의 초기 상태를 설정하거나 필요한 초기화 작업을 수행합니다.
- 생성자를 사용하여 클래스의 생성자를 호출하면서 필요한 인수를 전달하고, 이를 통해 클래스 내부의 속성(인스턴스 변수)을 초기화할 수 있습니다.
- 서브클래스에서 생성자를 정의할 때, super()를 사용하여 부모 클래스의 생성자를 호출할 수 있습니다. 이것은 상속 관계에서 부모 클래스의 초기화 코드를 실행하는 데 사용됩니다.
super 키워드는 객체지향 프로그래밍에서 주로 클래스와 상속 관계에서 사용되며 주로 2가지 목적으로 사용됩니다.
- 클래스에서 super를 사용하여 부모 클래스의 생성자를 호출하여 초기화 작업을 수행할 수 있습니다.
- super를 사용하여 서브클래스에서 부모 클래스의 메서드를 호출하여 부모 클래스의 기능을 확장하거나 재사용할 수 있습니다.
- 정적 메서드는 클래스 자체에 연결되어 있어 인스턴스를 생성하지 않고 클래스 이름을 통해 직접 호출되고 프로토타입 메서드는 클래스로부터 생성된 인스턴스에서 호출됩니다. 프로토타입 메서드는 인스턴스의 프로토타입(prototype)에 정의되어 해당 클래스의 모든 인스턴스에서 공유됩니다.
- 정적 메서드 내에서 this는 클래스 자체를 가리키며 인스턴스의 상태나 속성에 액세스할 수 없습니다. 프로토타입 메서드 내에서 this는 호출한 인스턴스를 가리키며 인스턴스의 상태 및 속성에 액세스할 수 있습니다.
- 정적 메서드는 클래스 전체와 관련된 동작을 처리하고, 프로토타입 메서드는 주로 인스턴스 간에 공통된 동작을 구현하는 데 사용됩니다.
- Symbol은 주로 고유한 식별자를 생성하는 데 사용되며, 다른 코드와의 충돌을 방지하거나 객체 속성을 보호하는 데 유용합니다.
- Symbol을 사용하여 객체 속성을 만들 때, 해당 속성은 문자열 속성과는 별개로 고유하게 식별됩니다. 이것은 객체에 추가된 고유한 동작 또는 정보를 저장하기에 유용합니다.
- ymbol을 사용하여 객체의 내부 상태를 숨길 수 있으므로 외부에서 쉽게 접근할 수 없습니다. 이것은 정보 은닉과 보호에 도움이 됩니다.
- JavaScript의 내장 객체와 상호작용할 때 Well-known Symbol을 활용합니다. 예를 들어, 이터러블(iterable) 객체를 만들 때 Symbol.iterator를 사용하고, 비동기 반복을 지원할 때 Symbol.asyncIterator를 사용합니다.
- 라이브러리나 프레임워크 개발 시 Symbol을 사용하여 사용자 지정 메서드를 확장하거나 라이브러리의 내부 동작을 제어합니다. 이는 다른 코드와의 충돌을 방지할 수 있습니다.
- 웹 애플리케이션에서 사용자 정의 이벤트를 다룰 때 Symbol을 사용하여 이벤트 타입을 고유하게 식별할 수 있습니다.
Object.getOwnPropertySymbols() 메서드는 객체에서 심볼 속성(symbol property)들을 반환합니다. 이 메서드는 객체의 프로토타입 체인을 통해 심볼 속성을 검색하고, 해당 객체 자체에 정의된 심볼 속성 및 부모 객체(프로토타입)에 정의된 심볼 속성을 모두 반환합니다.
- Symbol은 고유하며 중복되지 않는 값을 생성하는 데 사용됩니다. 이것은 객체 속성의 이름이나 키를 생성할 때 충돌을 피하기 위한 용도로 활용됩니다. 다른 속성과 충돌하지 않고 고유한 키를 생성할 수 있습니다.
- Symbol을 사용하면 객체의 내부 상태나 속성을 외부에서 쉽게 접근하지 못하도록 숨길 수 있습니다. 이는 정보 은폐와 보호에 유용하며 객체의 내부 구조를 숨기는 데 도움이 됩니다.
- 일부 내장 객체와 관련된 Well-known Symbol은 특정 목적에 따라 사용됩니다. 예를 들어, Symbol.iterator는 반복 가능한(iterable) 객체를 나타내고, Symbol.asyncIterator는 비동기 반복을 지원하는 데 사용됩니다.
- Symbol은 라이브러리나 프레임워크 개발 시 사용자 지정 메서드를 확장하거나 내부 동작을 제어하는 데 활용됩니다. 이는 라이브러리 코드와 다른 코드 간의 충돌을 방지하는 데 도움이 됩니다.
- Symbol은 사용자 정의 이벤트를 구분할 때 활용될 수 있습니다. 이를 통해 이벤트 핸들러에서 고유한 이벤트를 구분하고 처리할 수 있습니다.
+) 주요 이유만으로 답변 줄이기
- 충돌 방지를 위해 설명 문자열을 지정하고, 고유한 심볼을 만들어야 함.
Symbol을 생성할 때 Symbol 생성자에 전달하는 문자열을 "설명 문자열"이라고 합니다. 이 문자열은 주로 개발자에게 Symbol의 목적이나 용도를 설명하는 데 사용됩니다. 하지만 이 설명 문자열은 Symbol이 고유하게 만드는 데 영향을 주지 않습니다. Symbol은 항상 고유하며, 설명 문자열이 다르더라도 동일한 Symbol을 만들 수 없습니다.
- 코드를 디버그할 때 어떤 Symbol이 어떤 목적으로 사용되는지 파악하기 어려울 수 있습니다.
- Symbol을 사용해도 완벽한 보안을 제공하지 않으며, 객체 속성이 열거 가능하게 설정되면 여전히 여전히 접근 가능합니다.
- Symbol은 문자열과 다른 데이터 유형이므로 비교할 때 주의가 필요합니다.
+) 에러가 발생하는 경우
- Symbol.for(key):
Symbol.for(key) 메서드는 주어진 문자열 키(key)로 등록된 전역 Symbol을 검색하거나 새로 생성합니다. 이 메서드를 사용하면 전역 심볼 레지스트리(global symbol registry)에서 심볼을 공유하고, 동일한 키로 호출할 때 항상 동일한 Symbol을 반환합니다.const symbol1 = Symbol.for('mySymbol'); const symbol2 = Symbol.for('mySymbol'); console.log(symbol1 === symbol2); // true (같은 Symbol을 반환)
- Symbol.keyFor(symbol):
Symbol.keyFor(symbol) 메서드는 전역 Symbol 레지스트리에서 주어진 Symbol의 키를 반환합니다. 이 메서드는 전역 Symbol을 검색하고 해당 Symbol이 등록된 키를 반환합니다. Symbol.for(key)로 등록된 Symbol에 대해 사용됩니다.const symbol = Symbol.for('mySymbol'); const key = Symbol.keyFor(symbol); console.log(key); // 'mySymbol'
- 이러한 메서드를 사용하여 전역 심볼 레지스트리를 활용하고, 동일한 Symbol을 여러 곳에서 공유하거나 심볼과 키 간의 매핑을 확인할 수 있습니다.
- Collection 객체 (ex. Set, Map) 반복:
Collection 객체는 forEach 메서드를 사용하는 것이 일반적으로 가장 최적화된 방법입니다. 이 메서드는 Collection의 각 요소를 반복하면서 콜백 함수를 호출합니다.
- 이유: Collection 객체는 순회 방법이나 내부 구조가 다양할 수 있으며, forEach 메서드는 내부 동작을 최적화하고 숨깁니다. 또한, Collection 객체에서 요소에 쉽게 접근할 수 있도록 제공되므로 반복 과정이 효율적입니다.
- Object 객체 반복:
Object 객체를 반복할 때는 for...in 루프를 사용하는 것이 일반적으로 가장 효율적입니다. ES6에서는 Object.keys(), Object.values(), Object.entries() 메서드도 사용할 수 있지만, for...in 루프가 좀 더 전통적이며, 더 나은 호환성을 제공합니다.
- 이유: for...in 루프는 객체의 속성을 열거하고, 브라우저의 최적화된 열거 방식을 활용하므로 Object 객체를 효율적으로 반복할 수 있습니다.
- 배열 반복:
배열을 반복할 때는 배열의 메서드 중에서 forEach 메서드를 사용하는 것이 가장 간편하고 일반적입니다.
- 이유: 배열은 순서가 있는 데이터 구조이며, forEach 메서드는 배열의 각 요소를 순차적으로 처리하므로 가독성이 좋고 사용하기 쉽습니다.
- for...of 루프는 ES6에서 도입된 반복 구문으로, 배열의 값을 직접 열거하고 forEach() 메서드는 배열 객체에 속한 메서드로, 배열의 각 요소를 반복하면서 콜백 함수를 호출합니다.
- for...of 루프는 반복 중에 배열의 각 요소 값을 직접 반환할 수 있고 forEach() 메서드는 반환값이 없으며, 반복 중에 어떤 값을 반환하더라도 무시됩니다.
- for...of 루프 내에서 break 문을 사용하여 반복을 중단하거나 continue 문을 사용하여 다음 반복 단계로 이동할 수 있습니다. forEach() 메서드 내에서는 return 문을 사용해도 전체 반복을 중단할 수 없으며, continue를 사용해도 현재 반복을 건너뛸 수 없습니다.
- for...of는 간결하고 직관적이며 가독성이 높으며, 배열의 값 자체를 반복하고 값에 따라 작업을 수행할 때 유용합니다. 값만 필요한 경우에 적합합니다.
forEach()는 각 요소에 대한 작업 또는 부수 효과가 필요한 경우에 사용됩니다. 예를 들어, 각 요소를 콘솔에 출력하거나 변경할 때 사용됩니다.
- 이터러블(iterable)은 반복 가능한 객체로, Symbol.iterator 메서드를 가집니다. 이 메서드는 이터레이터를 반환하며, 이터레이터는 next() 메서드로 값을 반환하고 반복 상태를 제어합니다.
- 이터레이터(iterator)는 이터러블 객체를 반복하는 객체로, next() 메서드로 값을 반환하고 반복이 끝났는지 여부를 나타내는 done 속성을 반환합니다. 이터레이터는 반복 구문에서 사용됩니다. 이터레이터를 이용해 데이터 구조를 순회하고 제어할 수 있습니다.
- 이터러블 (Iterable)
이터러블은 반복 가능한 객체로, Symbol.iterator 메서드를 가집니다.
Symbol.iterator 메서드는 이터레이터를 반환하며, 이터레이터는 next() 메서드로 값을 반환하고 반복 상태를 제어합니다.- 이터레이터 (Iterator)
이터레이터는 이터러블 객체를 반복(iterate)하는 데 사용되는 객체입니다.
이터레이터는 next() 메서드를 가지며, 각 호출마다 현재 요소의 값을 반환하고 반복이 끝났는지 여부를 나타내는 done 속성을 반환합니다. 이터레이터는 반복 구문에서 사용됩니다. 이터레이터를 이용해 데이터 구조를 순회하고 제어할 수 있습니다.- 제너레이터 (Generator)
제너레이터는 함수 내부에서 일시 중단과 재개를 제어하는 함수입니다.
function* 키워드를 사용하여 정의하며, 함수 실행 중에 yield 키워드를 사용하여 값을 반환하고 일시 중단할 수 있습니다. 제너레이터는 이터레이터를 자동으로 생성하며, next() 메서드를 호출하여 제어하고 값을 반환합니다.
- 유사 배열 객체를 이터러블로 사용하려면 해당 객체를 이터러블 프로토콜을 따르는 형태로 변환해야 합니다.
- Symbol.iterator 메서드를 직접 구현:
객체에 Symbol.iterator 메서드를 추가하고 해당 메서드는 이터레이터 객체를 반환해야 합니다. 이 이터레이터 객체는 next() 메서드를 구현하고 값을 반환합니다.- Array.from() 메서드 사용:
Array.from() 메서드를 사용하여 유사 배열 객체를 진짜 배열로 변환한 다음, 이 배열을 이터러블로 사용할 수 있습니다.