리액트 딥다이브 스터디를 현재 진행하고 있습니다. 이 내용을 포스팅하여 공유하고자 합니다.
1.1 자바스크립트의 동등 비교
1.1.1 자바스크립트의 데이터 타입
자바스크립트의 모든 값은 데이터 타입을 가지고 있으며, 원시 타입과 객체 타입으로 나눌 수 있습니다.
원시 타입이란 객체가 아닌 모든 타입을 의미하며 메서드를 갖지 않는다.
메서드란 ? 객체에 포함된 함수로, 객체의 동작을 정의하며 데이터를 조작하거나 특정 작업을 수행할 수 있게 해줍니다.
undefined
선언한 후 값을 할당하지 않은 변수 또는 값이 주어지지 않은 인수에 자동으로 할당되는 값
null과 undefined는 각각 null, undefined라는 값만 가질 수 있으며 그 밖의 타입은 가질 수 있는 값이 두 개 이상 존재한다.
null
아직 값이 없거나 비어 있는 값을 표현할 때 사용한다.
null은 object라는 결과가 반환되며 undefined는 '선언됐지만 할당되지 않은 값', null은 '명시적으로 비어 있음을 나타내는 값'으로 사용하는 것이 일반적이다.
undefeind와 null의 차이를 보여주는 예시 코드
boolean
참과 거짓만을 가질 수 있는 데이터 타입이다.
true, false와 같은 boolean 형의 값 외에도 조건문에서 마치 true와 false처럼 취급되는 truthy, falsy값이 존재한다.
!! 연산자를 사용하는 이유는 값을 명시적으로 boolean 타입으로 변환하여 값을 보여주기 위함입니다.
number
-(2^53 - 1) ~ 2^53 - 1 사이의 값을 저장할 수 있습니다.
2진수, 8진수, 16진수 등의 별도 데이터 타입을 제공하지 않으므로 각 진수로 값을 표현해도 모두 10진수로 해석되어 값으로 표시됩니다.
BigInt
number가 다룰 수 있는 숫자 크기의 제한을 극복하기 위해 ES2020에서 새롭게 나온 타입
string
', ", `(문자열 리터럴 백틱)으로 표현할 수 있습니다.
백틱은 따옴표와 달리 줄바꿈을 할 수 있고 문자열 내부에 표현식을 쓸 수 있습니다.
문자열은 원시 타입이며 변경 불가능합니다. 문자열이 한번 생성되면 그 문자열은 변경할 수 없습니다.
Symbol
중복되지 않은 고유한 값을 나타내기 위해서 사용되며 반드시 Symbol()을 사용해야 합니다.
객체 타입
앞서 7가지의 원시 타입 이외의 모든 타입은 다 객체 타입입니다. 배열, 함수, 정규식, 클래스 등이 있습니다.
객체 타입은 참조를 전달한다고 해서 참조 타입으로도 불립니다.
1.1.2 값을 저장하는 방식의 차이
원시 타입과 객체 타입의 가장 큰 차이점은 값을 저장하는 방식의 차이입니다.
원시 타입은 불변 형태의 값으로 저장되며 이 값은 변수 할당 시점에 메모리 영역을 차지하고 저장됩니다.
객체는 프로퍼티를 삭제, 추가, 수정할 수 있으므로 원시 값과 다르게 변경 가능한 형태로 저장되며 복사할 때도 값이 아닌 참조를 전달하게 됩니다.
프토퍼티란? : 객체의 속성을 나타내는 키-값 쌍입니다. 여러 개의 프로퍼티를 가질 수 있으며, 각 프로퍼티는 key, value로 구성됩니다. 프로퍼티는 추가, 삭제, 수정할 수 있으므로 변경 가능한(mutable) 형태로 저장됩니다.
원시 타입 예시
객체 타입 예시
객체는 값을 저장하는 것이 아니라 참조를 저장하기 때문에 동일하게 선언한 객체라고 하더라도 다른 참조를 바라보기 때문에 비교 시 false를 반환합니다.
1.1.3 Object.is
Object.is는 두 개의 인수를 받으며 인수 두 개가 동일한지 확인하고 반환하는 메서드입니다.
하지만 객체 비교에 있어서는 ===와 동일하게 작동합니다. 왜냐면 두 방법 모두 객체의 참조를 비교하기 때문입니다.
1.2 함수
1.2.1 함수란 무엇인가?
작업을 수행하거나 값을 계산하는 등의 과정을 표현하고, 이를 하나의 블록으로 감싸서 실행 단위로 만들어 놓은 것을 의미합니다.
1.2.2 함수를 정의하는 4가지 방법
함수 선언문
함수 선언문은 표현식이 아닌 일반 문으로 분류됩니다. 함수 선언으로는 어떠한 값도 표현되지 않았으므로 문으로 분류됩니다. 하지만
위 예제는 sum이라는 변수에 함수 sum을 할당하는 표현식과 같은 작동을 보였다. 이는 JS 엔진이 문맥에 따라 동일한 함수를 문이 아닌 표현식으로 해석하는 경우가 있기 때문입니다. 즉 선언문으로도 표현식으로도 사용될 수 있습니다.
함수 표현식
자바스크립트에서 함수는 일급 객체이다. 일급 객체란 다른 함수의 매개변수가 될 수도 있고, 반환값이 될 수도 있으며 할당도 가능하다.
함수 표현식과 선언 식의 차이
가장 큰 방식의 차이는 호이스팅 여부입니다.
호이스팅이란? 호이스팅은 자바스크립트의 기본 동작 방식으로 변수 선언과 함수 선언이 실제 코드 실행 전에 해당 스코프의 최상위로 끌어올려지는 것을 의미합니다.
변수 초기화나 함수 표현식의 값은 호이스팅되지 않습니다.
함수 선언문이 미리 메모리에 등록됐고 코드의 순서에 상관없이 정상적으로 함수를 호출할 수 있게 되었습니다.
함수 선언문과 다르게 정상적으로 호출되지 않고 undefined로 남아있습니다. 함수와 다르게 변수는 undefined로 초기화되고 할당문이 실행되는 시점, 런타임 시점에 함수가 할당되어 작동합니다.
화살표 함수
function이라는 키워드 대신 화살표를 활용하여 함수를 만든다.
화살표 함수에는 constructor를 사용할 수 없습니다.
화살표 함수에는 arguments가 존재하지 않습니다.
this란? 자신이 속한 객체나 자신이 생성할 인스턴스를 가리키는 값, 이는 this는 화살표 함수 이전까지는 일반 함수로서 호출된다면, 그 내부의 this는 전역 객체를 가리키게 됩니다.
1.2.3 다양한 함수 살펴보기
즉시 실행 함수
한 번 선언하고 호출된 이후부터는 더 이상 재호출이 불가능한 함수
고차 함수
함수를 인수로 받거나 결과로 새로운 함수를 반환시킬 수 있습니다. 이런 역할을 하는 함수를 고차 함수라고 한다.
클로저란 ? 함수가 선언된 렉시컬 환경을 기억하고 그 환경에 접근할 수 있는 함수를 말합니다. 클로저는 함수가 자신이 선언된 위치에서의 스코프를 기억하고,그 스코프에 정의된 변수들에 접근할 수 있게 합니다.
렉시컬 환경이란 ? 실행 컨텍스트에서 변수를 저장하고 참조하는 구조를 정의한 개념 즉 코드가 실행될 때 변수가 어디서 정의되고 어디에서 접근할 수 있는지를 추적하는 구조입니다.
큰 상자(outerFunction) 안에 outerVariable이 있고 작은 상자(innerFunction)는 큰 상자 안에 있으며 이 안에는 innerVariable이 있다고 가정하였을 때 innerFunction은 outerFunction안에 있다는 것을 알고 있기에 큰 상자 안에 내용을 볼 수 있지만(접근 가능) 반대는 불가능 합니다.
함수의 부수 효과를 최대한 억제하라
함수 내의 작동으로 인해 함수 외부에 영향을 끼치는 것을 함수의 부수 효과라 합니다.(side-effect) 이러한 부수 효과가 없는 함수를 순수 함수라 하고 결과가 항상 동일하기 때문에 예측 가능하며 안정적이라는 장점이 있습니다.
리액트의 관점으로 본다면 useEffect의 작동을 최소화 하는 것이 그 일환이라 할 수 있습니다. 이러한 부수 효과를 최소화 하도록 설계해야 합니다.
가능한한 함수를 작게 만들어라
하나의 함수에서 너무나 많은 일을 하지 않게 해야 합니다. 재사용성을 그래야만 높일 수 있습니다.
1.3 클래스
1.3.1 클래스란 무엇인가?
특정한 객체를 만들기 위한 템플릿과 같은 개념으로 볼 수 있다. 클래스를 활용하면 객체를 만드는 데 필요한 데이터나 이를 조작하는 코드를 추상화해 객체 생성을 더욱 편리하게 할 수 있습니다.
constructor
constructor는 생성자로, 객체를 생성하는 데 사용하는 특수한 메서드이며 여러 개를 사용하면 에러가 발생합니다. 별다르게 수행할 작업이 없다면 생략해도 무방합니다.
프로퍼티
class로 인스턴스를 생성할 때 내부에 정의할 수 있는 속성값을 의미합니다.
인스턴스란? 클래스의 구체적인 실체로 클래스에 정의된 속성 값과 메서드를 가지는 실제 객체입니다.
getter와 setter
getter란 클래스에서 무언가를 가져올 때 사용되며 setter는 클래스 필드에 값을 할당할 때 사용합니다.
인스턴스 메서드
클래스 내부에서 선언한 메서드를 인스턴스 메서드라고 합니다. 이는 prototype에 선언되므로 프로토타입 메서드로 불리기도 합니다.
이는 다음과 같이 선언할 수 있습니다.
직접 객체에서 선언하지 않았음에도 프로토타입에 있는 메서드를 찾아서 실행을 도와주는 것을 프로토타입 체이닝이라고 합니다. 이를 통해서 최상위 객체인 Object까지 확인하여 hello를 호출할 수 있게 됩니다.
정적 메서드
클래스의 인스턴스가 아닌 이름으로 호출할 수 있는 메서드이며 내부의 this는 생성된 인스턴스가 아닌 클래스 자신을 가리키기 때문에 사용할 수 없습니다.
애플리케이션 전역에서 사용하는 유틸 함수를 정적 메서드로 많이 활용합니다.
1.4 클로저
함수와 함수가 선언된 렉시컬 스코프의 조합
렉시컬 스코프는 변수가 코드 내부에서 어디서 선언 되었는지를 말합니다.호출되는 방식에 따라서 동적으로 결정되는 this와 다르게
렉시컬 스코프는 코드가 작성되는 순간 정적으로 결정됩니다.
전역 상자 > outerFunction 상자 > innerFunction 상자 순으로 되어 있다고 생각하면 편합니다.
안에선 밖을 접근할 수 있지만 바깥에선 안을 접근할 수 없습니다.
Counter 함수는 counter라는 0으로 시작하는 변수를 하나 만듭니다. 또한 그 안에는 increase, decrease, counter라는 상자가
Counter 안에 존재 합니다. 따라서 각각의 함수는 counter를 접근할 수 있지만 Counter에서는 각 함수에 선언된 변수에 접근할 수
없습니다.
i는 함수 스코프를 가집니다. for 루프 안에서 선언된 i가 하나의 변수로 존재를 합니다. 즉 i는 증가를 하지만 하나의 변수로써
존재한다는 의미입니다. setTimeout 비동기가 실행되면서 i의 값은 빠르게 5가 된 이후에 출력을 하기 때문에 5 5 5 5 5가 출력됩니다.
그에 반해 let은 블록 스코프를 가집니다. 즉 새로운 i의 인스턴스가 생성이 되고 표시되는 i의 값은 각각이 다른 메모리를 참조합니다.