[ React ] 모던 리액트 DEEP DIVE - CH.1 필수 JS

·2024년 2월 11일

<1> 자바스크립트의 데이터 타입

1. 원시 타입

객체가 아닌 다른 모든 타입이며, 객체가 아니므로 메서드를 가지지 않는다.

1.1 원시타입의 종류

undefined : 선언 후 값을 할당하지 않은 변수, 값이 주어지지 않은 인수에 자동으로 할당되는 값

null : 아직 값이 없거나, 명시적으로 비어 있는 값

-> type of 로 확인했을 때 object 로 반환되는 특성이 있다.

boolean: 참과 거짓만을 가질 수 있는 데이터 타입

-> 조건문에서 falsy 가 가능한 실제 타입은 boolean값 외에, 0(-0, 0n, 0x0n), NaN, 빈 문자열, null, undefined가 있다

number : 모든 숫자를 포함한다. 따라서 각 진수별로 값을 표현해도 모두 10진수로 해석된다.

BigInt : 최대 2의 55승 -1 을 저장할 수 있는 number의 한계를 넘어 더 큰 숫자를 저장할 수 있게 한다.

String: 텍스트 타입의 데이터를 저장하기 위해 사용된다. "", ''로 표현가능하고 문자열 리터럴 표현 방식인 `으로 감쌀 수도 있다.

-> 문자열 리터럴은 줄바꿈이 가능하고, 문자열 내부에 표현식을 쓸 수 있다.
-> 원시 타입이기에 변경 불가능하여 한번 문자열이 생성되면 그 문자열은 변경할 수 없다.

Symbol : 중복되지 않은 어떠한 고유한 값을 나타내며, Symbol()을 사용해야만 생성할 수 있다.

2. 객체 타입

원시 타입 이외의 모든 것, 자바스크립트를 이루고 있는 대부분의 타입니다. 또한, 객체 타입은 참조를 전달하기에 참조 타입이라고 불린다.

3. 원시 타입 vs 객체 타입

3.1 값 저장 방식의 차이

  • 원시 타입 : 불변 형태의 값으로 저장된다. 또한, 변수 할당 시점에 메모리 영역을 차지하고 저장된다. 값을 전달하는 방식이 아닌 각각 선언하는 방식으로도 동일한 결과를 볼 수 있다.
let hello = 'hello world';
let hi = 'hello world';
let hey = hello

console.log(hello === hey ) //true
console.log(hello === hi ) //true
  • 객체 타입 : 프로퍼티를 삭제, 추가, 수정할 수 있어 원시 값과 다르게 변경 가능한 형태로 저장되며 값을 복사할 때도 값이 아닌 참조를 전달하게 된다.
var hello = {
  greet : 'hello world',
}

var hi = {
  greet : 'hello, world',
}

console.log(hello === hi) //false
console.log(hello.greet === hi.greet) //true

객체는 값이 아닌 참조를 저장하므로, 동일하게 선언했던 객체라 할지라도 저장하는 순간 다른 참조를 바라보게 된다.

var hello = {
  greet : 'hello world',
}

var hi = hello;  //두 변수가 모두 동일한 하나의 객체를 바라보게 된다. value가 가리키는 주소가 동일하다.

console.log(hi === hello) //true

3.2 Object.is

자바스크립트에서 비교를 위해 제공하는 방법이며, 두 개의 인수를 받고 이 인수 두 개의 동일성을 확인하고 반환하는 메서드이다.
===과 마찬가지로, 타입이 다르면 false 를 반환한다.
하지만 이때 객체 비교는 별로 차이가 없이 참조값으로 비교하게 된다.

Object.is(NaN, 0/0 ) //true
Object.is( {}, {} ) //false

3.3 리액트에서의 동등 비교

리액트에서의 동등 비교는 Object.is 를 사용하는데 이는 es6에서 제공되기 때문에 폴리필(Polyfill)을 함께 사용한다.

function is(x:any, y:any){
  return(
    (x === y && ( x !==0 || 1/x ===1/y)) || (x !==x && y !==y)//
    )
}

const objectIs : (x:any, y:any) => boolean = 
  typeof Object.is === 'function' ? Object.is : is

export default objectIs

리액트에서 이를 이용해서 값을 비교하기 위해서는 Object.is로 먼저 비교를 수행한 다음, Object.is에서 수행하지 못하는 비교인 얕은 비교를 한 번 더 수행한다. (shallowEqual)

<2> 함수

1. 함수란?

자바스크립트에서 함수란 작업을 수행하거나 값을 계산하는 등의 과정을 표현하고 하나의 블록을 감싸서 실행 단위로 만들어 놓은 것을 의미한다.
function으로 시작해 }로 끝나는 부분까지가 함수이며,
함수의 입력값으로 받는 것은 매개 변수, return으로 작성된 것은 반환값이다.
또한, 함수의 이름을 사용해 호출할 때 매개변수로 넘겨주는 값을 인수라고 한다.

function 함수이름(매개변수){
  return 반환값
}

컴포넌트를 만드는 함수도, 같은 형태를 띄는데,
return 문으로 jsx를 반환한다.

2. 함수 정의법

2.1 함수 선언문

function add(a,b){
  return a+b
}

표현식이 아닌 일반 문이며, 함수 선언으로 어떠한 값도 표현되지 않으므로 표현식이 아닌 문으로 분류된다.

2.2 함수 표현식

2.2.1 일급 객체

  • 일급 객체 : 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체. 자바스크립트에서 함수는 다른 함수의 매개변수가 될 수도, 반환값이 될 수도 있으며 할당도 가능하므로 일급 객체가 되기 위한 조건을 갖추고 있다. 따라서 함수를 변수에 할당하는 것은 당연하다.
const sum = function (a,b) {
return a+b
}

코드의 혼란을 방지하기 위해 함수 표현식에서는 할당하려는 함수의 이름을 생략하는 것이 일반적이다.

2.3 표현식 vs 선언식

2.3.1 호이스팅

함수의 호이스팅은 함수에 대한 선언을 실행 전에 미리 메모리에 등록하는 작업이다.

함수 선언식에서는: 함수 선언문이 미리 메모리에 등록됐고, 코드의 순서에 상관없이 정상적으로 함수를 호출할 수 있게 된다.

함수 표현식에서는: 반면, 함수 표현식은 함수를 변수에 할당하는 것인데 이때 변수도 호이스팅이 발생한다.
그러나 호이스팅되는 시점에서 var일 경우 undefined로 초기화된다.
즉, 런타임 이전에는 undefined로 초기화되고 할당문이 실행되는 시점에 함수가 할당되어 작동한다.

즉, 함수를 자유롭게 선언하고 어디서든 호출하고 싶고 명시적으로 함수를 구별하고 있을 때에는 함수 선언문이 더 좋을 수 있다. 그러나, 어디에서 선언했는지 해당 스코프를 끝까지 찾지 않으면 확인하기 어렵다.

2.4 함수 생성방식

2.4.1 Function 생성자

const add = new Function('a', 'b', 'return a+b')

매개변수, return 값 모두 문자열로 작성해야 한다.
또한 이러한 방식으로 함수를 만들면 함수의 클로저 또한 생성되지 않는다.

2.4.2 화살표 함수

const add = (a,b) =>  { 
  return a+b
}

화살표 함수에서는 constructor를 사용할 수 없다. 생성자 함수로 화살표 함수를 사용하는 것은 불가능하다.

const Pen = (name) => {
  this.name = name
}

//Uncaught TypeError: Pen is not a consturctor
const myPen = new Pen('히얼')

또한, 화살표 함수에넌 arguments가 존재하지 않는다.

const hi = () => {
  console.log(arguments)
}

hi(1,2,3)

2.4.3 this

자신이 속한 객체나 자신이 생성할 인스턴스를 가리키는 값, 함수가 어떻게 호출되느냐에 따라 동적으로 결정된다.
일반 함수 호출 : 내부의 this는 전역 객체를 가리키게 된다.
화살표 함수 : 함수 자체의 바인딩을 갖지 않아, 상위 스코프의 this를 그대로 따르게 된다.

class Component extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      counter : 1,
    }
  }

  functionCountUp() {
    console.log(this) //undefined
    this.setState((prev) => ( {counter: prev.counter+1}))
  }

  ArrowFunctionCountUp = () => {
    console.log(this) //class component
    this.setState((prev) => ( {counter: prev.counter+1}))
  }

  render() 
		return (
  			<div>
  				<button onClick={this.functionCountUp)}일반함수</button>
				//Cannont readd properties of undefined (reading setState)
  				<button onClick={this.ArrowFunctionCountUpp)}화살표함수</button>
				//정상작동
			</div>
			)
		}
	}

2.5 다양한 함수

2.5.1 즉시 실행 함수

함수를 정의하고 그 순간 즉시 실행되는 함수이며
단 한번만 호출되고 다시금 호출할 수 없는 함수이다.
그렇기에 일반적으로 즉시 실행 함수에 이름을 붙이지 않는다.

function (a,b) {
  return a+b
})(10, 24); //34

((a,b) => {
  return a+b
},
 )(10,24)

즉시 실행함수는 독립적인 함수 스코프를 운용할 수 있다. 따라서 즉시 실행 함수 내부에 있는 값은 함수 내부가 아니고서는 접근 불가능하다.
그 선언만으로 실행이 거기서 끝나는 것을 각인시키기에 리팩토링에 큰 도움이 된다.

2.5.2 고차 함수

자바스크립트 함수가 일급 객체라는 특징을 이용해 함수를 인수를 받거나 결과로 새로운 함수를 반환할 수 있다.

const doubleArray = [1,2,3].map((item) => item * 2 )

const add = function (a) {
  return function (b) {
    return a +b
  }
}

이러한 특징을 활용하여, 고차 컴포넌트를 만들 수 있다.

2.6 함수를 만들때 주의사항

2.6.1 함수의 부수 효과를 최대한 억제하자

이러한 부수효과가 없는 함수를 순수함수라고 한다.

  • 순수 함수: 언제 어디서나 어떤 상황에서든 동일한 인수를 받으면 동일한 결과를 반환하는 것

2.6.2 가능한 함수를 작게 만들어라

2.6.3 누구나 이해할 수 있는 이름을 붙여라

Terser가 설치되어 있다면 한글로 네이밍할 수 있다.

profile
new blog: https://hae0-02ni.tistory.com/

1개의 댓글

comment-user-thumbnail
2024년 3월 3일

null이 왜 object 타입으로 반환되는지 더 구체적인 이유가 문득 궁금했는데요, 원래 객체의 의미를 내재하고 있는 값으로 만들어졌기 때문이라고 합니다! 즉 역사적으로 원래 객체 참조가 있어야 하는데 참조가 없다는 의미를 표현하기 위해 만들어졌기 때문입니다.

또다른 이유는 책에도 기술된 것처럼 "기술적인 버그"인데요, 더 구체적으로는 C와 비슷하게 JS에서도 null을 0으로 숫자 형변환되는 값으로 정의하였습니다. 하지만 typeOf 작동 방식에 null을 위한 특별한 처리 로직이 없었고, object와 같은 태그 값을 가지고 있다는 이유로 반환값이 object가 되었다고 합니다.

이와 관련된 구체적이고 재밌는 레퍼런스가 있어서 링크 남깁니다:)
https://witch.work/posts/javascript-why-typeof-null-is-object

답글 달기