Giter VIP home page Giter VIP logo

articles's People

Contributors

sbyeol3 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

hkh0105

articles's Issues

[๋ฒˆ์—ญ] React์˜ ๊ถ๊ทน์  ์›๋ฆฌ - ์†Œํ”„ํŠธ์›จ์–ด ๋””์ž์ธ, ์•„ํ‚คํ…์ณ & ์ข‹์€ ์˜ˆ์‹œ 1

์›๋ฌธ : 2021.01.18์— ์ž‘์„ฑ๋œ Tao of React - Software Design, Architecture & Best Practices

์ €๋Š” React๋ฅผ 2016๋…„๋ถ€ํ„ฐ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์กฐ์™€ ๋””์ž์ธ์— ๋Œ€ํ•œ ๋ชจ๋ฒ”์ ์ธ ์˜ˆ์‹œ๋Š” ํ•œ ๊ฑด๋„ ์—†์Šต๋‹ˆ๋‹ค. ๋งˆ์ดํฌ๋กœ ์ˆ˜์ค€์— ๋Œ€ํ•œ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋Š” ์žˆ์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ํŒ€๋“ค์€ ๊ฐ์ž ์ž์‹ ๋งŒ์˜ ์•„ํ‚คํ…์ณ๋ฅผ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก , ๋ชจ๋“  ๋น„์ฆˆ๋‹ˆ์Šค์™€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์ตœ๊ณ ์˜ ์˜ˆ์‹œ๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ƒ์‚ฐ์ ์ธ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋”ฐ๋ผ์•ผ ํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๊ทœ์น™๋“ค์€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

์†Œํ”„ํŠธ์›จ์–ด ์•„ํ‚คํ…์ณ์™€ ๋””์ž์ธ์˜ ๋ชฉ์ ์€ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์ƒ์‚ฐ์ ์ด๊ณ  ์œ ์—ฐํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์— ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋“ค์€ ์†Œํ”„ํŠธ์›จ์–ด์˜ ํ•ต์‹ฌ๋ถ€๋ถ„์„ ์žฌ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ  ํšจ๊ณผ์ ์œผ๋กœ ์ž‘์—…ํ•˜๊ณ  ์ˆ˜์ •ํ•ด์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์€ ์ €์™€ ์ œ๊ฐ€ ํ•จ๊ป˜ ์ผํ–ˆ๋˜ ํŒ€์—์„œ ๊ฝค ํšจ๊ณผ์ ์ด๋ผ๊ณ  ์ฆ๋ช…๋˜์—ˆ๋˜ ์›๋ฆฌ์™€ ๊ทœ์น™๋“ค์˜ ๋ชจ์Œ์ง‘์ž…๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ, ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์กฐ, ํ…Œ์ŠคํŒ…, ์Šคํƒ€์ผ๋ง, ์ƒํƒœ ๊ด€๋ฆฌ์™€ ๋ฐ์ดํ„ฐ fetching ๋“ฑ์— ๋Œ€ํ•œ ์‚ฌ๋ก€๋“ค์„ ๊ฐœ๋žต์ ์œผ๋กœ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ์˜ ์ผ๋ถ€๋Š” ๊ตฌํ˜„๋ณด๋‹ค๋Š” ์›์น™์— ์ง‘์ค‘ํ•˜๊ณ ์ž ์ง€๋‚˜์น˜๊ฒŒ ๋‹จ์ˆœํ™”๋˜์–ด ์žˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์„ธ์š”.

์ด ๊ธ€์˜ ๋ชจ๋“  ๊ฒƒ์„ ์ ˆ๋Œ€์ ์ธ ๊ฒƒ์ด ์•„๋‹Œ ํ•˜๋‚˜์˜ ์˜๊ฒฌ์œผ๋กœ์„œ ๋ฐ›์•„๋“ค์ด๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ์—๋Š” ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ (Components)

ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€ํ–ฅํ•˜๋ผ (Favor Functional Components)

ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€ํ–ฅํ•˜๋ผ - ๊ฐ„๋‹จํ•œ ํ‘œํ˜„์ž…๋‹ˆ๋‹ค. ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฉ”์†Œ๋“œ, ์ƒ์„ฑ์ž, ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ๋„ ์—†์Šต๋‹ˆ๋‹ค. ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋ณด๋‹ค ๊ฐ€๋…์„ฑ์„ ์žƒ์ง€ ์•Š์œผ๋ฉด์„œ ์ ์€ ํ‘œํ˜„์œผ๋กœ ๊ฐ™์€ ๋กœ์ง์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. error boundary๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๋ฉด ์ด ๋ฐฉ์‹์„ ๋”ฐ๋ผ์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ๋จธ๋ฆฟ ์†์— ๊ฐ„์งํ•ด์•ผ ํ•  ์ •์‹ ์ ์ธ ๋ชจ๋ธ์ด ํ›จ์”ฌ ์ž‘์•„์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

// ๐Ÿ‘Ž ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋Š” ์žฅํ™ฉํ•ฉ๋‹ˆ๋‹ค
class Counter extends React.Component {
  state = {
    counter: 0,
  }

  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    this.setState({ counter: this.state.counter + 1 })
  }

  render() {
    return (
      <div>
        <p>counter: {this.state.counter}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    )
  }
}

// ๐Ÿ‘ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฝ๊ธฐ๋„ ์‰ฝ๊ณ  ์œ ์ง€ํ•˜๊ธฐ๋„ ์ข‹์ฃ 
function Counter() {
  const [counter, setCounter] = useState(0)

  handleClick = () => setCounter(counter + 1)

  return (
    <div>
      <p>counter: {counter}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  )
}

์ผ๊ด€๋œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋ผ (Write Consistent Components)

์—ฌ๋Ÿฌ๋ถ„์˜ ์ปดํฌ๋„ŒํŠธ์˜ ์Šคํƒ€์ผ์„ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•˜์„ธ์š”. ๊ฐ™์€ ์œ„์น˜์— ํ—ฌํผ ํ•จ์ˆ˜๋ฅผ ๋‘๊ณ , ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ exportํ•˜๊ณ  ๋™์ผํ•œ ๋„ค์ด๋ฐ ํŒจํ„ด์„ ๋”ฐ๋ฅด์„ธ์š”.
์–ด๋–ค ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋‹ค๋ฅธ ๋ฐฉ์‹๋ณด๋‹ค ๋‚˜์€ ์ ์€ ์—†์Šต๋‹ˆ๋‹ค. ํŒŒ์ผ ์•„๋ž˜์—์„œ exportํ•˜๋“ ์ง€, ์ปดํฌ๋„ŒํŠธ ์ •์˜์—์„œ ๋ฐ”๋กœ ํ•˜๋“ ์ง€ ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค.
ํ•˜๋‚˜๋ฅผ ๊ณจ๋ผ ๊ทธ ๋ฐฉ์‹์„ ๊ณ ์ˆ˜ํ•˜์„ธ์š”.

์ปดํฌ๋„ŒํŠธ์˜ ์ด๋ฆ„์„ ์ง€์–ด๋ผ (Name Components)

์—ฌ๋Ÿฌ๋ถ„์˜ ์ปดํฌ๋„ŒํŠธ์— ํ•ญ์ƒ ์ด๋ฆ„์„ ์ง€์–ด์ฃผ์„ธ์š”. ์ด๋Š” ๋‚˜์ค‘์— ์—ฌ๋Ÿฌ๋ถ„์ด ์—๋Ÿฌ ์Šคํƒ์„ ์ถ”์ ํ•˜๊ฑฐ๋‚˜ React Dev tools๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.
๋˜ํ•œ ํŒŒ์ผ ๋‚ด์— ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์ด ์žˆ๋‹ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์ด ๊ฐœ๋ฐœํ•  ๋•Œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐพ๊ธฐ๊ฐ€ ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค.

ํ—ฌํผ ํ•จ์ˆ˜๋ฅผ ๊ตฌ์„ฑํ•˜๋ผ (Organize Helper Functions)

์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•ด ํด๋กœ์ ธ๋ฅผ ๊ฐ€์งˆ ํ•„์š” ์—†๋Š” ํ—ฌํผ ํ•จ์ˆ˜๋Š” ๋ฐ”๊นฅ์œผ๋กœ ์˜ฎ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด์ƒ์ ์ธ ์œ„์น˜๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ •์˜๋œ ๊ณณ๋ณด๋‹ค ๋จผ์ € ๋‚˜์˜ค๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์•ผ ์œ„์—์„œ๋ถ€ํ„ฐ ์•„๋ž˜๋กœ ํŒŒ์ผ์„ ์ฝ๊ธฐ๊ฐ€ ์ข‹๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด ๋ฃฐ์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊นจ๋—ํ•˜๊ฒŒ ํ•ด์ฃผ๋ฉฐ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ํ•„์š”ํ•œ ๊ฒƒ๋งŒ ๋‚จ๊ฒจ๋‘ก๋‹ˆ๋‹ค.

// ๐Ÿ‘Ž ํด๋กœ์ ธ๋ฅผ ์œ ์ง€ํ•  ํ•„์š” ์—†๋Š” ๋ณต์žกํ•œ ํ•จ์ˆ˜๋ฅผ ํ”ผํ•˜์„ธ์š”.
function Component({ date }) {
  function parseDate(rawDate) {
    ...
  }

  return <div>Date is {parseDate(date)}</div>
}

// ๐Ÿ‘ ํ—ฌํผํ•จ์ˆ˜๋Š” ์ปดํฌ๋„ŒํŠธ ์œ„์— ๋‘์„ธ์š”
function parseDate(date) {
  ...
}

function Component({ date }) {
  return <div>Date is {parseDate(date)}</div>
}

์—ฌ๋Ÿฌ๋ถ„์€ ์ •์˜ํ•œ ํ•จ์ˆ˜ ๋‚ด์— ์ ์€ ์–‘์˜ ํ—ฌํผํ•จ์ˆ˜๋ฅผ ์œ ์ง€ํ•˜๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•œ ํ•œ ํ—ฌํผ ํ•จ์ˆ˜๋Š” ๋ฐ–์œผ๋กœ ์˜ฎ๊ฒจ๋‘๊ณ  ์ธ์ž๋กœ ์ƒํƒœ๊ฐ’์„ ์ „๋‹ฌํ•˜์„ธ์š”.
๋กœ์ง์„ ์ž…๋ ฅ๊ฐ’์— ์˜์กดํ•˜๋Š” ์ˆœ์ˆ˜ํ•จ์ˆ˜๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋ฒ„๊ทธ๋ฅผ ์ฐพ๊ธฐ๊ฐ€ ์šฉ์ดํ•˜๋ฉฐ ํ™•์žฅ์„ฑ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

// ๐Ÿ‘Ž ํ—ฌํผ ํ•จ์ˆ˜๊ฐ€ ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ์—์„œ ์ฝํžˆ๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค.
export default function Component() {
  const [value, setValue] = useState('')

  function isValid() {
    // ...
  }

  return (
    <>
      <input
        value={value}
        onChange={e => setValue(e.target.value)}
        onBlur={validateInput}
      />
      <button
        onClick={() => {
          if (isValid) {
            // ...
          }
        }}
      >
        Submit
      </button>
    </>
  )
}

// ๐Ÿ‘ ํ—ฌํผํ•จ์ˆ˜๋Š” ๋ฐ–์œผ๋กœ ๋นผ์„œ ํ•„์š”ํ•œ ๊ฐ’๋งŒ ์ „๋‹ฌํ•˜์„ธ์š”.
function isValid(value) {
  // ...
}

export default function Component() {
  const [value, setValue] = useState('')

  return (
    <>
      <input
        value={value}
        onChange={e => setValue(e.target.value)}
        onBlur={validateInput}
      />
      <button
        onClick={() => {
          if (isValid(value)) {
            // ...
          }
        }}
      >
        Submit
      </button>
    </>
  )
}

๋งˆํฌ์—…์„ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ๋งˆ๋ผ (Don't Hardcode Markup)

๋„ค๋น„๊ฒŒ์ด์…˜, ํ•„ํ„ฐ, ๋ชฉ๋ก์— ๋Œ€ํ•œ ๋งˆํฌ์—…์„ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ๋งˆ์„ธ์š”. ๋Œ€์‹  ๊ฐ์ฒด ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์•„์ดํ…œ์„ ์ˆœํšŒํ•˜์„ธ์š”.
์ฆ‰, ํ•œ ๊ณณ์—์„œ๋งŒ ๋งˆํฌ์—…๊ณผ ์•„์ดํ…œ์„ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

// ๐Ÿ‘Ž ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋งˆํฌ์—…์€ ๊ด€๋ฆฌํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
function Filters({ onFilterClick }) {
  return (
    <>
      <p>Book Genres</p>
      <ul>
        <li>
          <div onClick={() => onFilterClick('fiction')}>Fiction</div>
        </li>
        <li>
          <div onClick={() => onFilterClick('classics')}>
            Classics
          </div>
        </li>
        <li>
          <div onClick={() => onFilterClick('fantasy')}>Fantasy</div>
        </li>
        <li>
          <div onClick={() => onFilterClick('romance')}>Romance</div>
        </li>
      </ul>
    </>
  )
}

// ๐Ÿ‘ loop์™€ ๊ฐ์ฒด ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์„ธ์š”
const GENRES = [
  {
    identifier: 'fiction',
    name: Fiction,
  },
  {
    identifier: 'classics',
    name: Classics,
  },
  {
    identifier: 'fantasy',
    name: Fantasy,
  },
  {
    identifier: 'romance',
    name: Romance,
  },
]

function Filters({ onFilterClick }) {
  return (
    <>
      <p>Book Genres</p>
      <ul>
        {GENRES.map(genre => (
          <li>
            <div onClick={() => onFilterClick(genre.identifier)}>
              {genre.name}
            </div>
          </li>
        ))}
      </ul>
    </>
  )
}

์ปดํฌ๋„ŒํŠธ ๊ธธ์ด (Component Length)

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” props๋ฅผ ๋ฐ›๊ณ  ๋งˆํฌ์—…์„ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋„ ๋™์ผํ•œ ์†Œํ”„ํŠธ์›จ์–ด ์„ค๊ณ„ ์›์น™์„ ์ค€์ˆ˜ํ•ฉ๋‹ˆ๋‹ค.
ํ•จ์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์€ ์ผ์„ ํ•œ๋‹ค๋ฉด, ๋กœ์ง์˜ ์ผ๋ถ€๋ฅผ ๊บผ๋‚ด์„œ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ปดํฌ๋„ŒํŠธ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.
๋„ˆ๋ฌด ๋งŽ์€ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ผ๋ฉด ์ž‘์€ ์ปดํฌ๋„ŒํŠธ๋“ค๋กœ ์ชผ๊ฐœ์„œ ํ˜ธ์ถœํ•˜๋„๋ก ํ•˜์„ธ์š”.

๋งˆํฌ์—…์˜ ์–ด๋Š ๋ถ€๋ถ„์ด ๋ฐ˜๋ณต๋ฌธ์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์กฐ๊ฑด๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณต์žกํ•˜๋‹ค๋ฉด ๋ฐ–์œผ๋กœ ๋นผ๋‘์„ธ์š”.
์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜๊ณผ ๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•œ props์™€ callback์— ์˜์กดํ•˜์„ธ์š”. ์ฝ”๋“œ์˜ ๋ผ์ธ์€ ๊ฐ๊ด€์ ์ธ ์ฒ™๋„๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
๋Œ€์‹ ์— ์ฑ…์ž„๊ฐ๊ณผ ์ถ”์ƒ์„ฑ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด๋ณด์„ธ์š”.

JSX์—์„œ ์ฃผ์„์„ ์‚ฌ์šฉํ•˜๋ผ (Write Comments in JSX)

๋” ๋ช…ํ™•ํ•˜๊ฒŒ ํ•ด์•ผ ํ•  ๋•Œ ์ฝ”๋“œ ๋ธ”๋ก์„ ์—ด๊ณ  ์ถ”๊ฐ€์ ์ธ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์„ธ์š”. ๋งˆํฌ์—…์€ ๋กœ์ง์˜ ์ผ๋ถ€์ด๋ฏ€๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ ํ•  ๋•Œ ์ฃผ์„์„ ์ž‘์„ฑํ•˜์„ธ์š”.

function Component(props) {
  return (
    <>
      {/* If the user is subscribed we don't want to show them any ads */}
      {user.subscribed ? null : <SubscriptionPlans />}
    </>
  )
}

Error Boundary๋ฅผ ์‚ฌ์šฉํ•˜๋ผ (Use Error Boundaries)

ํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๊ณ  ํ•ด์„œ ์ „์ฒด UI๊ฐ€ ๊นจ์ง€๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค. ์‹ฌ๊ฐํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ํŽ˜์ด์ง€๋ฅผ ํ†ต์งธ๋กœ ๋‚ด๋ฆฌ๊ฑฐ๋‚˜ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ๋Š” ๋“œ๋ฌธ ์ผ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์Šคํฌ๋ฆฐ์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๋ถ€๋ถ„๋งŒ ์ˆจ๊ธฐ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ํ•จ์ˆ˜์—์„œ ์—ฌ๋Ÿฌ try/catch ๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์ด ์•„๋‹ˆ๋”๋ผ๋„ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ๊ณณ์— Error boundary๋ฅผ ๋‘์„ธ์š”.
๋ณ„๊ฐœ๋กœ ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” ์Šคํฌ๋ฆฐ์˜ element๋ฅผ ๊ฐ์‹ธ๋ฉด ์ด์–ด์ง€๋Š” ์žฅ์• ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function Component() {
  return (
    <Layout>
      <ErrorBoundary>
        <CardWidget />
      </ErrorBoundary>

      <ErrorBoundary>
        <FiltersWidget />
      </ErrorBoundary>

      <div>
        <ErrorBoundary>
          <ProductList />
        </ErrorBoundary>
      </div>
    </Layout>
  )
}

props๋ฅผ ๋น„๊ตฌ์กฐํ™”ํ•˜๋ผ (Destructure Props)

๋Œ€๋ถ€๋ถ„์˜ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ํ•จ์ˆ˜์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. props๋ฅผ ๋ฐ›์•„ ๋งˆํฌ์—…์„ ๋ฆฌํ„ดํ•˜์ฃ . ์ผ๋ฐ˜ ํ•จ์ˆ˜์—์„œ ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ธ์ˆ˜๊ฐ€ ์ง์ ‘ ์ „๋‹ฌ๋˜๋ฏ€๋กœ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์—๋„ ๋™์ผํ•œ ์›๋ฆฌ๋ฅผ ์ ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์–ด๋””์„œ๋‚˜ props๋ฅผ ๋ฐ˜๋ณตํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

props๋ฅผ ๋น„๊ตฌ์กฐํ™”ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ์•„๋งˆ ์™ธ๋ถ€์—์„œ ์˜จ ๊ฒƒ๊ณผ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ตฌ๋ถ„์ง“๊ธฐ ์œ„ํ•จ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ผ๋ฐ˜ ํ•จ์ˆ˜์—์„œ ์ธ์ž์™€ ๋ณ€์ˆ˜์˜ ๊ตฌ๋ถ„์ด ๋”ฐ๋กœ ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ถˆํ•„์š”ํ•œ ํŒจํ„ด์„ ๋งŒ๋“ค์ง€ ๋งˆ์„ธ์š”.

// ๐Ÿ‘Ž ์ปดํฌ๋„ŒํŠธ ์–ด๋””์—์„œ๋“ ์ง€ props๋ฅผ ๋ฐ˜๋ณตํ•˜์ง€ ๋งˆ์„ธ์š”
function Input(props) {
  return <input value={props.value} onChange={props.onChange} />
}

// ๐Ÿ‘ props๋ฅผ ๋น„๊ตฌ์กฐํ™”ํ•˜์—ฌ ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜์„ธ์š”
function Component({ value, onChange }) {
  const [state, setState] = useState('')

  return <div>...</div>
}

props์˜ ์ˆ˜ (Number of Props)

์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ›๋Š” props์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋ช‡๊ฐœ์—ฌ์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์งˆ๋ฌธ์€ ์ฃผ๊ด€์ ์ž…๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ€์ง€๋Š” props์˜ ์ˆ˜๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•˜๋Š” ๊ฒƒ๊ณผ ์ƒ๊ด€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋” ๋งŽ์ด props๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜๋ก ์ปดํฌ๋„ŒํŠธ์˜ ์ฑ…์ž„๋„ ํ•จ๊ป˜ ์ปค์ง‘๋‹ˆ๋‹ค. props๊ฐ€ ๋„ˆ๋ฌด ๋งŽ๋‹ค๋ฉด ์ด๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์€ ์ผ์„ ํ•œ๋‹ค๋Š” ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค.

์ €๋Š” 5๊ฐœ ์ด์ƒ์˜ props๋ฅผ ๋ฐ›๋Š”๋‹ค๋ฉด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‚˜๋ˆ„์–ด์•ผ ํ• ์ง€๋ฅผ ์ƒ๊ฐํ•ด ๋ด…๋‹ˆ๋‹ค. ์ผ๋ถ€์˜ ๊ฒฝ์šฐ์—์„œ ๋งŽ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด input ํ•„๋“œ๋Š” ๋งŽ์€ props๋ฅผ ๋ฐ›์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฒฝ์šฐ์—์„œ๋Š” ๋‚˜๋ˆ„์–ด์•ผ ํ•œ๋‹ค๋Š” ์‹ ํ˜ธ๊ฐ€ ๋˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜ : ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ€์ง€๋Š” props๊ฐ€ ๋งŽ์„ ์ˆ˜๋ก ๋ฆฌ๋ Œ๋”๋ง๋˜์–ด์•ผ ํ•  ์ด์œ ๋„ ๋งŽ์•„์ง‘๋‹ˆ๋‹ค!

์›์‹œ๊ฐ’ ๋Œ€์‹  ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋ผ (Pass Objects Instead of Primitives)

props์˜ ์–‘์„ ์ค„์ด๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋Š” ์›์‹œ๊ฐ’ ๋Œ€์‹ ์— ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ฆ„, ์ด๋ฉ”์ผ, ์„ค์ • ๋“ฑ์„ ๋ฐ”๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ ๋Œ€์‹ ์— ๋ฌถ์–ด์„œ ๊ฐ์ฒด๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์ฃ . ์ด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ถ”๊ฐ€์ ์ธ ๊ฐ’์„ ์ „๋‹ฌํ•  ๋•Œ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์„ ์ค„์—ฌ์ค๋‹ˆ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋ฅผ ๋” ์‰ฝ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

// ๐Ÿ‘Ž ๊ด€๋ จ๋œ ๊ฐ’์ด๋ผ๋ฉด ํ•˜๋‚˜์”ฉ ์ „๋‹ฌํ•˜์ง€ ๋งˆ์„ธ์š”
<UserProfile
  bio={user.bio}
  name={user.name}
  email={user.email}
  subscription={user.subscription}
/>

// ๐Ÿ‘ ๋Œ€์‹ ์— ๊ฐ์ฒด๋กœ ๋ฌถ์–ด ๋ณด๋‚ด์„ธ์š”
<UserProfile user={user} />

์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง (Conditional Rendering)

์ผ๋ถ€ ์ƒํ™ฉ์—์„œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ์œ„ํ•ด ๋‹จ๋ฝ ์—ฐ์‚ฐ์ž(&&)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์—ญํšจ๊ณผ๋ฅผ ๋‚ณ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์—ฌ๋Ÿฌ๋ถ„์˜ UI์— ์›์น˜์•Š๋Š” 0์ด ๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์ƒํ™ฉ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ๋‹ค๋งŒ ์ข€ ๋” ์žฅํ™ฉํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋‹จ๋ฝ ์—ฐ์‚ฐ์ž๋Š” ์ฝ”๋“œ์˜ ์–‘์„ ์ค„์—ฌ์ฃผ๊ณ  ์ด๋Š” ์•„์ฃผ ์ข‹์Šต๋‹ˆ๋‹ค. ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋Š” ๋” ๋ณต์žกํ•˜์ง€๋งŒ ์ž˜๋ชป๋  ์—ฌ์ง€๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ๋‹ค๋ฅธ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜๋”๋ผ๋„ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ ์Šต๋‹ˆ๋‹ค.

// ๐Ÿ‘Ž ๋‹จ๋ฝ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ง€์–‘ํ•˜์„ธ์š”
function Component() {
  const count = 0

  return <div>{count && <h1>Messages: {count}</h1>}</div>
}

// ๐Ÿ‘ ๋Œ€์‹  ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”
function Component() {
  const count = 0

  return <div>{count ? <h1>Messages: {count}</h1> : null}</div>
}

์ค‘์ฒฉ๋œ ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋ฅผ ์ง€์–‘ํ•˜๋ผ (Avoid Nested Ternary Operators)

์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋Š” ํ•œ ๋‹จ๊ณ„๋ฅผ ์ง€๋‚˜๊ฐ€๊ฒŒ ๋˜๋ฉด ์ฝ๊ธฐ ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค. ๊ณต๊ฐ„์„ ์ ˆ์•ฝํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋”๋ผ๋„ ์—ฌ๋Ÿฌ๋ถ„์˜ ์˜๋„๋ฅผ ๋ถ„๋ช…ํžˆ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

// ๐Ÿ‘Ž JSX์—์„œ ์ค‘์ฒฉ๋œ ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋Š” ์ฝ๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
isSubscribed ? (
  <ArticleRecommendations />
) : isRegistered ? (
  <SubscribeCallToAction />
) : (
  <RegisterCallToAction />
)

// ๐Ÿ‘ ์ปดํฌ๋„ŒํŠธ ๋‚ด์— ๋‘์„ธ์š”
function CallToActionWidget({ subscribed, registered }) {
  if (subscribed) {
    return <ArticleRecommendations />
  }

  if (registered) {
    return <SubscribeCallToAction />
  }

  return <RegisterCallToAction />
}

function Component() {
  return (
    <CallToActionWidget
      subscribed={subscribed}
      registered={registered}
    />
  )
}

๋ฐฐ์—ด์€ ๋ณ„๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ์˜ฎ๊ฒจ๋ผ (Move Lists in a Separate Component)

map ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ ค ์•„์ดํ…œ์˜ ๋ฐฐ์—ด์„ ์ˆœํšŒํ•˜๋Š” ๊ฒƒ์€ ํ”ํžˆ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๋Ÿฌ ๋งˆํฌ์—…์„ ๊ฐ€์ง„ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ์ถ”๊ฐ€์ ์ธ ์—ฌ๋ฐฑ์ด๋‚˜ map ๋ฌธ๋ฒ•์€ ๊ฐ€๋…์„ฑ์„ ํ•ด์นฉ๋‹ˆ๋‹ค. map์œผ๋กœ ์ˆœํšŒํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋งˆํฌ์—…์ด ๋งŽ์ง€ ์•Š๋”๋ผ๋„ ๊ทธ ๋ถ€๋ถ„์„ ๋”ฐ๋กœ ๋นผ์„œ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌํ•˜์„ธ์š”. ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋Š” ์ž์„ธํ•œ ๋ถ€๋ถ„์„ ์•Œ ํ•„์š”์—†์ด ๋ฐฐ์—ด์„ ๋‚˜ํƒ€๋‚ด๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ์˜ ์ฃผ ์—ญํ• ์ด ๋ณด์—ฌ์ฃผ๊ธฐ๋ผ๋ฉด ๋งˆํฌ์—…์— ๋ฃจํ”„๋ฅผ ๋‘๊ธฐ๋งŒ ํ•˜์„ธ์š”. ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค ํ•˜๋‚˜์˜ ๋งคํ•‘์„ ๋‘๋„๋ก ํ•˜์„ธ์š”. ๋งˆํฌ์—…์ด ๋„ˆ๋ฌด ๊ธธ์–ด์ง€๊ฑฐ๋‚˜ ๋ณต์žกํ•ด์ง„๋‹ค๋ฉด ๋”ฐ๋กœ ๋นผ๋‘๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

// ๐Ÿ‘Ž ๋ฐ˜๋ณต๋ฌธ๊ณผ ๋‹ค๋ฅธ ๋งˆํฌ์—…์„ ๊ฐ™์ด ๋‘์ง€ ๋งˆ์„ธ์š”.
function Component({ topic, page, articles, onNextPage }) {
  return (
    <div>
      <h1>{topic}</h1>
      {articles.map(article => (
        <div>
          <h3>{article.title}</h3>
          <p>{article.teaser}</p>
          <img src={article.image} />
        </div>
      ))}
      <div>You are on page {page}</div>
      <button onClick={onNextPage}>Next</button>
    </div>
  )
}

// ๐Ÿ‘ ๋ฐฐ์—ด์— ๋Œ€ํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋”ฐ๋กœ ๋นผ์„ธ์š”
function Component({ topic, page, articles, onNextPage }) {
  return (
    <div>
      <h1>{topic}</h1>
      <ArticlesList articles={articles} />
      <div>You are on page {page}</div>
      <button onClick={onNextPage}>Next</button>
    </div>
  )
}

๋น„๊ตฌ์กฐํ™”๋ฅผ ํ•  ๋•Œ ๊ธฐ๋ณธ props๋ฅผ ํ• ๋‹นํ•˜๋ผ (Assign Default Props When Destructuring)

๊ธฐ๋ณธ prop ๊ฐ’์„ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ปดํฌ๋„ŒํŠธ์— defaultProps๋ฅผ ๋‘๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์™€ ์ธ์ž ๊ฐ’์ด ํ•จ๊ป˜ ์žˆ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. props๋ฅผ ๋น„๊ตฌ์กฐํ™”ํ•  ๋•Œ ๊ธฐ๋ณธ๊ฐ’์„ ๋ฐ”๋กœ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์„ ์ง€ํ–ฅํ•˜์„ธ์š”. ์ด๋Š” ์ฝ”๋“œ๋ฅผ ์œ„์—์„œ๋ถ€ํ„ฐ ์ฝ๊ธฐ ํŽธํ•˜๊ฒŒ ํ•˜๋ฉฐ ์ •์˜์™€ ๊ฐ’์„ ํ•จ๊ป˜ ๋‘ก๋‹ˆ๋‹ค.

// ๐Ÿ‘Ž default props๋ฅผ ํ•จ์ˆ˜ ๋ฐ–์— ์ •์˜ํ•˜์ง€ ๋งˆ์„ธ์š”
function Component({ title, tags, subscribed }) {
  return <div>...</div>
}

Component.defaultProps = {
  title: '',
  tags: [],
  subscribed: false,
}

// ๐Ÿ‘ ์ธ์ž ๋ชฉ๋ก์— ํ•จ๊ป˜ ๋‘์„ธ์š”
function Component({ title = '', tags = [], subscribed = false }) {
  return <div>...</div>
}

์ค‘์ฒฉ๋œ ๋ Œ๋” ํ•จ์ˆ˜๋ฅผ ์ง€์–‘ํ•˜๋ผ (Avoid Nested Render Functions)

์ปดํฌ๋„ŒํŠธ๋‚˜ ๋กœ์ง์œผ๋กœ๋ถ€ํ„ฐ ๋งˆํฌ์—…์„ ๋ถ„๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๋•Œ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ ๋‚ด์— ๋งˆํฌ์—… ํ•จ์ˆ˜๋ฅผ ๋‘์ง€ ๋งˆ์„ธ์š”. ์ปดํฌ๋„ŒํŠธ๋Š” ํ•จ์ˆ˜์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.
์ด๋ ‡๊ฒŒ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ฒŒ ๋˜๋ฉด ๋ถ€๋ชจ ํ•จ์ˆ˜ ๋‚ด์—์„œ ๋‘ฅ์ง€๋ฅผ ํŠธ๋Š” ์…ˆ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋ถ€๋ชจ์˜ ์ƒํƒœ๋‚˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋Š”๋ฐ์š”.
์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ํ•จ์ˆ˜๊ฐ€ ํ•˜๋Š” ์ผ์ด ์—†์Œ์—๋„ ๋‚ด๋ถ€์— ์žˆ๋‹ค๋ฉด ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ํ•ด์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋งˆํฌ์—… ์ปดํฌ๋„ŒํŠธ๋กœ ์˜ฎ๊ธฐ๊ณ  ์ด๋ฆ„์„ ์ง“๊ณ  ํด๋กœ์ ธ ๋Œ€์‹ ์— props๋กœ ์ „๋‹ฌํ•˜์„ธ์š”.

// ๐Ÿ‘Ž ์ค‘์ฒฉ๋˜๋„๋ก ๋ Œ๋”ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์ง€ ๋งˆ์„ธ์š”
function Component() {
  function renderHeader() {
    return <header>...</header>
  }
  return <div>{renderHeader()}</div>
}

// ๐Ÿ‘ ๊ฐ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌํ•˜์„ธ์š”
import Header from '@modules/common/components/Header'

function Component() {
  return (
    <div>
      <Header />
    </div>
  )
}

[๋ฒˆ์—ญ] ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ Never ์™„๋ฒฝ ๊ฐ€์ด๋“œ

์›๋ฌธ : https://www.zhenghao.io/posts/ts-never

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ never๋Š” ๋‹ค๋ฅธ ํƒ€์ž…๋“ค๋งŒํผ ์•„์ฃผ ํ”ํ•˜๊ฑฐ๋‚˜ ๋ฌด์‹œํ•  ์ˆ˜ ์—†๋Š” ํƒ€์ž…์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋‹ค์ง€ ํ™œ๋ฐœํ•˜๊ฒŒ ๋…ผ์˜๋˜๋Š” ํƒ€์ž…์ด ์•„๋‹™๋‹ˆ๋‹ค. ์‹ฌํ™”๋œ ํƒ€์ž…์„ ๋‹ค๋ฃจ๊ฑฐ๋‚˜ ๊นŒ๋‹ค๋กœ์šด ํƒ€์ž… ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ์„ ๋•Œ๋‚˜ ๋“ฑ์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ดˆ๊ธ‰์ž๋“ค์€ ์•„๋งˆ never ํƒ€์ž…์„ ๋ฌด์‹œํ•˜๊ณ ๋„ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

never ํƒ€์ž…์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ฝค ์ข‹์€ ์œ ์ฆˆ ์ผ€์ด์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ๊ทธ๋งŒํผ ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์กฐ์‹ฌํ•ด์•ผ ํ•˜๋Š” ์œ„ํ—˜๋“ค๋„ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ๊ธ€์—์„œ๋Š” ๋‹ค์Œ ๋‚ด์šฉ์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

  • never ํƒ€์ž…์˜ ์˜๋ฏธ์™€ ํ•„์š”์„ฑ
  • never ํƒ€์ž…์˜ ์‘์šฉ๊ณผ ์œ„ํ—˜
  • ์—ฌ๋Ÿฌ ๋ง์žฅ๋‚œ๋“ค ๐Ÿคฃ

never ํƒ€์ž…์ด ๋ฌด์—‡์ผ๊นŒ?

never ํƒ€์ž…๊ณผ ์ด๊ฒƒ์˜ ๋ชฉ์ ์„ ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, ํƒ€์ž…์ด๋ž€ ๋ฌด์—‡์ธ์ง€ ๊ทธ๋ฆฌ๊ณ  ํƒ€์ž… ์‹œ์Šคํ…œ์—์„œ ํƒ€์ž…์ด ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ๋จผ์ € ์ดํ•ดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
ํƒ€์ž…์€ ๊ฐ€๋Šฅํ•œ ๊ฐ’๋“ค์˜ ์ง‘ํ•ฉ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด string ํƒ€์ž…์€ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ž์—ด์˜ ๋ฌดํ•œ์ง‘ํ•ฉ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋ณ€์ˆ˜์— string ํƒ€์ž…์ด๋ผ๊ณ  ๋ถ™์—ฌ์ค„ ๋•Œ, ๊ทธ ๋ณ€์ˆ˜๋Š” ๋ฌธ์ž์—ด ์ง‘ํ•ฉ ๋‚ด์—์„œ๋งŒ ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

let foo: string = 'foo'
foo = 3 // โŒ ์ˆซ์ž๋Š” ๋ฌธ์ž์—ด ์ง‘ํ•ฉ์— ์†ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ never๋Š” ๊ฐ’๋“ค์˜ ๊ณต์ง‘ํ•ฉ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๋˜๋‹ค๋ฅธ ์œ ๋ช…ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํƒ€์ž… ์‹œ์Šคํ…œ์ธ Flow์—์„œ๋„ never์™€ ๋™์ผํ•œ ํƒ€์ž…์„ empty๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ต๋‹ˆ๋‹ค.

์ง‘ํ•ฉ์— ๊ฐ’์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— never๋Š” any ํƒ€์ž…์„ ํฌํ•จํ•˜์—ฌ ์ ˆ๋Œ€๋กœ(never ใ…‹) ์–ด๋– ํ•œ ๊ฐ’๋„ ๊ฐ€์งˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. never๊ฐ€ ๋•Œ๋•Œ๋กœ ๊ฑฐ์ฃผ ๋ถˆ๊ฐ€๋Šฅํ•œ ํƒ€์ž…(uninhabitable type) ๋˜๋Š” ๋ฐ”๋‹ฅ ํƒ€์ž…(bottom type)์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค.

declare const any: any
const never: never = any // โŒ 'any' ํƒ€์ž…์€ 'never'์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ฐ”๋‹ฅ ํƒ€์ž…์€ TypeScript Handbook์—์„œ ์ •์˜ํ•œ ๋‹จ์–ด์ž…๋‹ˆ๋‹ค. ์ €๋Š” ์„œ๋ธŒํƒ€์ดํ•‘์„ ์ดํ•ดํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ํƒ€์ž… ๊ณ„์ธต ํŠธ๋ฆฌ์—์„œ never๋ฅผ ๋‘์ง€ ์•Š๋Š” ๊ฒŒ ๋” ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ๋…ผ๋ฆฌ์ ์ธ ์งˆ๋ฌธ์€, '์™œ never ํƒ€์ž…์ด ํ•„์š”ํ•œ๊ฐ€?' ์ž…๋‹ˆ๋‹ค.

์™œ ์šฐ๋ฆฌ๋Š” never ํƒ€์ž…์ด ํ•„์š”ํ• ๊นŒ?

์ˆซ์ž ์‹œ์Šคํ…œ์—์„œ ์•„๋ฌด๊ฒƒ๋„ ๊ฐ€์ง€์ง€ ์•Š์•˜๋‹ค๋Š” ๊ฒƒ์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๊ฐ€ 0์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ํƒ€์ž… ์‹œ์Šคํ…œ๋„ ๋ถˆ๊ฐ€๋Šฅํ•จ์„ ๋‚˜ํƒ€๋‚ด๋Š” ํƒ€์ž…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. "๋ถˆ๊ฐ€๋Šฅํ•จ"์ด๋ž€ ๋‹จ์–ด ์ž์ฒด๊ฐ€ ๋ชจํ˜ธํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ "๋ถˆ๊ฐ€๋Šฅํ•จ"์€ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

  • ๋‹ค์Œ์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š”, ์–ด๋– ํ•œ ๊ฐ’๋„ ๊ฐ€์ง€์ง€ ์•Š๋Š” ๋นˆ ํƒ€์ž…
    • ์ œ๋„ค๋ฆญ๊ณผ ํ•จ์ˆ˜์—์„œ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ
    • ์„œ๋กœ ๋ฐฐํƒ€์ ์ธ ํƒ€์ž…๋“ค์˜ ๊ต์นฉํ•ฉ
    • ๋น„์–ด์žˆ๋Š” ํ•ฉ์ง‘ํ•จ (์—†์Œ์˜ ํ•ฉ์ง‘ํ•ฉ)
  • ์‹คํ–‰์ด ์™„๋ฃŒ๋˜์—ˆ์„ ๋•Œ ํ˜ธ์ถœ์ž(caller)์—๊ฒŒ ์ œ์–ด๋ฅผ ์•„๋ฌด๊ฒƒ๋„(never) ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด ํƒ€์ž… (Node์—์„œ process.exit์ฒ˜๋Ÿผ)
    • void์™€ ํ˜ผ๋™ํ•˜์ง€ ๋งˆ์„ธ์š”. void๋Š” ํ˜ธ์ถœ์ž์—๊ฒŒ ์œ ์šฉํ•œ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ฆฌํ„ดํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.
  • ์กฐ๊ฑด๋ฌธ์—์„œ ์ ˆ๋Œ€(never) ๋“ค์–ด๊ฐˆ ์ˆ˜ ์—†๋Š” else ๋ถ„๊ธฐ
  • reject๋œ promise์˜ fulfilled๋œ ๊ฐ’์˜ ํƒ€์ž…
const p = Promise.reject('foo') // const p: Promise<never>

never ํƒ€์ž…์€ ํ•ฉ์ง‘ํ•ฉ(union)๊ณผ ๊ต์ง‘ํ•ฉ(intersection)์—์„œ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ• ๊นŒ?

๋ง์…ˆ, ๊ณฑ์…ˆ์—์„œ 0์ด ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ, never ํƒ€์ž…์€ union ํƒ€์ž…๊ณผ intersection ํƒ€์ž…์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํŠน๋ณ„ํ•œ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

  • never์™€ ํ•ฉ์ง‘ํ•ฉ์„ ํ•˜๊ฒŒ ๋˜๋ฉด never๋Š” ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ์ˆซ์ž์— 0์„ ๋”ํ–ˆ์„ ๋•Œ ๊ทธ ์ˆซ์ž๊ฐ€ ๊ทธ๋Œ€๋กœ์ธ ๊ฒƒ๊ณผ ๊ฐ™์€ ์›๋ฆฌ์ž…๋‹ˆ๋‹ค.
    • ์˜ˆ์‹œ) type Res = never | string // string
  • never์™€ intersection ํ•˜๊ฒŒ ๋˜๋ฉด ๋‹ค๋ฅธ ํƒ€์ž…์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ์ˆซ์ž์— 0์„ ๊ณฑํ•˜๋ฉด 0์ด ๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ž…๋‹ˆ๋‹ค.
    • ์˜ˆ์‹œ) type Res = never & string // never

never ํƒ€์ž…์ด ๊ฐ€์ง€๋Š” ๋‘ ๊ฐ€์ง€ ๋™์ž‘/ํŠน์„ฑ์€ ๋‚˜์ค‘์— ๋ณด๊ฒŒ ๋  ๋ช‡๋ช‡ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์œ ์ฆˆ ์ผ€์ด์Šค์˜ ๊ธฐ๋ฐ˜์„ ๋งˆ๋ จํ•ด์ค๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ never ํƒ€์ž…์„ ์‚ฌ์šฉํ• ๊นŒ?

์•„๋งˆ ์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ์Šค์Šค๋กœ never๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง„ ์•Š์•˜๊ฒ ์ง€๋งŒ, ์ด๋ฏธ ๊ฝค ์ž˜ ์‚ฌ์šฉ๋˜๋Š” ์œ ์ฆˆ ์ผ€์ด์Šค๋“ค์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ œํ•œํ•˜๊ธฐ

์–ด๋–ค ๊ฐ’์— never ํƒ€์ž…์„ ํ• ๋‹นํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๋Š” ๋‹ค์–‘ํ•œ ์‘์šฉ์„ ์œ„ํ•ด ํ•จ์ˆ˜์— ์ œํ•œ์„ ๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ never๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

switch๋ฌธ๊ณผ if-else๋ฌธ์—์„œ ์™„์ „ํžˆ ์ผ์น˜ํ•˜๋Š”์ง€ ๋ณด์žฅ

์–ด๋–ค ํ•จ์ˆ˜๊ฐ€ ์˜ค์ง never ํƒ€์ž…์ธ ํ•˜๋‚˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋งŒ ๋ฐ›๋Š”๋‹ค๋ฉด ๊ทธ ํ•จ์ˆ˜๋Š” never๊ฐ€ ์•„๋‹Œ ๊ฐ’๊ณผ ํ•จ๊ป˜ ํ˜ธ์ถœ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

function fn(input: never) {}

// `never`๋งŒ ํ—ˆ์šฉ
declare let myNever: never
fn(myNever) // โœ…

// ๋‹ค๋ฅธ ๊ฑธ ์ „๋‹ฌํ•˜๋ฉด ํƒ€์ž… ์—๋Ÿฌ ๋ฐœ์ƒ
fn() // โŒ 'input`์— ๋Œ€ํ•œ ์ธ์ž๊ฐ€ ์ฃผ์–ด์ง€์ง€ ์•Š์Œ.
fn(1) // โŒ number ํƒ€์ž…์€ never์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Œ
fn('foo') // โŒ string ํƒ€์ž…์€ never์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Œ

// ์‹ฌ์ง€์–ด any๋„ ๋ถˆ๊ฐ€๋Šฅ
declare let myAny: any
fn(myAny) // โŒ any ํƒ€์ž…์€ never์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Œ

์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ switch๋ฌธ๊ณผ if-else๋ฌธ์—์„œ ์™„์ „ํžˆ ์ผ์น˜ํ•˜๋„๋ก ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚จ์€ ํƒ€์ž…์€ ๋ฐ˜๋“œ์‹œ never ํƒ€์ž…์ด๋ฏ€๋กœ default ์ผ€์ด์Šค๋กœ never ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  ๊ฒฝ์šฐ๊ฐ€ ์ปค๋ฒ„๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์‹ค์ˆ˜๋กœ ์ผ์น˜ํ•˜๋Š” ํ•ญ๋ชฉ์„ ๋ˆ„๋ฝํ•˜๋ฉด ํƒ€์ž… ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

function unknownColor(x: never): never {
    throw new Error("unknown color");
}


type Color = 'red' | 'green' | 'blue'

function getColorName(c: Color): string {
    switch(c) {
        case 'red':
            return 'is red';
        case 'green':
            return 'is green';
        default:
            return unknownColor(c); // Argument of type 'string' is not assignable to parameter of type 'never'
    }
}

๊ตฌ์กฐ์ ์ธ ํƒ€์ดํ•‘์„ ๋ถ€๋ถ„์ ์œผ๋กœ ๋น„ํ—ˆ์šฉ

VariantA ๋˜๋Š” VariantB๋ฅผ ๊ฐ€์ง€๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ์šฉ์ž๊ฐ€ ๋‘ ์œ ํ˜•์˜ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ํƒ€์ž…์„ ์ „๋‹ฌํ•ด์„œ๋Š” ์•ˆ๋˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์œ ๋‹ˆ์˜จ ํƒ€์ž…์ธ VariantA | VariantB์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ํƒ€์ž… ํ˜ธํ™˜์„ฑ์€ ๊ตฌ์กฐ์ ์ธ ์„œ๋ธŒํƒ€์ดํ•‘์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ํƒ€์ž…๋ณด๋‹ค ๋” ๋งŽ์€ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๋Š” ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. (๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์„ ์ „๋‹ฌํ•˜์ง€ ์•Š๋Š” ํ•œ)

type VariantA = {
    a: string,
}

type VariantB = {
    b: number,
}

declare function fn(arg: VariantA | VariantB): void

const input = {a: 'foo', b: 123 }
fn(input) // TypeScript๊ฐ€ ์•ˆ๋œ๋‹ค๊ณ  ํ•˜์ง„ ์•Š์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ์ด๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์œ„์˜ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์—์„œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ํƒ€์ž… ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
never๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๋ถ€๋ถ„์ ์œผ๋กœ ๊ตฌ์กฐ์  ํƒ€์ดํ•‘์„ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ณ  ์‚ฌ์šฉ์ž๋“ค์ด ๋‘ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋‹ค ๊ฐ€์ง€๋Š” ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

type VariantA = {
    a: string
    b?: never
}

type VariantB = {
    b: number
    a?: never
}

declare function fn(arg: VariantA | VariantB): void

const input = {a: 'foo', b: 123 }
fn(input) // โŒ Types of property 'a' are incompatible

์˜๋„๋˜์ง€ ์•Š์€ API ์‚ฌ์šฉ ๋ฐฉ์ง€

๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  ์ €์žฅํ•˜๋Š” Cache ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค๊ณ  ํ•ด๋ด…์‹œ๋‹ค.

type Read = {}
type Write = {}
declare const toWrite: Write

declare class MyCache<T, R> {
  put(val: T): boolean;
  get(): R;
}

const cache = new MyCache<Write, Read>()
cache.put(toWrite) // โœ… allowed

์–ด๋– ํ•œ ์ด์œ ๋“ ์ง€ ๊ฐ„์— get ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•œ read-only ์บ์‹œ๋ฅผ ๊ฐ€์ง€๊ณ  ์‹ถ์–ด์งˆ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. put ๋ฉ”์†Œ๋“œ ์ธ์ž์— never ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜๋ฉด ํ•จ์ˆ˜ ๋‚ด๋ถ€๋กœ ์–ด๋– ํ•œ ๊ฐ’์ด๋“  ๋ฐ›์„ ์ˆ˜ ์—†๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

declare class ReadOnlyCache<R> extends MyCache<never, R> {} 
                        // Now type parameter `T` inside MyCache becomes `never`

const readonlyCache = new ReadOnlyCache<Read>()
readonlyCache.put(data) // โŒ Argument of type 'Data' is not assignable to parameter of type 'never'.

๋ถ€๊ฐ€์ ์œผ๋กœ never ํƒ€์ž…๊ณผ๋Š” ๊ด€๋ จ์—†์ง€๋งŒ, ์ด๋Š” ํŒŒ์ƒ ํด๋ž˜์Šค์˜ ์ข‹์€ ์˜ˆ์‹œ๊ฐ€ ์•„๋‹ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์ „๋ฌธ๊ฐ€๊ฐ€ ์‚ฌ์‹ค ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ž ์•Œ์•„์„œ ํŒ๋‹จํ•ด์ฃผ์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ด๋ก ์ ์œผ๋กœ ๋‹ฟ์„ ์ˆ˜ ์—†๋Š” ์กฐ๊ฑด ๋ถ„๊ธฐ๋“ค์„ ๋‚˜ํƒ€๋‚ด๊ธฐ

์กฐ๊ฑด ํƒ€์ž… ๋‚ด์—์„œ ์ถ”๊ฐ€์ ์ธ ํƒ€์ž… ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด infer๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์šฐ๋ฆฌ๋Š” ๋ชจ๋“  infer ํ‚ค์›Œ๋“œ์— ๋ฐ˜๋“œ์‹œ else ๋ถ„๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

type A = 'foo';
type B = A extends infer C ? (
    C extends 'foo' ? true : false// inside this expression, C represents A
) : never // ์ด ๋ถ„๊ธฐ์ ์— ๋‹ฟ์„ ์ˆ˜ ์—†๊ฒ ์ง€๋งŒ ์ƒ๋žตํ•  ์ˆœ ์—†์Šต๋‹ˆ๋‹ค

์™œ extends infer ์ฝค๋ณด๊ฐ€ ์œ ์šฉํ•œ๊ฐ€์š”?
์ด์ „์— ์ž‘์„ฑํ•œ ๊ธ€์—์„œ "๋กœ์ปฌ (ํƒ€์ž…) ๋ณ€์ˆ˜"๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ฐฉ์‹๊ณผ ํ•จ๊ป˜ extends infer๋ฅผ ์–ธ๊ธ‰ํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์•„์ง ์ฝ์ง€ ์•Š์•˜๋‹ค๋ฉด ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

์œ ๋‹ˆ์˜จ ํƒ€์ž…์—์„œ ์œ ๋‹ˆ์˜จ ๋ฉค๋ฒ„ ๋ถ„๋ฆฌํ•˜๊ธฐ

๋ถˆ๊ฐ€๋Šฅํ•œ ๋ถ„๊ธฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ ์™ธ์—๋„, never๋Š” ์กฐ๊ฑด ํƒ€์ž…์—์„œ ์›์น˜์•Š๋Š” ํƒ€์ž…์„ ๋ถ„๋ฆฌํ•ด๋‚ด๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด์ „์—๋„ ์–˜๊ธฐํ–ˆ๋“ฏ์ด, ์œ ๋‹ˆ์˜จ ๋ฉค๋ฒ„๋กœ์จ never๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž๋™์ ์œผ๋กœ ์ œ๊ฑฐ๋œ๋‹ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์œ ๋‹ˆ์˜จ ํƒ€์ž…์—์„œ never๋Š” ์“ธ๋ชจ๊ฐ€ ์—†๋Š” ๊ฒƒ์ด์ฃ .

์–ด๋–ค ๊ธฐ์ค€์ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์œ ๋‹ˆ์˜จ ํƒ€์ž…์—์„œ ์œ ๋‹ˆ์˜จ ๋ฉค๋ฒ„๋ฅผ ์„ ํƒํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž…์„ ์ž‘์„ฑํ•  ๋•Œ never ํƒ€์ž…์˜ ์“ธ๋ชจ์—†์Œ์€ else ๋ถ„๊ธฐ์— ์™„๋ฒฝํ•œ ํƒ€์ž…์„ ๋‘๊ฒŒ๋” ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

foo ๋ฌธ์ž์—ด ๋ฆฌํ„ฐ๋Ÿด์„ ๊ฐ€์ง€๋Š” name ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”์ถœํ•˜๊ณ , ๊ทธ ์™ธ์—๋Š” ํ•„ํ„ฐ๋งํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž…์ธ ExtractTypeByName์„ ์ž‘์„ฑํ•œ๋‹ค๊ณ  ํ•ด๋ณผ๊นŒ์š”.

type Foo = {
    name: 'foo'
    id: number
}

type Bar = {
    name: 'bar'
    id: number
}

type All = Foo | Bar

type ExtractTypeByName<T, G> = T extends {name: G} ? T : never

type ExtractedType = ExtractTypeByName<All, 'foo'> // the result type is Fo

์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์ž์„ธํžˆ ์‚ดํŽด๋ด…์‹œ๋‹ค.
๋‹ค์Œ์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๊ฒฐ๊ณผ ํƒ€์ž…์„ ํ‰๊ฐ€ํ•˜๊ณ  ๊ฐ€์ ธ์˜ค๋Š” ๊ฐ ๋‹จ๊ณ„๋“ค์ž…๋‹ˆ๋‹ค.

  • ์กฐ๊ฑด๋ถ€ ํƒ€์ž…์€ ์œ ๋‹ˆ์˜จ ํƒ€์ž…์— ๊ฑธ์ณ ๋ถ„์‚ฐ๋ฉ๋‹ˆ๋‹ค.
type ExtractedType = ExtractTypeByName<All, Name> 
โฌ‡๏ธ                    
type ExtractedType = ExtractTypeByName<Foo | Bar, 'foo'>
โฌ‡๏ธ    
type ExtractedType = ExtractTypeByName<Foo, 'foo'> | ExtractTypeByName<Bar, 'foo'>
  • ๊ตฌํ˜„์„ ๋Œ€์ฒดํ•˜๊ณ  ๊ฐœ๋ณ„์ ์œผ๋กœ ํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค.
type ExtractedType = Foo extends {name: 'foo'} ? Foo : never 
                    | Bar extends {name: 'foo'} ? Bar : never
โฌ‡๏ธ
type ExtractedType = Foo | never
  • ์œ ๋‹ˆ์˜จ์—์„œ never๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
type ExtractedType = Foo | never
โฌ‡๏ธ
type ExtractedType = Foo

๋งคํ•‘๋œ ํƒ€์ž…์—์„œ key๋ฅผ ํ•„ํ„ฐ๋งํ•˜๊ธฐ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ํƒ€์ž…์€ ๋ถˆ๋ณ€์ž…๋‹ˆ๋‹ค. ๊ฐ์ฒด ํƒ€์ž…์—์„œ ์–ด๋–ค ํ”„๋กœํผํ‹ฐ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํƒ€์ž…์„ ๋ณ€ํ˜•ํ•˜๊ณ  ํ•„ํ„ฐ๋งํ•˜์—ฌ ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ๋งŒ๋“ค์–ด์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. ๋งคํ•‘๋œ ํƒ€์ž…์˜ ํ‚ค๋ฅผ ์กฐ๊ฑด๋ถ€๋กœ ๋‹ค์‹œ never๋กœ ๋งคํ•‘ํ•  ๋•Œ, key๋Š” ํ•„ํ„ฐ๋ง๋ฉ๋‹ˆ๋‹ค.

๊ฐ์ฒด์˜ ๊ฐ’ ํƒ€์ž…์— ๋”ฐ๋ผ ๊ฐ์ฒด ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๋Š” Filter ํƒ€์ž…์— ๋Œ€ํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

type Filter<Obj extends Object, ValueType> = {
    [Key in keyof Obj 
        as ValueType extends Obj[Key] ? Key : never]
        : Obj[Key]
}

interface Foo {
    name: string;
    id: number;
}

type Filtered = Filter<Foo, string>; // {name: string;}

์ œ์–ด ํ๋ฆ„ ๋ถ„์„์—์„œ ํƒ€์ž… ์ขํžˆ๊ธฐ

ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด ๊ฐ’์„ never๋ผ๊ณ  ํƒ€์ž…์„ ์ง€์ •ํ•œ๋‹ค๋Š” ๊ฒƒ์€, ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰์ด ์ข…๋ฃŒ๋˜์—ˆ์„ ๋•Œ ์ ˆ๋Œ€ ํ˜ธ์ถœ์ž์—๊ฒŒ ์ œ์–ด๊ถŒ์„ ๋ฆฌํ„ดํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž…์„ ์ขํžˆ๊ธฐ ์œ„ํ•œ ์ œ์–ด ํ๋ฆ„ ๋ถ„์„์—์„œ ์ด ์ ์„ ์‘์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ ์•„๋ฌด๊ฒƒ๋„ ๋ฆฌํ„ดํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ๋ชจ๋“  ์ฝ”๋“œ ๊ฒฝ๋กœ๋งˆ๋‹ค ์˜ˆ์™ธ๋ฅผ throwํ•˜๋Š” ๊ฒฝ์šฐ, ๋ฌดํ•œ ๋ฃจํ”„์— ๋น ์ง€๋Š” ๊ฒฝ์šฐ, process.exit๊ณผ ๊ฐ™์€ ํ”„๋กœ๊ทธ๋žจ์— ์˜ํ•ด ์ข…๋ฃŒ๋˜๋Š” ๊ฒฝ์šฐ

๋‹ค์Œ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์—์„œ, never ํƒ€์ž…์„ ๋ฆฌํ„ดํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ foor๋ผ๋Š” union ํƒ€์ž…์—์„œ undefined๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function throwError(): never {
    throw new Error();
}

let foo: string | undefined;

if (!foo) {
    throwError();
}

foo; // string

๋˜๋Š” ||๋‚˜ ?? ์—ฐ์‚ฐ์ž ์ดํ›„์— throwError๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

let foo: string | undefined;

const guaranteedFoo = foo ?? throwError(); // string

๊ณต์กดํ•  ์ˆ˜ ์—†๋Š” ํƒ€์ž…๋“ค์˜ ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ต์ง‘ํ•ฉ ๋‚˜ํƒ€๋‚ด๊ธฐ

never์˜ ์‘์šฉ ์‚ฌ๋ก€๋ณด๋‹ค๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์–ธ์–ด์˜ ๋™์ž‘/ํŠน์ง•์— ๋” ๊ฐ€๊น๋‹ค๊ณ  ๋Š๊ปด์งˆ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ์—๋„, ์ด ์ ์€ ์—ฌ๋Ÿฌ๋ถ„์ด ๋งˆ์ฃผ์น  ์ˆ˜๋„ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์•”ํ˜ธ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ ์•„์ฃผ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๊ณต์กดํ•  ์ˆ˜ ์—†๋Š” ํƒ€์ž…๋“ค๋ผ๋ฆฌ ๊ต์ง‘ํ•ฉ ์—ฐ์‚ฐ์„ ํ•˜๋ฉด never ํƒ€์ž…์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

type Res = number & string // never

๋˜ํ•œ, ์–ด๋Š ํƒ€์ž…์ด๋“ ์ง€ never๋กœ ๊ต์ง‘ํ•ฉ ์—ฐ์‚ฐ์„ ํ•˜๋ฉด never๋ฅผ ์–ป๊ฒ ์ฃ .

type Res = number & never // never
์ด๊ฑด ๊ฐ์ฒด ํƒ€์ž…์—์„œ ๋” ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค.
๊ฐ์ฒด ํƒ€์ž…์„ ๊ต์ฐจํ•˜๊ฒŒ ๋˜๋ฉด, ํ”„๋กœํผํ‹ฐ ํƒ€์ž…์ด ํŒ๋ณ„ ํ”„๋กœํผํ‹ฐ์ธ์ง€ ์•„๋‹Œ์ง€์— ๋”ฐ๋ผ(๋ฆฌํ„ฐ๋Ÿด ์œ ํ˜• ๋˜๋Š” ๋ฆฌํ„ฐ๋Ÿด ์œ ํ˜•์˜ ์œ ๋‹ˆ์˜จ ํฌํ•จ), ์ „์ฒด ํƒ€์ž…์„ `never`๋กœ ์ขํž ์ˆ˜๋„ ์žˆ๊ณ  ์•„๋‹ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์‹œ์—์„œ ์˜ค์ง `name` ํ”„๋กœํผํ‹ฐ๋งŒ `never`ํƒ€์ž…์ด ๋ฉ๋‹ˆ๋‹ค. `string`๊ณผ `number`๋Š” ๊ณต์กดํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด์ฃ 
type Foo = {
    name: string,
    age: number
    }
type Bar = {
    name: number,
    age: number
}

type Baz = Foo & Bar // {name: never, age: number} 

๋‹ค์Œ ์˜ˆ์‹œ์—์„œ๋Š” ์ „์ฒด ํƒ€์ž…์ธ Baz๊ฐ€ never๋กœ ์ขํ˜€์ง€๋Š”๋ฐ boolean์€ ํŒ๋ณ„ ํ”„๋กœํผํ‹ฐ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. (true | false์˜ ์œ ๋‹ˆ์˜จ)

type Foo = {
    name: boolean,
    age: number
    }
type Bar = {
    name: number,
    age: number
}

type Baz = Foo & Bar // never

์ด PR์—์„œ ๋” ์‚ดํŽด๋ณด์„ธ์š”.

(์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋กœ๋ถ€ํ„ฐ) never ํƒ€์ž…์„ ์ฝ๋Š” ๋ฐฉ๋ฒ•

์—ฌ๋Ÿฌ๋ถ„์ด ๋ช…์‹œ์ ์œผ๋กœ never๋ผ๊ณ  ํƒ€์ž…์„ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด, ์˜ˆ์ƒ์น˜ ๋ชปํ•œ never ํƒ€์ž…๊ณผ ํ•จ๊ป˜ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋งˆ์ฃผํ•˜๊ฒŒ ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํƒ€์ž…๋“ค์„ ๊ต์ฐจํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํƒ€์ž…์˜ ์•ˆ์ „์„ฑ์„ ์ง€ํ‚ค๊ณ  ๊ฑด์ „์„ฑ(soundness)์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์•”๋ฌต์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜๋Š” ์ž‘์—…์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์‹œ๋Š” ์ด์ „์— ๋‹คํ˜•์ ์ธ ํ•จ์ˆ˜์˜ ํƒ€์ž…์— ๋Œ€ํ•ด ์ž‘์„ฑํ•œ ํฌ์ŠคํŒ…์—์„œ ์‚ฌ์šฉํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

type ReturnTypeByInputType = {
  int: number
  char: string
  bool: boolean
}

function getRandom<T extends 'char' | 'int' | 'bool'>(
  str: T
): ReturnTypeByInputType[T] {
  if (str === 'int') {
    // generate a random number
    return Math.floor(Math.random() * 10) // โŒ Type 'number' is not assignable to type 'never'.
  } else if (str === 'char') {
    // generate a random char
    return String.fromCharCode(
      97 + Math.floor(Math.random() * 26) // โŒ Type 'string' is not assignable to type 'never'.
    )
  } else {
    // generate a random boolean
    return Boolean(Math.round(Math.random())) // โŒ Type 'boolean' is not assignable to type 'never'.
  }
}

์ด ํ•จ์ˆ˜๋Š” ์ „๋‹ฌ๋ฐ›๋Š” ์ธ์ž์— ๋”ฐ๋ผ ์ˆซ์ž, ๋ฌธ์ž์—ด, ๋ถˆ๋ฆฌ์–ธ์„ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค. ๋ฆฌํ„ด ๊ฐ’์— ํ•ด๋‹นํ•˜๋Š” ํƒ€์ž…์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ReturnTypeByInputType[T]๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ชจ๋“  ๋ฆฌํ„ด๋ฌธ์—์„œ Type X is not assignable to type 'never'๋ผ๋Š” ํƒ€์ž… ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ถ„๊ธฐ์— ๋”ฐ๋ผ X๋Š” string, number, boolean์ด ๋ฉ๋‹ˆ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์šฐ๋ฆฌ ํ”„๋กœ๊ทธ๋žจ์ด ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ๊ฐ€๋Šฅ์„ฑ์„ ์ค„์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ๋„์›€์„ ์ฃผ๋ ค๊ณ  ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ๋ฆฌํ„ด ๊ฐ’์€ ReturnTypeByInputType[T]์— ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ด ๊ฐ’์€ ๋Ÿฐํƒ€์ž„ ๋•Œ number, string, boolean์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฆฌํ„ด ํƒ€์ž…์ด ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ReturnTypeByInputType[T]์— ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์„ ๋•Œ ํƒ€์ž… ์•ˆ์ •์„ฑ์ด ์ง€์ผœ์ง‘๋‹ˆ๋‹ค. ์ฆ‰ number, string, boolean์˜ intersecion์ผ ๋•Œ๊ฐ€ ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์ง€๋งŒ ์ด๋Š” ์„œ๋กœ ๊ณต์กดํ•  ์ˆ˜ ์—†๋Š” ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— never๊ฐ€ ๋˜๋Š” ๊ฒƒ์ด์ฃ . ๊ทธ๋ž˜์„œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€์— never๋ฅผ ๋ณด๊ฒŒ ๋˜๋Š” ๊ฒ๋‹ˆ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด, ์—ฌ๋Ÿฌ๋ถ„์€ ํƒ€์ž… ๋‹จ์–ธ(type assertions) (๋˜๋Š” ํ•จ์ˆ˜ ์˜ค๋ฒ„๋กœ๋”ฉ)์„ ์‚ฌ์šฉํ•ด์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค.

  • return Math.floor(Math.random() * 10) as ReturnTypeByInputType[T]
  • return Math.floor(Math.random() * 10) as never

๋‹ค๋ฅธ ๋ถ„๋ช…ํ•œ ์˜ˆ์‹œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function f1(obj: { a: number, b: string }, key: 'a' | 'b') {
    obj[key] = 1;    // Type 'number' is not assignable to type 'never'.
    obj[key] = 'x';  // Type 'string' is not assignable to type 'never'.
}

obj[key]๋Š” ๋Ÿฐํƒ€์ž„์— key์˜ ๊ฐ’์— ๋”ฐ๋ผ string ๋˜๋Š” number๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ œ์•ฝ์กฐ๊ฑด์ด ๋”ํ•ด์ง„ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ํƒ€์ž…์˜ ์•ˆ์ •์„ฑ์„ ์œ„ํ•ด string๊ณผ number ๋‘ ํƒ€์ž… ๋ชจ๋‘ ๊ณต์กด๊ฐ€๋Šฅํ•œ ๊ฐ’๋งŒ ์“ฐ๊ฒŒ๋” ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‘ ํƒ€์ž…์˜ ๊ต์ฐจ๋œ ํƒ€์ž…์ธ never ํƒ€์ž…์ด ์ „๋‹ฌ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

never ํ™•์ธํ•˜๊ธฐ

์–ด๋–ค ํƒ€์ž…์ด never์ด์–ด์•ผ ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค never์ธ์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์ฝ”๋“œ ์˜ˆ์‹œ๋ฅผ ๋ด…์‹œ๋‹ค.

type IsNever<T> = T extends never ? true : false

type Res = IsNever<never> // never ๐Ÿง

Res๋Š” true ๋˜๋Š” false๊ฐ€ ๋ ๊นŒ์š”? ๋†€๋ž๊ฒŒ๋„ ๋‘˜ ๋‹ค ์ •๋‹ต์ด ์•„๋‹™๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ๋Š” never๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์ €๋„ ์ด๊ฑธ ์ฒ˜์Œ ์ ‘ํ–ˆ์„ ๋•Œ ์ •์‹ ์ด ๋‚˜๊ฐ€๋Š” ๋“ฏ ํ–ˆ์Šต๋‹ˆ๋‹ค. Ryan Cavanaugh๊ฐ€ ์—ฌ๊ธฐ์„œ ์ด๋ฅผ ์„ค๋ช…ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

์š”์•ฝ์„ ํ•ด๋ณด์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์กฐ๊ฑด๋ถ€ ํƒ€์ž…์„ ์œ ๋‹ˆ์˜จ ํƒ€์ž…์œผ๋กœ ์ž๋™์ ์œผ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
  • never๋Š” ๋นˆ ์œ ๋‹ˆ์˜จ์ž…๋‹ˆ๋‹ค.
  • ๊ทธ๋ž˜์„œ ์•„๋ฌด๊ฒƒ๋„ ํ•ฉ์น  ๊ฒŒ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์กฐ๊ฑด๋ถ€ ํƒ€์ž…์€ ๋‹ค์‹œ never๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์œ ์ผํ•œ ํ•ด๊ฒฐ์ฑ…์€ ์•”์‹œ์ ์œผ๋กœ ํ•ฉ์น˜๋Š” ๊ฒƒ์„ ์„ ํƒํ•˜๊ณ  ํŠœํ”Œ๋กœ ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฐ์‹ธ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

type IsNever<T> = [T] extends [never] ? true : false;
type Res1 = IsNever<never> // 'true' โœ…
type Res2 = IsNever<number> // 'false' โœ…

์ด๋Š” ์‹ค์ œ๋กœ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์†Œ์Šค ์ฝ”๋“œ์˜ ์ผ๋ถ€์ด๋ฉฐ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ด ์ฝ”๋“œ๋ฅผ ์™ธ๋ถ€์— ๋…ธ์ถœ์‹œํ‚ค๋ฉด ๋” ์ข‹์„ ๋“ฏ ํ•ฉ๋‹ˆ๋‹ค.

์š”์•ฝ

์ด ๊ธ€์—์„œ ์ •๋ง ๋งŽ์€ ๊ฒƒ์„ ๋‹ค๋ฃจ์—ˆ๋„ค์š”.

  • ๋จผ์ €, never ํƒ€์ž…์˜ ์ •์˜์™€ ๋ชฉ์ ์— ๋Œ€ํ•ด ๋‹ค๋ค˜์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ๋‹ค์–‘ํ•œ ์‚ฌ๋ก€๋“ค์„ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค.
    • never๊ฐ€ ๋นˆ ํƒ€์ž…์ธ ์ ์„ ํ™œ์šฉํ•˜์—ฌ ํ•จ์ˆ˜์— ์ œ์•ฝ์‚ฌํ•ญ ์ถ”๊ฐ€ํ•˜๊ธฐ
    • ํ•„์š”์—†๋Š” ์œ ๋‹ˆ์˜จ ๋ฉค๋ฒ„์™€ ๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๊ธฐ
    • ์ œ์–ด ํ๋ฆ„ ๋ถ„์„์— ์•ˆ์ „์„ฑ์„ ๋”ํ•˜๊ธฐ
    • ์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋ถˆ๊ฐ€๋Šฅํ•œ ์กฐ๊ฑด๋ถ€ ๋ถ„๊ธฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ
  • ์•”๋ฌต์ ์ธ ํƒ€์ž… ๊ต์ฐจ๋•Œ๋ฌธ์— ํƒ€์ž… ์—๋Ÿฌ๋ฉ”์‹œ์ง€์—์„œ ๊ฐ‘์ž๊ธฐ never๊ฐ€ ๋‚˜ํƒ€๋‚˜๋Š” ์ด์œ ์— ๋Œ€ํ•ด์„œ๋„ ๋‹ค๋ค˜์—ˆ์ฃ 
  • ๋งˆ์ง€๋ง‰์œผ๋กœ never ํƒ€์ž…์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•๊นŒ์ง€ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค.

์ด ๊ธ€์„ ๋ฆฌ๋ทฐํ•ด์ฃผ๊ณ  ์•„์ฃผ ์†Œ์ค‘ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ๋‚จ๊ฒจ์ค€ ์นœ๊ตฌ Josh์—๊ฒŒ ๊ฐ์‚ฌ์˜ ์ธ์‚ฌ๋ฅผ!

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์›์‹œ๊ฐ’์˜ ๋น„๋ฐ€์Šค๋Ÿฌ์šด ์‚ฌ์‹ค

์›๋ฌธ : https://javascriptweblog.wordpress.com/2010/09/27/the-secret-life-of-javascript-primitives/

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋ฌธ์ž์—ด, ์ˆซ์ž ๋˜๋Š” ๋ถˆ๋ฆฌ์–ธ ์›์‹œํƒ€์ž…๋“ค์„ ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค ์—ฌ๋Ÿฌ๋ถ„์€ ๊ฐ์ฒด์˜ ๊ทธ๋ฆผ์ž์™€ ๊ฐ•์••์— ์ˆจ๊ฒจ์ง„ ์„ธ๊ณ„์— ๋“ค์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์…œ๋กํ™ˆ์ฆˆ์˜ ์˜ท์žฅ์˜ ๋จผ์ง€๋ฅผ ํ„ธ์–ด๋‚ด๊ณ  ๊ณ„์† ์ฝ์–ด๋ณด์„ธ์š”.

๊ธฐ๋ณธ

๊ฐ์ฒด๋Š” ์†์„ฑ๋“ค์˜ ์ง‘ํ•ฉ์ž…๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ์†์„ฑ์€ ๊ฐ์ฒด๋‚˜ ์›์‹œํƒ€์ž…์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๊ณ , ์›์‹œ ํƒ€์ž…์€ ๊ฐ’๋“ค๋กœ ์†์„ฑ์„ ๊ฐ–์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์›์‹œ ํƒ€์ž…์€ ๋‹ค์„ฏ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. undefined, null, boolean, string ๊ทธ๋ฆฌ๊ณ  number์ž…๋‹ˆ๋‹ค. ๊ทธ ์™ธ์— ๋ชจ๋“  ๊ฒƒ๋“ค์€ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์›์‹œํƒ€์ž… boolean, string, number๋Š” ๊ทธ๋“ค์˜ ๊ฐ์ฒด์— ๋Œ€์‘๋˜๋Š” ๊ฒƒ๋“ค์— ๊ฐ์‹ธ์งˆ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด๋“ค์€ ๊ฐ Boolean, String, Number ์ƒ์„ฑ์ž์˜ ์ธ์Šคํ„ด์Šค๋“ค์ž…๋‹ˆ๋‹ค.

typeof true; //"boolean"
typeof Boolean(true); //"boolean"
typeof new Boolean(true); //"object"
typeof (new Boolean(true)).valueOf(); //"boolean"

typeof "abc"; //"string"
typeof String("abc"); //"string"
typeof new String("abc"); //"object"
typeof (new String("abc")).valueOf(); //"string"

typeof 123; //"number"
typeof Number(123); //"number"
typeof new Number(123); //"object"
typeof (new Number(123)).valueOf(); //"number"

์›์‹œ ํƒ€์ž…์€ ์†์„ฑ์ด ์—†๋Š”๋ฐ ์™œ "abc".length๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ• ๊นŒ?

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์›์‹œ ํƒ€์ž…๊ณผ ๊ฐ์ฒด๋ฅผ ์‰ฝ๊ฒŒ ๊ฐ•์ œ๋ณ€ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์—์„œ ๋ฌธ์ž์—ด ๊ฐ’์€ length๋ผ๋Š” ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ž์—ด ๊ฐ์ฒด๋กœ ๊ฐ•์ œ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด ๊ฐ์ฒด๋Š” ์ฐฐ๋‚˜์˜ ์ˆœ๊ฐ„์—๋งŒ ์‚ฌ์šฉ๋˜๊ณ  ๋ฐ”๋กœ ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰์…˜์— ์˜ํ•ด ์ˆ˜์ง‘๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ฐฐ๋‚˜์˜ ์ด ์ƒ๋ช…์ฒด๋ฅผ ๊ฐ€๋‘ฌ ๋ถ„์„์„ ํ•ด๋ณผ ๊ฒ๋‹ˆ๋‹ค.

String.prototype.returnMe= function() {
    return this;
}

var a = "abc";
var b = a.returnMe();  

a; //"abc" 
typeof a; //"string" (still a primitive)
b; //"abc"
typeof b; //"object"

์˜๋ฏธ์žˆ๋Š” ๋งŽ์€ ์กฐ์‚ฌ๋“ค๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์šฐ๋ฆฌ๋Š” b๋ฅผ ์ƒ์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— b๊ฐ€ ์กด์žฌํ•˜๋Š” ํ•œ ๊ฐ์ฒด๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ˆ˜์ง‘๋˜๋Š” ๊ฒƒ์„ ๋ฐฉํ•ดํ•˜์—ฌ ๋ง‰์•˜์Šต๋‹ˆ๋‹ค. ํ•˜์ด์  ๋ฒ ๋ฅดํฌ๋Š” ์‚ด์•„์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ˜‰ (strict mode์—์„œ๋Š” ์ด๋ ‡๊ฒŒ ์žก์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.)

๋‹ค์Œ ์˜ˆ์‹œ๋Š” ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์„ ๋ฐฉํ•ดํ•˜์ง€ ์•Š๊ณ  ๊ฐ์ฒด์˜ ์œ ํ˜•์„ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

Number.prototype.toString = function() {
    return typeof this;
}

(123).toString(); //"object"

์ด๋Ÿฌํ•œ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ์›์‹œํƒ€์ž…์€ ๊ฐ์ž์˜ ๊ฐ์ฒด ์ƒ์„ฑ์ž๊ฐ€ ์ •์˜ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ํฌํ•จํ•œ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ฐ์ฒด๋“ค์€ ๊ฐ’๋“ค๋กœ ๊ฐ•์ œ ๋ณ€ํ™˜๋  ์ˆ˜๋„ ์žˆ๋Š”๊ฐ€?

์ฃผ๋กœ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ๊ฐ์ฒด๋“ค์€ ๋‹จ์ง€ ๋ž˜ํผ์˜ ์—ญํ• ์„ ํ•˜๋ฉฐ ๊ทธ๋“ค์˜ ๊ฐ’์€ ๊ฐ์ฒด๋“ค์ด ๊ฐ์‹ธ๊ณ  ์žˆ๋Š” ์›์‹œํƒ€์ž…์ž…๋‹ˆ๋‹ค. ํ•„์š”ํ•  ๋•Œ๋Š” ์ž์‹ ๋“ค์˜ ๊ฐ’์œผ๋กœ ๊ฐ•์ œ ๋ณ€ํ™˜๋˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

// ์›์‹œ๊ฐ’์œผ๋กœ ๊ฐ•์ œ๋ณ€ํ™˜๋˜๋Š” ๊ฐ์ฒด 1
var Twelve = new Number(12); 
var fifteen = Twelve + 3; 
fifteen; //15
typeof fifteen; //"number" (primitive)
typeof Twelve; //"object"; (still object)

//์›์‹œ๊ฐ’์œผ๋กœ ๊ฐ•์ œ๋ณ€ํ™˜๋˜๋Š” ๊ฐ์ฒด 2
new String("hippo") + "potamus"; //"hippopotamus" 

// ๋ณ€ํ™˜๋˜์ง€ ์•Š๋Š” ๊ฐ์ฒด ('typeof' ์—ฐ์‚ฐ์ž๋Š” ์—ฌ์ „ํžˆ ๊ฐ์ฒด๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ)
typeof new String("hippo") + "potamus"; //"objectpotamus"

์Šฌํ”„๊ฒŒ๋„ ๋ถˆ๋ฆฌ์–ธ ๊ฐ์ฒด๋Š” ๊ทธ๋ ‡๊ฒŒ ์‰ฝ๊ฒŒ ๋ณ€ํ™˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ถˆ๋ฆฌ์–ธ ๊ฐ์ฒด๋Š” ๊ฐ’์ด null ์ด๋‚˜ undefined๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด true๋กœ ํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค.

if (new Boolean(false)) {
    alert("true???"); 
}

์ผ๋ฐ˜์ ์œผ๋กœ ๋ถˆ๋ฆฌ์–ธ ๊ฐ์ฒด์— ๊ฐ’์„ ๋ช…์‹œ์ ์œผ๋กœ ์š”์ฒญํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ๊ฐ’์ด "truthy"ํ•œ์ง€ "falsy"ํ•œ์ง€ ๊ฒฐ์ •ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

var a = "";
new Boolean(a).valueOf(); //false

ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์ด๋ ‡๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค.

var a = Boolean("");
a; // false

๋˜๋Š” ์ด๋ ‡๊ฒŒ์š”.

var a = "";
!!a; //false

ํ˜•๋ณ€ํ™˜์„ ์ด์šฉํ•˜์—ฌ ์›์‹œ ํƒ€์ž…์— ๊ฐ’์„ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์„๊นŒ?

๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

var primitive = "september";
primitive.vowels = 3;

primitive.vowels; //undefined; 

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์›์‹œ ํƒ€์ž…์— ํ”„๋กœํผํ‹ฐ๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์„ ๊ฐ์ง€ํ•œ๋‹ค๋ฉด ์›์‹œ ํƒ€์ž…์„ ๊ฐ์ฒด๋กœ ๊ฐ•์ œ ํ˜•๋ณ€ํ™˜์‹œ์ผฐ์„ ๊ฒ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์œ„์˜ ์˜ˆ์‹œ์ฒ˜๋Ÿผ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋Š” ์ฐธ์กฐ๊ฐ’์ด ์—†๊ณ  ์ฆ‰์‹œ ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰์…˜์— ์˜ํ•ด ์ˆ˜์ง‘๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ์‹ค์ œ๋กœ ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚˜๋Š”์ง€ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•œ ์ˆ˜๋„ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

var primitive = "september";
primitive.vowels = 3;
// ์ƒ์„ฑ๋œ ์ƒˆ๋กœ์šด ๊ฐ์ฒด์— ํ”„๋กœํผํ‹ฐ ์…‹
(new String("september")).vowels = 3;

primitive.vowels;
// ๋˜ ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์ด ๊ฐ์ฒด์—์„œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐพ์Œ
(new String("september")).vowels; //undefined

๋ณด์‹œ๋‹ค์‹œํ”ผ, ์ด๋Ÿฌํ•œ ์ฝ”๋“œ๋Š” ์“ธ๋ชจ์—†์„ ๋ฟ ์•„๋‹ˆ๋ผ ๋‚ญ๋น„์ž…๋‹ˆ๋‹ค.

๋งˆ๋ฌด๋ฆฌ

ํ”„๋กœํผํ‹ฐ๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์€ ์›์‹œํƒ€์ž…๊ณผ ๋‹ฌ๋ฆฌ ๊ฐ์ฒด๊ฐ€ ๊ฐ€์ง€๋Š” ์œ ์ผํ•œ ์žฅ์ ์ด์ง€๋งŒ ์ด๋งˆ์ €๋„ ๊ฝค ์˜์‹ฌ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด, ๋ถˆ๋ฆฌ์–ธ, ๋„˜๋ฒ„๋Š” ๊ตฌ์ฒด์ ์ด๊ณ  ์ž˜ ์ •์˜๋œ ๋ชฉ์ ์„ ๊ฐ€์ง€๋ฉฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€ ์‚ฌ๋žŒ๋“ค์„ ํ˜ผ๋ž€์Šค๋Ÿฝ๊ฒŒ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ์›์‹œ ํƒ€์ž…์€ ๋ถˆ๋ณ€๊ฐ’์ด๋ฏ€๋กœ ๊ฐ์ฒด ๋ž˜ํผ์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

var me = new String("Angus");
me.length = 2; //(error in strict mode)
me.length; //5 (not 2 - thanks @joseanpg)
me.valueOf(); "Angus"

๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์›์‹œํƒ€์ž…์„ ์ž˜ ์ดํ•ดํ•˜๊ณ  ์›์‹œํƒ€์ž…์„ ์‚ฌ์šฉํ•  ๋•Œ ์–ด๋–ค ์ผ๋“ค์ด ์ผ์–ด๋‚˜๋Š”์ง€ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ ์–ธ์–ด๋ฅผ ๋” ์ž˜ ์ดํ•ดํ•˜๋Š”๋ฐ ์•„์ฃผ ์ค‘์š”ํ•œ ๋‹จ๊ณ„๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] React์˜ ๊ถ๊ทน์  ์›๋ฆฌ - ์†Œํ”„ํŠธ์›จ์–ด ๋””์ž์ธ, ์•„ํ‚คํ…์ณ & ์ข‹์€ ์˜ˆ์‹œ 2

์›๋ฌธ : 2021.01.18์— ์ž‘์„ฑ๋œ Tao of React - Software Design, Architecture & Best Practices

์„ฑ๋Šฅ (Performance)

๋„ˆ๋ฌด ๋นจ๋ฆฌ ์ตœ์ ํ™”ํ•˜๋ ค๊ณ  ํ•˜์ง€ ๋งˆ๋ผ

์–ด๋–ค ์ตœ์ ํ™”๋ฅผ ํ•˜๊ธฐ ์ „์— ์ตœ์ ํ™”์— ๋Œ€ํ•œ ์ด์œ ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ์—ฌ๋Ÿฌ๋ถ„์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ์—๋„ ๋งน๋ชฉ์ ์œผ๋กœ ์ข‹์€ ์‚ฌ๋ก€๋ฅผ ๋”ฐ๋ผํ•˜๋Š” ๊ฒƒ์€ ๋…ธ๋ ฅ์„ ํ—ˆ๋น„ํ•  ๋ฟ์ž…๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ ๊ฑธ ์•„๋Š” ๊ฒƒ๋„ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค๋งŒ, ์„ฑ๋Šฅ ์ด์ „์— ๊ฐ€๋…์„ฑ ์žˆ๊ณ  ์œ ์ง€๋ณด์ˆ˜ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ๋” ์šฐ์„ ์œผ๋กœ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ž˜ ์“ฐ์—ฌ์ง„ ์ฝ”๋“œ๊ฐ€ ๊ฐœ์„ ํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์˜ ์•ฑ์— ์„ฑ๋Šฅ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ๋•Œ ๋ฌธ์ œ์˜ ์›์ธ์„ ์ธก์ •ํ•˜๊ณ  ๋ฌด์—‡์ธ์ง€ ํ™•์ธํ•˜์„ธ์š”. ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ๊ฐ€ ๊ฑฐ๋Œ€ํ•˜๋‹ค๋ฉด ๋ฆฌ๋ Œ๋”๋ง ํšŸ์ˆ˜๋ฅผ ์ค„์—ฌ๋„ ์†Œ์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค. ์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ผ๋‹จ ์•Œ๋ฉด ๋ฌธ์ œ์˜ ์˜ํ–ฅ ์ˆœ์„œ์— ๋”ฐ๋ผ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ๋ฅผ ํ™•์ธํ•˜๋ผ

๋ธŒ๋ผ์šฐ์ €์— ์ „๋‹ฌ๋˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์–‘์€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ฑ๋Šฅ์˜ ๊ฐ€์žฅ ์ฃผ์š”ํ•œ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ์•ฑ์ด ์—„์ฒญ ๋น ๋ฅด๋”๋ผ๋„ 4MB์˜ JS ์ฝ”๋“œ๋ฅผ ๋กœ๋“œํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์•„๋ฌด๋„ ์—ฌ๋Ÿฌ๋ถ„์˜ ์•ฑ์ด ๋น ๋ฅธ ๊ฒƒ์„ ์•Œ์ง€ ๋ชปํ•  ๊ฒ๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ๋ฒˆ๋“ค์„ ์ „๋‹ฌํ•˜์ง€ ๋ง๊ณ  ์—ฌ๋Ÿฌ๋ถ„์˜ ์•ฑ์„ route ์ˆ˜์ค€์œผ๋กœ ์ชผ๊ฐœ๋„๋ก ํ•˜์„ธ์š”. ๊ฐ€๋Šฅํ•œ ์ตœ์†Œํ•œ์˜ JS ์ฝ”๋“œ๋ฅผ ์ „๋‹ฌํ•˜๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž๊ฐ€ ๋‹ค๋ฅธ ๋ฒˆ๋“ค์ด ํ•„์š”ํ•  ๋•Œ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ๋ฒ„ํŠผ์ด PDF๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๋Š” ๊ฒƒ์„ ํŠธ๋ฆฌ๊ฑฐํ•œ๋‹ค๋ฉด, ๋ฒ„ํŠผ์ด hover๋˜์—ˆ์„ ๋•Œ PDF ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๋„๋ก ์ง€์—ฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Rerenders - ์ฝœ๋ฐฑ, ๋ฐฐ์—ด, ๊ฐ์ฒด

๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์˜ ํšŒ์ˆ˜๋ฅผ ์ค„์ด๋Š” ๊ฒƒ์€ ์ข‹์€ ์‹œ๋„์ž…๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์•ฑ์— ์—„์ฒญ๋‚œ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๊ฑฐ์˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์œ ์˜ํ•˜์„ธ์š”. ๊ฐ€์žฅ ํ”ํ•œ ์กฐ์–ธ์€ props๋กœ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์„ ์ง€์–‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ๋งˆ๋‹ค ๋ฆฌ๋ Œ๋”๋ง์„ ์œ ๋ฐœํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ฝœ๋ฐฑํ•จ์ˆ˜๋กœ ์ธํ•ด ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ๊ฒช์€ ์ ์€ ์—†์—ˆ๊ณ , ์‚ฌ์‹ค ๊ทธ๊ฒƒ์ด ์ œ๊ฐ€ ์ ‘๊ทผํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์ด ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ๊ฒช๊ณ  ์žˆ๊ณ  ํด๋กœ์ ธ๊ฐ€ ์›์ธ์ด๋ผ๋ฉด ํด๋กœ์ ธ๋ฅผ ์ œ๊ฑฐํ•˜์„ธ์š”. ๊ทธ๋Ÿฌ๋‚˜ ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ํ•ด์น˜๊ฑฐ๋‚˜ ๋” ์žฅํ™ฉํ•˜๊ฒŒ ๋งŒ๋“ค์ง€๋Š” ๋งˆ์„ธ์š”. ๋ฐฐ์—ด์ด๋‚˜ ๊ฐ์ฒด๋ฅผ ์•„๋ž˜๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์€ ๋น„์Šทํ•œ ๊ฒฐ์ž…๋‹ˆ๋‹ค. ์ฐธ์กฐ ์ฒดํฌ์— ์‹คํŒจํ•˜๋ฉด ๋ฆฌ๋ Œ๋”๋ง์„ ์œ ๋ฐœํ•˜์ฃ . ๊ณ ์ •๋œ ๋ฐฐ์—ด์„ ์ „๋‹ฌํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด, ์ปดํฌ๋„ŒํŠธ ์ •์˜์— ์•ž์„œ ๋ฐฐ์—ด์„ ์ƒ์ˆ˜๋กœ ์„ ์–ธํ•จ์œผ๋กœ์จ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ „๋‹ฌ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ (Testing)

์Šค๋ƒ…์ƒท ํ…Œ์ŠคํŠธ์— ์˜์กดํ•˜์ง€ ๋งˆ๋ผ

React๋กœ 2016๋…„๋ถ€ํ„ฐ ์ž‘์—…ํ•˜๋ฉด์„œ ์ œ ์ปดํฌ๋„ŒํŠธ์—์„œ ์Šค๋ƒ…์ƒท ํ…Œ์ŠคํŠธ๊ฐ€ ๋ฌธ์ œ๋ฅผ ์บ์น˜ํ•œ ์ ์€ ๋”ฑ ํ•œ ๋ฒˆ ์žˆ์Šต๋‹ˆ๋‹ค. ์ธ์ž ์—†์ด new Date()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ•ญ์ƒ ํ˜„์žฌ ๋‚ ์งœ๋กœ ๊ธฐ๋ณธ ์„ค์ •๋˜์—ˆ๋˜ ๊ฑฐ์ฃ . ๊ฒŒ๋‹ค๊ฐ€ ์Šค๋ƒ…์ƒท์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๋นŒ๋“œ ์‹คํŒจ์˜ ์›์ธ์ด ๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ์›Œํฌํ”Œ๋กœ์šฐ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์Šค๋ƒ…์ƒท์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•œ ํ›„ ์Šค๋ƒ…์ƒท์„ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ๊ณ„์† ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์˜คํ•ดํ•˜์ง€ ๋งˆ์„ธ์š”. ์Šค๋ƒ…์ƒท ํ…Œ์ŠคํŠธ๋Š” ์ข‹์€ ์ƒˆ๋„ˆํ‹ฐ ์ฒดํฌ์ง€๋งŒ ์ปดํฌ๋„ŒํŠธ ์ˆ˜์ค€์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๋Œ€์ฒดํ’ˆ์ด ๋  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ €๋Š” ์Šค๋ƒ…์ƒท์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์กฐ์ฐจ๋ฅผ ์ง€์–‘ํ•ฉ๋‹ˆ๋‹ค.

์˜ฌ๋ฐ”๋ฅธ ๋ Œ๋”๋ง์„ ํ…Œ์ŠคํŠธํ•˜๋ผ

์—ฌ๋Ÿฌ๋ถ„์˜ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฒ€์ฆํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์˜ˆ์ƒ๋Œ€๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ธฐ๋ณธ๊ฐ’์˜ props์™€ ์ „๋‹ฌ๋˜๋Š” props๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ Œ๋”๋˜๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ์ธํ’‹์— ๋Œ€ํ•ด ํ•จ์ˆ˜๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํ„ดํ•˜๋Š”์ง€๋ฅผ ๊ฒ€์ฆํ•˜์„ธ์š”. ์Šคํฌ๋ฆฐ์—์„œ ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ๋“ค์„ ๊ฒ€์ฆํ•˜์„ธ์š”.

์ƒํƒœ์™€ ์ด๋ฒคํŠธ๋ฅผ ๊ฒ€์ฆํ•˜๋ผ

์ƒํƒœ๊ฐ€ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” ์ด๋ฒคํŠธ์˜ ์‘๋‹ต์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ทธ์— ์ ์ ˆํžˆ ๋ฐ˜์‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ์ ์ ˆํ•œ ์ธ์ž๊ฐ€ ์ „๋‹ฌ๋˜๋Š”์ง€ ๊ฒ€์ฆํ•˜์„ธ์š”. ๋˜ํ•œ ๋‚ด๋ถ€ ์ƒํƒœ๊ฐ€ ์ž˜ ์„ค์ •๋˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.

ํ…Œ์ŠคํŠธ ์—ฃ์ง€ ์ผ€์ด์Šค (Test Edge Cases)

์—ฃ์ง€ ์ผ€์ด์Šค๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋ผ

๊ธฐ๋ณธ์ ์ธ ํ…Œ์ŠคํŠธ๋ฅผ ๋‹ค๋ค˜๋‹ค๋ฉด, ์—ฃ์ง€ ์ผ€์ด์Šค๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด ๋ช‡ ๊ฐ€์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋นˆ ๋ฐฐ์—ด์„ ์ „๋‹ฌํ–ˆ์„ ๋•Œ ์ฒดํ‚น์—†์ด ์ธ๋ฑ์Šค๋ฅผ ์ ‘๊ทผํ•˜์ง€ ์•Š๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. API ํ˜ธ์ถœ์—์„œ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•ด๋‹น ์˜ค๋ฅ˜๋ฅผ ์ž˜ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋ผ

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋Š” ์ „์ฒด ํŽ˜์ด์ง€๋‚˜ ํฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ถ”์ƒํ™”๋กœ์„œ ์ž˜ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด์ฃ . ์ด ํ…Œ์ŠคํŠธ๋Š” ์•ฑ์ด ์˜ˆ์ƒ๋Œ€๋กœ ์ž˜ ์ž‘๋™ํ•œ๋‹ค๋Š” ์ž์‹ ๊ฐ์„ ์ค๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ์ž์ฒด๋กœ๋„ ์ž˜ ์ž‘๋™ํ•˜๊ณ  ์œ ๋‹› ํ…Œ์ŠคํŠธ ๋‹จ์œ„๋กœ๋„ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ํ†ตํ•ฉ๋˜์—ˆ์„ ๋•Œ ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์Šคํƒ€์ผ๋ง (Styling)

CSS-in-JS๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋™์˜ํ•˜์ง€ ์•Š๊ณ  ์—ฌ๋Ÿฌ ๋…ผ๋ž€์„ ์•ผ๊ธฐํ•  ์˜๊ฒฌ์ž…๋‹ˆ๋‹ค. ์ €๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ๋ชจ๋“  ๊ฒƒ๋“ค์„ ํ‘œํ˜„์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— Styled Components๋‚˜ Emotion๊ณผ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ๊ด€๋ฆฌํ•  ํŒŒ์ผ์ด ํ•˜๋‚˜ ์ค„์–ด๋“ค๋ฉฐ CSS ์ปจ๋ฒค์…˜์— ๋Œ€ํ•ด ์ƒ๊ฐํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋ฆฌ์•กํŠธ์—์„œ ๋…ผ๋ฆฌ ๋‹จ์œ„๋Š” ์ปดํฌ๋„ŒํŠธ์ด๋ฏ€๋กœ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ด€์ ์—์„œ๋„ ์ปดํฌ๋„ŒํŠธ์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ๊ฒƒ๋“ค์„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์†Œ์œ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜ : ์Šคํƒ€์ผ์— ๋Œ€ํ•œ ์ž˜๋ชป๋œ ์„ ํƒ์€ ์—†์Šต๋‹ˆ๋‹ค. SCSS, CSS ๋ชจ๋“ˆ, Tailwind์™€ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋“ฑ. CSS-in-JS๋Š” ์ œ๊ฐ€ ์ถ”์ฒœํ•˜๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

Styled component๋ฅผ ํ•จ๊ป˜ ๋‘์–ด๋ผ.

CSS-in-JS ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํ•œ ํŒŒ์ผ์— ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ๊ฐ™์ด ๋‘๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ์ผ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ์™€ ๋™์ผํ•œ ํŒŒ์ผ์— ๋ณด๊ด€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋„ˆ๋ฌด ์Šคํƒ€์ผ ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด ๊ธธ์–ด์ง€๊ฒŒ ๋˜๋ฉด ๋ถ„๋ฆฌํ•ด์„œ ์Šคํƒ€์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ๊ทผ์ฒ˜์— ๋‘๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. Spectrum๊ณผ ๊ฐ™์€ ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ์—์„œ ์ด๋Ÿฌํ•œ ํŒจํ„ด์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ (Data Fetching)

data fetching ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

๋ฆฌ์•กํŠธ๋Š” API์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ณ ์ง‘๋œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐ ํŒ€์€ API์™€ ํ†ต์‹คํ•˜๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋“ค์„ ์ œ๊ณตํ•˜๋Š” ์ž์‹ ๋“ค๋งŒ์˜ ์„œ๋น„์Šค์— ๊ด€๋ จ๋œ ์ž์ฒด ๊ตฌํ˜„์„ ๋งŒ๋“ค์–ด๋‚ด์ฃ . ์ด ๋ฐฉ์‹์„ ์„ ํƒํ•˜๋ฉด ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  http ์—๋Ÿฌ๋“ค์„ ๋‹ค๋ฃจ๋Š” ๊ฒƒ๋“ค์„ ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์žฅํ™ฉํ•œ ์ฝ”๋“œ๋ฅผ ๊ฐ€์ง€๋Š” ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ๋ฅผ ํ•„์š”๋กœ ํ•ฉ๋‹ˆ๋‹ค. ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ๋Œ€์‹  React Query๋‚˜ SWR๊ณผ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. hook์ด๋ผ๋Š” ๊ด€์šฉ์ ์ธ ๋ฐฉ์‹์„ ํ†ตํ•ด ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๋Š” ๊ฒƒ์„ ์ปดํฌ๋„ŒํŠธ ๋ผ์ดํ”„์‚ฌ์ดํด์˜ ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ถ€๋ถ„์œผ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋˜ํ•œ ์บ์‹ฑ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ณ  ๋กœ๋”ฉ๊ณผ ์—๋Ÿฌ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๊ทธ ๊ธฐ๋Šฅ์„ ๋‹ค๋ฃจ๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋ฅผ ์—†์• ์ค๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] ์„ธ๋ฏธ์ฝœ๋ก ์„ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”

์›๋ฌธ : Never Use Semicolons
ํŠธ์œ„ํ„ฐ

์ด ๊ธ€์€ ์˜ค๋ž˜๋œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋…ผ์Ÿ์„ ๋‹ค์‹œ ์—ด์–ด๋ณด๊ณ ์ž ์ž‘์„ฑํ•˜๋Š” ๊ธ€์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋‹จ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์Šคํƒ ๋‹ค๋“œ ์Šคํƒ€์ผ์—์„œ "์„ธ๋ฏธ์ฝœ๋ก ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”" ๊ทœ์น™์„ ๊ฐ•์ œํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๊ถ๊ธˆ์ฆ์— ์ฐธ์กฐ์šฉ์œผ๋กœ์„œ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์ž๋™ ์„ธ๋ฏธ์ฝœ๋ก  ์‚ฝ์ž…(ASI)์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•˜์ง€ ์•Š๊ณ  "์–ธ์ œ๋‚˜ ์„ธ๋ฏธ์ฝœ๋ก ์„ ์“ธ ์ˆ˜ ์žˆ๋‹ค๋Š”" ์ƒ๊ฐ์€ ์™„์ „ํžˆ ์ž˜๋ชป๋์Šต๋‹ˆ๋‹ค.
๋ชจ๋“  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ์ž๋“ค์€ ๋ฐ˜๋“œ์‹œ ASI์— ๋Œ€ํ•ด ์ดํ•ดํ•ด์•ผ ํ•˜๋ฉฐ, ์„ธ๋ฏธ์ฝœ๋ก ์„ ํ•ญ์ƒ ๋ถ™์ด๋”๋ผ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

function foo () {
  return
    {
      bar: 1,
      baz: 2
    };
}

์„ธ๋ฏธ์ฝœ๋ก ์„ ๋„ฃ๋Š” ๊ฒƒ์„ ์žŠ์—ˆ๋‹ค ํ• ์ง€๋ผ๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ASI๊ฐ€ ์•„๋ž˜์ฒ˜๋Ÿผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

function foo () {
  return; // <-- ASI๊ฐ€ ์—ฌ๊ธฐ์— ์„ธ๋ฏธ์ฝœ๋ก ์„ ์ถ”๊ฐ€ํ–ˆ๊ณ  ์—ฌ๋Ÿฌ๋ถ„์€ ๋ฒ„๊ทธ๋ฅผ ์–ป๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!
    {
      bar: 1,
      baz: 2
    };
}

์ด๋Ÿฐ ๊ฒฝ์šฐ๋กœ ์ธํ•ด ์‚ฌ๋žŒ๋“ค์ด "ํ•ญ์ƒ ์„ธ๋ฏธ์ฝœ๋ก ์„ ์“ด๋‹ค๋ฉด" ์ด์ƒํ•œ ASI์˜ ๋™์ž‘์œผ๋กœ๋ถ€ํ„ฐ ์•ˆ์ „ํ•˜๋‹ค๋Š” ์˜คํ•ด๋ฅผ ๋‚ณ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ASI๋Š” ์šฐ๋ฆฌ์™€ ํ‰์ƒ ํ•จ๊ป˜ ํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ASI๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ๋ฐฐ์šธ ์‹œ๊ฐ„์ž…๋‹ˆ๋‹ค. ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”. ASI๋Š” ECMAScript ์–ธ์–ด ํ‘œ์ค€์— ์ž˜ ์„ค๋ช…๋˜์–ด ์žˆ์œผ๋ฉฐ ๋ชจ๋“  ๋ธŒ๋ผ์šฐ์ €๋Š” ์ •ํ™•ํžˆ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์ตœ์†Œํ•œ์œผ๋กœ ์˜ˆ๊ธฐ์น˜ ๋ชปํ•œ ASI์˜ ๋™์ž‘์„ ํ™•์ธํ•˜๋Š” ์šฉ๋„๋กœ ๋ฆฐํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”. ESLint๋Š” ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ASI์˜ ๋™์ž‘์„ ์žก์•„์ฃผ๋Š” no_unexpected_multiline ๊ทœ์น™์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์ผ๋‹จ ๋ฆฐํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ๋ถ„๋“ค์„ ์•ˆ์ „ํ•˜๊ฒŒ ํ•ด์ฃผ๋ฏ€๋กœ ์„ธ๋ฏธ์ฝœ๋ก ์„ ์‚ฌ์šฉํ•˜๋“  ์‚ฌ์šฉํ•˜์ง€ ์•Š๋“  ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

The argument for โ€œnever use semicolonsโ€

"ํ•ญ์ƒ ์„ธ๋ฏธ์ฝœ๋ก ์„ ์‚ฌ์šฉํ•˜๋ผ"๋Š” ๊ทธ๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์„ธ๋ฏธ์ฝœ๋ก ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋งŽ์€ ์—ฃ์ง€ ์ผ€์ด์Šค๋“ค์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด๋ด…์‹œ๋‹ค.

function foo () {
  return 42; // ok
};           // <-- AVOID!

var foo = function () {
}; // ok

๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฐ ๊ฒฝ์šฐ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

class Foo {
  constructor () {
    if (baz) {
      return 42; // ok
    };           // <-- AVOID!
    return 12;   // ok
  };             // <-- AVOID!
};               // <-- AVOID!

"์„ธ๋ฏธ์ฝœ๋ก ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ"๋ณด๋‹ค "์„ธ๋ฏธ์ฝœ๋ก ์„ ํ•ญ์ƒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ"์€ ๋” ๋งŽ์€ "์—ฃ์ง€ ์ผ€์ด์Šค"๋“ค์„ ๋ช…์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๋งŒ์•ฝ ์—ฌ๋Ÿฌ๋ถ„์ด "์„ธ๋ฏธ์ฝœ๋ก ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด" ํ•œ ๊ฐ€์ง€์˜ ๊ทœ์น™๋งŒ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. [, (, ```๋กœ ๋ผ์ธ์„ ์‹œ์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์—”, ์ด๋ ‡๊ฒŒ ๋‹จ์ˆœํžˆ ;๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

;[1, 2, 3].forEach(bar)

๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฐ ์‹์œผ๋กœ ๋งŽ์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ํŽธ์ด๋ผ๋ฉด, ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋˜‘๋˜‘ํ•œ ์ฝ”๋“œ๋ฅผ ์“ฐ๊ณ  ์žˆ๋Š” ๊ฒƒ์ผ์ง€๋„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.
์ด๋ ‡๊ฒŒ ์“ฐ๋Š” ๊ฒŒ ๋” ๊ฐ„๋‹จํ•˜์ฃ .

const nums = [1, 2, 3]
nums.forEach(bar)

๊ทธ๋ฆฌ๊ณ  ์—ฌ๋Ÿฌ๋ถ„์ด standard์ฒ˜๋Ÿผ ๋ฆฐํ„ฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ASI๊ฐ€ ์—๋Ÿฌ๋กœ ์•Œ๋ ค์ง€๋ฏ€๋กœ ๊ธฐ์–ตํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

[์ •๋ฆฌ] FEConf 2021 : B track

์ƒํƒœ๊ด€๋ฆฌ, ์ด์ œ Recoil ํ•˜์„ธ์š”.

์˜์ƒ ๋งํฌ, ๊น€ํ˜„ํƒœ๋‹˜

ํ•ต์‹ฌ ์ปจ์…‰

  • React ๋‚ด๋ถ€ ์ƒํƒœ๋งŒ์„ ์ด์šฉ
  • ์ž‘์€ Atom ๋‹จ์œ„๋กœ ๊ด€๋ฆฌ, ์ˆœ์ˆ˜ํ•จ์ˆ˜ Selector
  • ๋ฆฌ๋ Œ๋”๋ง ์ตœ์†Œํ™”, ์ƒˆ๋กœ์šด ๋ฆฌ์•กํŠธ ๊ธฐ๋Šฅ๊ณผ์˜ ํ˜ธํ™˜์„ฑ

๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ๋‹ค๋ฃจ๊ธฐ

export const productAsyncState = selector({
  key: 'productAsyncState',
  get: async ({get}) => {
    const idx = get(productIdxState);
    return idx > 0 ? await getProductDetail(idx) : null;
  },
});
export const productAsyncState = selectorFamily({
  key: 'productAsyncState',
  get: ({idx}) => async ({get}) => {
    return idx > 0 ? await getProductDetail(idx) : null;
  },
});

-> ์ด๋Ÿฐ ์‹์œผ๋กœ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋ฉด Suspense๋ฅผ ์ด์šฉํ•˜๋ผ๋Š” ์—๋Ÿฌ๊ฐ€ ๋œธ

  • indicator ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด ๋‘๊ณ  State ํ˜ธ์ถœํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ Suspense๋กœ ๊ฐ์‹ธ์ž
  • ์‹ซ์œผ๋ฉด Loadable ์‚ฌ์šฉ

์—๋Ÿฌ ํ•ธ๋“ค๋ง

  • <ErrorBoundary>๋กœ ๊ฐ์‹ธ๊ฑฐ๋‚˜ useRecoilValueLoadable์—์„œ state๋ฅผ ํ™œ์šฉ

๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ์˜ ๊ฐฑ์‹ 

  • ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ๊ฐฑ์‹ ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ์š”์†Œ
    • (1) ๋‚ด๋ถ€์—์„œ ๊ตฌ๋…์ค‘์ธ ๋‹ค๋ฅธ Recoil state์˜ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ (2) ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ƒˆ๋กœ์šด ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝ
  • req id์— ๋Œ€ํ•œ atom์„ ๋งŒ๋“ค๊ณ  refresh ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋ฉด id๊ฐ€ ๊ฐฑ์‹ ๋˜๋ฉด์„œ (1)์˜ ์ด์œ ๋กœ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ๋ฐฉ์‹
  • refresh hooks ๋Œ€์‹  setter ํ™œ์šฉ : ์ƒํƒœ ๋ณ€๊ฒฝ์ด ์—†๋Š” set์„ ์‹คํ–‰ํ•˜๋ฉด ๋™์ผํ•œ ํšจ๊ณผ

Atom ๊ตฌ๋… ๊ณต์œ  ์‹œ ์ฃผ์˜์ 

  • ์–ด๋””์„œ๋“  ๊ตฌ๋…์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์˜ํ–ฅ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ
  • ์˜์กด ๊ด€๊ณ„๋ฅผ ๊ฐ–๋Š” ์ƒํƒœ๋ผ๋ฆฌ ํŒŒ์ผ๋กœ ๊ด€๋ฆฌํ•˜๊ฑฐ๋‚˜ AtomFamily๋กœ ๊ทธ๋ฃจํ•‘ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์กด์žฌ

์บ์‹ฑ ์ปจํŠธ๋กค ํ•  ์ˆ˜ ์žˆ๋Š” ์‹คํ—˜ ๋ฒ„์ „์ด ๋“ฑ์žฅ! v.0.4

[๋ฒˆ์—ญ] ์›น ๊ฐœ๋ฐœ์ž๊ฐ€ ๋งŽ์ด ์ €์ง€๋ฅด๋Š” ๋ฆฌ์•กํŠธ ์‹ค์ˆ˜ Top 5

2021๋…„ 7์›” 27์ผ์— ์ž‘์„ฑ๋œ Top 5 React Mistakes Web Developers Make์„ ์ฝ๊ณ  ๋ฒˆ์—ญํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค. ๐Ÿ™‚

์ตœ๊ทผ, ์ €๋Š” ํ•™์ƒ๋“ค์„ ๊ฐ€๋ฅด์น˜๊ธฐ ์‹œ์ž‘ํ•˜์—ฌ ๊ฐ€๋”์”ฉ ์ž์ฃผ ๋ณด์ด๋Š” ์‹ค์ˆ˜๋“ค์„ ๋ชจ์•„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.
์ง€๊ธˆ ๋ชจ์€ ๊ฒƒ๋“ค์˜ ์ผ๋ถ€๋ฅผ ์—ฌ๋Ÿฌ๋ถ„๋“ค๊ณผ ๊ณต์œ ํ•ด๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.
๋˜ํ•œ ๋ช‡๋ช‡ ๋ถ„๋“ค๊ณผ ์ธํ„ฐ๋ทฐ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ ๋ณดํ†ต ์ด ๋ชฉ๋ก์—์„œ ์ผ๋ถ€๋ฅผ ๊ณจ๋ž๊ณ , ์ธํ„ฐ๋ทฐ์ด๋ถ„๋“ค๊ป˜ ์ฝ”๋“œ์˜ ์ž˜๋ชป๋œ ์ ์„ ์—ฌ์ญค๋ณด๊ธฐ๋„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  ์˜ˆ์ œ๋Š” ์ฝ”๋“œ๋ฆฌ๋ทฐ๋‚˜ ์ธํ„ฐ๋ทฐ ๊ณผ์ œ์—์„œ ๊ฐ€์ ธ์™”์ง€๋งŒ ๋ฌธ์ œ์— ์ง‘์ค‘ํ•˜๊ณ ์ž ๋‹จ์ˆœํ™”์‹œ์ผฐ์Œ์„ ์•Œ๋ ค๋“œ๋ฆฝ๋‹ˆ๋‹ค.

1. ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ชจ๋“  ๊ตฌ๋…์— ๋Œ€ํ•œ clean-up ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋ผ

export const Component4: FC = () => {
    const [value, setValue] = useState(0);

    useEffect(() => {
        setInterval(() => setValue((value) => value + 1), 1000);
    }, []);

    return <div>{value}</div>;
};

์šฐ๋ฆฌ๊ฐ€ ์ž˜ ์•Œ๋“ฏ์ด, SPA ์•ฑ์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋Š” ์ค‘์š”ํ•œ ๋ฌธ์ œ์ด๊ณ  ๋ฐ˜๋“œ์‹œ ์‹ ๊ฒฝ์จ์•ผ ํ•  ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์˜ ์ด์œ ๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ์ข‹์€ ์˜ˆ์ œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์ผ๋ถ€ ๋กœ์ง์„ setInterval ํ•จ์ˆ˜์— ๋‘์—ˆ๊ณ  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ธ๋งˆ์šดํŠธ๋  ๋•Œ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ํด๋ฆฌ์–ดํ•˜๋Š” ๊ฒƒ์ด ๋ˆ„๋ฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
useEffect์— ์ „๋‹ฌ๋˜๋Š” ํ•จ์ˆ˜๋Š” clean-up ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์˜ณ์€ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

export const Component4: FC = () => {
    const [value, setValue] = useState(0);

    useEffect(() => {
        const interval = 
            setInterval(() => setValue((value) => value + 1), 1000);
        return () => clearInterval(interval);
    }, []);

    return <div>{value}</div>;
};

clean-up ํ•จ์ˆ˜์—์„œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ธ๋งˆ์šดํŠธ๋  ๋•Œ๋งˆ๋‹ค ์ธํ„ฐ๋ฒŒ ํ•จ์ˆ˜๋ฅผ ์ •๋ฆฌํ•จ์œผ๋กœ์จ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์˜ ์›์ธ์„ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค.
useEffect/useLayoutEffect์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ๋…์— ๋Œ€ํ•ด ์–ธ์ œ๋‚˜ ๊ตฌ๋…์„ ํ•ด์ œํ•˜๋Š” ๋กœ์ง์„ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
setInterval์ด๋‚˜ ์†Œ์ผ“ ์—ฐ๊ฒฐ๊ณผ ๊ฐ™์€ ์–ด๋–ค ๊ตฌ๋…์ด๋“ ์ง€ ๋ง์ž…๋‹ˆ๋‹ค.

2. useState ํ›…์—์„œ ์—…๋ฐ์ดํŠธ๋˜๋Š” ์ƒํƒœ์— ๊ด€๋ จ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ํ•˜์ง€๋งˆ๋ผ

์ƒˆ๋กœ์šด ํ•™์ƒ๋“ค์ด ํ”„๋กœ์ ํŠธ ๊ตฌํ˜„์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ์ œ๊ฐ€ ํ•ญ์ƒ ํ•˜๋Š” ํ•œ ๋งˆ๋””๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋„ˆ๋ฌด ์ด๋ฅธ ์ตœ์ ํ™”๋Š” ๋ชจ๋“  ์•…์˜ ๊ทผ์›์ด๋‹ค. - Donald Knuth

๊ทธ๋Ÿฌ๋‚˜ ๋•Œ๋•Œ๋กœ ํ•™์ƒ๋“ค์ด ๊ฐœ๋ฐœ ๊ณผ์ •๊ณผ ์ƒˆ๋กœ์šด ๊ฒƒ๋“ค์„ ์•Œ์•„๊ฐ€๋Š” ๊ณผ์ •์—์„œ ๋„ˆ๋ฌด ์—ด์ •์„ ์Ÿ์•„ ๋ถ“๋Š๋ผ ์ด ๋ง์„ ๊นŒ๋จน๊ณค ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ๋ณด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

const Component1:FC = () => {
    const [users, setUsers] = useState<User[]>([]);
    const setUserList = useCallback(setUsers, []);
    
    return <Component2 setUserList={setUserList}/>
}

๊ทธ๋Ÿฌ๋‚˜ ๋ฆฌ์•กํŠธ๋Š” setState ํ•จ์ˆ˜์˜ ๋™์ผ์„ฑ์ด ์•ˆ์ •์ ์ด๊ณ  ๋ฆฌ๋ Œ๋”๋ง๋  ๋•Œ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์„ ๊ฑฐ๋ผ๊ณ  ๋ณด์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ์ตœ์ ํ™”๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋‹ค๋ฅธ ํ•œํŽธ์œผ๋กœ๋Š” ์ด๋Ÿฐ ์ ๋“ค์„ ๊ณ ๋ฏผํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์€ ๋ฉ‹์ง„ ์ผ์ด๊ธฐ๋Š” ํ•ฉ๋‹ˆ๋‹ค.

3. ์ž์‹ ์ปดํฌ๋„ŒํŠธ๊ฐ€ memo ํ•จ์ˆ˜๋กœ ๊ฐ์‹ธ์งˆ ๋•Œ prop์œผ๋กœ ๋„˜๊ธฐ๋Š” ์ธ๋ผ์ธ ํ•จ์ˆ˜๋Š” ๋ฉ”๋ชจ๋ผ์ด์ฆˆํ•˜๋ผ

์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค.

type User = {
    name: string,
    roles: string[]
}

type UserRolesProps = {
    roles: string[],
    deleteRole: (role: string) => void
}
const UserRoles: FC<UserRolesProps> = React.memo(({roles, deleteRole}) => {
    console.log('Render User Roles');
    return (
        <div>
            {roles.map((role, i) =>
                <span key={i} onClick={() => deleteRole(role)}>{role}</span>
            )}
        </div>
    );
});

export const User: FC = () => {
    console.log('Render User component');
    const [user, changeUser] = useState<User>({name: 'Peter', roles: ['admin']});

    const deleteRole = (deletedRole: string) => {
        changeUser((prevUser) => ({
            ...prevUser,
            roles: prevUser.roles.filter(role => role !== deletedRole)
        }));
    };

    const changeName = (name: string) => {
        changeUser((prevUser) => ({...prevUser, name}));
    };

    return (
        <div>
            <input value={user.name} onChange={(e) => changeName(e.target.value)}/>
            <UserRoles roles={user.roles} deleteRole={deleteRole}/>
        </div>
    );
};

์ฝ”๋“œ ์œ„์น˜ ์ˆœ์„œ ๋ณ€๊ฒฝ

User ์ปดํฌ๋„ŒํŠธ์™€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ ํ•˜๋‚˜๊ฐ€ ์žˆ๋Š”๋ฐ, UserRoles๋Š” ์œ ์ €์˜ ์—ญํ• ์—๋งŒ ์˜์กดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ UserRole์„ React.memo ํ•จ์ˆ˜๋กœ ๊ฐ์‹ธ๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์— ์ฃผ๋ชฉํ•˜์„ธ์š”. ์„ฑ๋Šฅ ์ด์Šˆ๋ฅผ ์‹ ๊ฒฝ์จ์„œ props๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์„ ๋•Œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์‹ถ์ง€ ์•Š์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ๋ฐ ๋ฌธ์ œ๋Š” deleteRole์ด ์ธ๋ผ์ธ prop์ด๊ณ  ๋ฆฌ์•กํŠธ๊ฐ€ User ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌ๋ Œ๋”๋งํ•  ๋•Œ deleteRole ํ•จ์ˆ˜์˜ ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณ„์† ์ƒ์„ฑํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊ฐ„๊ณผํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰ user.role์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์„ ๋•Œ deleteRole์€ ๊ฐ ํƒ€์ž„๋งˆ๋‹ค ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ React.memo์— ๊ฐ์‹ธ์ ธ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” ์˜๋ฏธ๊ฐ€ ์—†์–ด์ง‘๋‹ˆ๋‹ค.

์•„๋งˆ ์—ฌ๋Ÿฌ๋ถ„๋“ค๋„ ์ด๋ฏธ ๋‹ต์„ ์•Œ๊ณ  ๊ณ„์‹ค ๊ฒ๋‹ˆ๋‹ค. deleteRole ํ•จ์ˆ˜๋ฅผ useCallback ํ•จ์ˆ˜๋กœ ๊ฐ์‹ธ๋ฉด ๋˜๋Š” ๊ฒƒ์ด์ฃ .

export const User: FC = () => {
  
   // skipped for brevity

    const deleteRole = useCallback((deletedRole: string) => {
        changeUser((prevUser) => ({
            ...prevUser,
            roles: prevUser.roles.filter(role => role !== deletedRole)
        }));
    }, []);

   // skipped for brevity
};

์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•œ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.

4. ์ƒํƒœ์˜ ์—…๋ฐ์ดํŠธ๋ฅผ ๋‘˜ ๋‹ค ๊ฐ€๋Šฅํ•˜๋”๋ผ๋„ ๋™๊ธฐ ์ž‘์—…๋ณด๋‹ค๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์œผ๋กœ ์ทจ๊ธ‰ํ•˜๋ผ

๋ฉด์ ‘์—์„œ 1000ms๋งˆ๋‹ค ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ์นด์šดํ„ฐ์˜ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„์„ ์š”์ฒญํ•œ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ข…์ข… ์ œ๊ฐ€ ๋ณด๋˜ ์ฝ”๋“œ๋ฅผ ๋ณด์‹œ์ฃ .

function Counter() {
  let [count, setCount] = useState(0);

  useEffect(() => {
    let id = setInterval(() => {
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(id);

 }, []);

  return <h1>{count}</h1>;
}

์—ฌ๋Ÿฌ๋ถ„๋„ ์˜ˆ์ƒํ•˜๋“ฏ์ด, ๋ผ์ธ 6์—์„œ count ๊ฐ’์€ ํ•จ์ˆ˜ ํด๋กœ์ €์—์„œ ๊ฐ€์ ธ์˜ค๋ฏ€๋กœ ํ•ญ์ƒ 0์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๊ฐ 1000ms๋งˆ๋‹ค ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ค๋ ค๊ณ  ํ•จ์—๋„ ๋ง์ž…๋‹ˆ๋‹ค. ํ™”๋ฉด์—์„œ ์šฐ๋ฆฌ๋Š” 0๊ณผ 1000ms ํ›„์—๋Š” 1์„ ๊ณ„์† ๋ณด๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์นด์šดํ„ฐ๋Š” ์ ˆ๋Œ€ ์ฆ๊ฐ€์‹œํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋ฆฌ์•กํŠธ์—์„œ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด์ฃ . code sandbox๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”

์ƒํƒœ ๊ฐ’ ๋ณ€๊ฒฝ์„ ๋น„๋™๊ธฐ ์ž‘์—…์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

export default function Counter() {
  let [count, setCount] = useState(0);

  useEffect(() => {
    let id = setInterval(() => {
      setCount((count) => count + 1);
    }, 1000);
    return () => clearInterval(id);
  }, []);

  return <h1>{count}</h1>;
}

setCount(count + 1) ๋Œ€์‹ ์— setCount((count) => count + 1์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
์ด ๊ฐ’์€ ํ•จ์ˆ˜ ํด๋กœ์ €๊ฐ€ ์•„๋‹Œ ์ด์ „์˜ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ์ƒํƒœ์—์„œ ๊ฐ€์ ธ์˜ค๋Š” ๊ฐ’์ž…๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ํฅ๋ฏธ๋กœ์šด ์ผ€์ด์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

const Task02 = () => {
   const [count, setCount] = useState(0);

   const onClick = () => {
       setCount(count + 1);
       setCount(count + 1);
   }

   return (
       <div>
           Count: {count}
           <div>
               <button onClick={onClick}>Increment twice</button>
           </div>
       </div>
   )
}

๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ƒํƒœ๊ฐ’์ด 2๋ฒˆ ์ฆ๊ฐ€ํ•  ๊ฑฐ๋ผ๊ณ  ์˜ˆ์ƒํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๋•Œ ์˜ค์ง 1๋งŒ ์ฆ๊ฐ€๋  ๋ฟ์ž…๋‹ˆ๋‹ค.
React๋Š” ๊ฝค ๋˜‘๋˜‘ํ•ด์„œ ๊ฐ ์ž‘์—…์„ ๋™๊ธฐ์ ์œผ๋กœ ์™„์„ฑ์‹œํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฐฐ์น˜์—์„œ ์—ฌ๋Ÿฌ ์ƒํƒœ๊ฐ’ ๊ฐฑ์‹ ์„ ๋ชจ์œผ๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

Object.assign(
    prevState,
    { count: prevState.count + 1 },
    { count: prevState.count + 1 }
)

๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ์˜ ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋ ค๋ฉด ๋น„๋™๊ธฐ ์ž‘์—…์œผ๋กœ ์ทจ๊ธ‰ํ•˜์—ฌ ์•„๋ž˜์ฒ˜๋Ÿผ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

const Task02 = () => {
   const [count, setCount] = useState(0);

   const onClick = () => {
       setCount((count) => count + 1);
       setCount((count) => count + 1);
   }

   return (
       <div>
           Count: {count}
           <div>
               <button onClick={onClick}>Increment twice</button>
           </div>
       </div>
   )
}

๊ฒฝํ—˜์ ์œผ๋กœ ๋น„์ถ”์–ด ๋ดค์„ ๋•Œ ๋ฆฌ์•กํŠธ๊ฐ€ ์ƒํƒœ๋ฅผ ๋™๊ธฐ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ๋งŽ์€ ๊ฒฝ์šฐ์— ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์–ธ์ œ๋‚˜ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ƒํƒœ ๊ฐฑ์‹ ์„ ์œ ์ง€ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋Š” React๊ฐ€ ๊ฐฑ์‹ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๊ณ  ์•„๋ฌด๋„ ์ด์— ๋Œ€ํ•ด ๋ฐ˜๋Œ€ํ•˜์ง€ ์•Š๊ฒŒ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

5. useRef hook์˜ ์‚ฌ์šฉ์„ ๋‚จ์šฉํ•˜์ง€ ๋งˆ๋ผ

๋ฐฐ์šฐ๊ธฐ ์‹œ์ž‘ํ•  ๋•Œ ์•„๋งˆ ์—ฌ๋Ÿฌ๋ถ„์€ ๋ฆฌ์•กํŠธ๊ฐ€ ๋ช…๋ นํ˜•๋ณด๋‹ค ์„ ์–ธํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๊ณ ์ˆ˜ํ•œ๋‹ค๊ณ  ๋“ค์œผ์…จ์„ ๊ฒ๋‹ˆ๋‹ค. ๋•Œ๋•Œ๋กœ ๊ทธ ๋‘˜์˜ ์ฐจ์ด๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์‹ค์ „์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ useRef ํ›…์„ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์€ ์•„๋งˆ ์ด ๊ทœ์น™์„ ์œ„๋ฐ˜ํ•˜๋ฉฐ ์„ ์–ธํ˜•์—์„œ ๋ช…๋ นํ˜• ์ ‘๊ทผ๋ฒ•์œผ๋กœ ๊ด€์ ์ด ๋ฐ”๋€ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ธด ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์„ ๋ณผ๊นŒ์š”. codesandbox

export const App: FC = () => {
    const inputGroupRef = useRef<HTMLDivElement>(null);
    const inputRef = useRef<HTMLInputElement>(null);

    useEffect(() => {
        const handleFocus = () => inputGroupRef.current!.classList.add(styles.active);
        const handleBlur = () => inputGroupRef.current!.classList.remove(styles.active);

        inputRef.current!.addEventListener('focus', handleFocus);
        inputRef.current!.addEventListener('blur', handleBlur);

        return () => {
            inputRef.current!.removeEventListener('focus', handleFocus);
            inputRef.current!.removeEventListener('blur', handleBlur);
        }
    }, []);

    return (
        <div className={styles.container}>
            <div ref={inputGroupRef} className={styles.inputGroup}>
                <label className={styles.label}>
                    Your name
                </label>
                <input
                    ref={inputRef}
                    className={styles.input}
                    type="text"
                />
                <div className={styles.border}/>
            </div>

        </div>
    )
};

์ด ์ฝ”๋“œ๋Š” ๊ฝค ๋ณ„๋กœ์ธ ๊ตฌํ˜„์ด๋„ค์š”. ์ฝ”๋“œ๋ฅผ ๋ณด๋‹ˆ jQuery๊ฐ€ ๋ช…๋ นํ˜• ๋ฐฉ์‹๊ณผ ํ•จ๊ป˜ ์‚ด์•„์žˆ์—ˆ๋‹ค๋Š” ๊ฒƒ์ด ์ƒ๊ฐ๋‚˜๋„ค์š”.
์—ฌ๊ธฐ์—์„œ ์šฐ๋ฆฌ๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ๋ฅผ ๋ช…๋ นํ˜•์œผ๋กœ ๋ณ€๊ฒฝ์‹œํ‚ค๋ฉฐ DOM ํŠธ๋žœ์ง€์…˜์„ ํšจ๊ณผ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” React์˜ ํž˜์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๊ฐœ๋ฐœ์ž์˜ ์˜๋„๋Š” ๊ฐ input๋งˆ๋‹ค ์ปดํฌ๋„ŒํŠธ์˜ CSS ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ค๊ณ ์ž ํ•˜๋Š” ๊ฒƒ์ด์—ˆ๋Š”๋ฐ์š”.
์šฐ๋ฆฌ๋Š” useRef์˜ ์‚ฌ์šฉ์„ ์ œ๊ฑฐํ•ด์„œ ์„ ์–ธํ˜• ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์žฌ์ž‘์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

export const App: FC = () => {
    const [isActive, changeState] = useState(false);

    return (
        <div className={styles.container}>
            <div className={isActive ? '${styles.inputGroup} ${styles.active}' : styles.inputGroup}>
                <label className={styles.label}>
                    Your name
                </label>
                <input
                    onFocus={() => changeState(() => true)}
                    onBlur={() => changeState(() => false)}
                    className={styles.input}
                    type="text"
                />
                <div className={styles.border}/>
            </div>
        </div>
    );
};

๊ฒฝํ—˜์ ์œผ๋กœ ์—ฌ๋Ÿฌ๋ถ„์€ ๊ฐ€๋Šฅํ•˜๋ฉด ๋ ˆํผ๋Ÿฐ์Šค ํ˜ธ์ถœ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
์—ฌ๋Ÿฌ๋ถ„์ด useRef ํ›…์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•œ 3๊ฐ€์ง€ ์ข‹์€ ์ด์œ ์ž…๋‹ˆ๋‹ค.

  • focus, ํ…์ŠคํŠธ selection, ๋ฏธ๋””์–ด playback ๊ด€๋ฆฌ
  • ๋ช…๋ นํ˜• ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ํ˜ธ์ถœ
  • ์„œ๋“œํŒŒํ‹ฐ DOM ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฒฐํ•ฉ

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ข‹์€ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” 4๊ฐ€์ง€ ํ•„์ˆ˜ ํŒ

์›๋ฌธ '4 Essential Tips for Better Asynchronous Code in JavaScript'

์ƒˆ๋กœ์šด ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ์ˆ ์„ ๋ฐฐ์šฐ๋Š” ๊ฒƒ์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๊ฐ€ "์ž‘๋™ํ•˜๋Š” ๊ฒƒ"์„ ๋„˜์–ด "๋” ์ž˜" ์ž‘๋™ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ํ•œ ๋‘๊ฐœ์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๋งŒ ๋งŒ๋“ค์–ด ๋ดค๊ฑฐ๋‚˜ callback, promise, async/await ๋“ฑ์œผ๋กœ ๋น„๋™๊ธฐ ํ˜ธ์ถœ์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ์„์ง€๋ผ๋„ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์ž˜ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ฒŒ๋˜๋Š” ๊ฑด ์–ธ์ œ๋‚˜ ์—ฌ๋Ÿฌ๋ถ„์—๊ฒŒ ์œ ์šฉํ•˜๊ฒŒ ์“ฐ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ €ํฌ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ๋ฅผ ์ž˜ ๋‹ค๋ฃจ๊ณ  ํšจ์œจ์ ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ "๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ 201" ํŒ๊ณผ ํŠธ๋ฆญ์„ ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ๊ณต์œ ๋“œ๋ฆด ๊ฒƒ์ž…๋‹ˆ๋‹ค. "์‹œ๊ฐ„/์ฝœ๋ฐฑ ์ง€์˜ฅ์˜ ์‹œ์ž‘"์„ ํ”ผํ•˜๊ณ  ์ตœ๊ทผ์— ์‚ฌ์šฉ๋˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋น„๋™๊ธฐ ํŒจํ„ด์— ์ง‘์ค‘ํ•˜๊ณ ์ž ๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ์—ญ์‚ฌ๋ฅผ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ await์€ async ํ•จ์ˆ˜๋กœ ๊ฐ์‹ธ๊ณ  fakeFetch()์€ ๋‹ค๋ฅธ ์–ด๋–ค ๊ณณ์— ์ •์˜๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

1. ๋ณ‘๋ ฌ์ ์œผ๋กœ ์‹คํ–‰ํ•˜๊ณ  ๋‚˜์ค‘์— ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ํ•˜์—ฌ ์ฝ”๋“œ๊ฐ€ ๋น ๋ฅด๊ฒŒ ์‹คํ–‰๋˜๋„๋ก ํ•˜๋ผ

๊ฐ Promise๋“ค์€ fetchFile(file)์„ ์“ฐ์ž๋งˆ์ž GET ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ๋น ๋ฆ…๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— await์€ promise๊ฐ€ ํ•ด๊ฒฐ๋  ๋•Œ๊นŒ์ง€ ํ•จ์ˆ˜์˜ ์‹คํ–‰์„ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค. ๋ถˆํ•„์š”ํ•œ ๊ธฐ๋‹ค๋ฆผ์„ ์ œ๊ฑฐํ•˜๊ณ , ๋” ๋น ๋ฅธ promise๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ํ•˜๋‚˜์”ฉ ๋ณด๋‚ด์ง€ ์•Š๊ณ  ํ•œ๋ฒˆ์— ์—ฌ๋Ÿฌ ํŒŒ์ผ์— ๋Œ€ํ•œ ์š”์ฒญ์„ ๋ณด๋ƒ„์œผ๋กœ์จ ์ฝ”๋“œ๋ฅผ ๋” ํšจ์œจ์ ์ด๊ณ  ๋น ๋ฅด๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ๋ณ‘๋ ฌ์ ์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š”๊ฐ€?

์ƒˆ๋กœ์šด Promise๋ฅผ ๋ฐ˜๋“ค๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋‚˜์ค‘์— ๋ฐ›์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ ์˜ˆ์ œ์—์„œ ์„ธ ํŒŒ์ผ์„ ๋™์‹œ์— fetchํ•˜๊ณ  ๋ฐ›์€ promise๋Š” ๋‚˜์ค‘์— ์–ธ์  ๊ฐ€(await)์—์„œ resolve ๋˜์–ด์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

// fake fetch function returning a new Promise object
const fetchFile = (file) => new Promise(resolve => fakeFetch(file, resolve))

// ํ•˜๋‚˜์”ฉ ๋ณ‘๋ ฌ์ ์œผ๋กœ ๋ชจ๋“  ํŒŒ์ผ์— ๋Œ€ํ•ด ์š”์ฒญ์„ ๋ณด๋ƒ„
const promise1 = fetchFile('file1')
const promise2 = fetchFile('file2')
const promise3 = fetchFile('file3')

// ๋‚˜์ค‘์— ๊ธฐ๋‹ค๋ฆฌ๊ธฐ
const file1 = await promise1

Promise ๊ฐ์ฒด์—๋Š” ์—ฌ๋Ÿฌ promise๋ฅผ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•๋“ค์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์—ฌ๋Ÿฌ ํŒŒ์ผ์„ ๋™์‹œ์— fetchํ•  ์ˆ˜ ์žˆ๋Š” ํŽธ๋ฆฌํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Promise.all()์€ ๋ณ‘๋ ฌ์ ์œผ๋กœ ํŒŒ์ผ์„ ์š”์ฒญํ•˜๊ณ  ๊ฐ™์€ ๋ผ์ธ์—์„œ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. ๋ฐ”๋กœ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ์–ด์š”!

// ๊ฐ’์„ ๊ธฐ๋‹ค๋ฆฌ์ง€๋งŒ ๊ฐ ์š”์ฒญ์€ ๋ณ‘๋ ฌ์ ์œผ๋กœ ๋ณด๋‚ด์ง€๋Š” ์ค‘
const fileArray = await Promise.all([fetchFile('file1'), fetchFile('file2'), fetchFile('file3')])

๋„ˆ๋ฌด ๋งŽ์€ ๋ณ‘๋ ฌ ์š”์ฒญ์€ (ํŠนํžˆ ํฐ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•˜๋Š” ์ƒํ™ฉ์—์„œ) ๋‚˜์œ ์„ฑ๋Šฅ์„ ์•ผ๊ธฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ์„ ๊ธฐ์–ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด, ์–ธ์ œ await์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”๊ฐ€?

์ฝ”๋“œ์—์„œ ๋ฐ์ดํ„ฐ๋ผ๋ฆฌ ์˜์กด์„ฑ์ด ์žˆ์„ ๋•Œ ์ด์ „ promise์˜ resolve๋œ ๊ฒฐ๊ณผ๊ฐ’์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํŒŒ์ผ๋“ค์„ ์ˆœ์ฐจ์ ์œผ๋กœ ๋ฐ›์•„์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ ์˜ˆ์ œ์—์„œ file2์— ๋Œ€ํ•œ fetch ์š”์ฒญ์€ ์ฒ˜์Œ์— ๋ณด๋‚ธ fetchFile() ํ˜ธ์ถœ์ด file1์™€ ํ•จ๊ป˜ resolve๋˜์–ด์กŒ์„ ๋•Œ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋™์‹œ์— ์š”์ฒญ์„ ๋ณด๋‚ด๋˜ ์ด์ „ ์˜ˆ์ œ์— ๋น„ํ•˜๋ฉด ๊ฝค ๋Š๋ฆฝ๋‹ˆ๋‹ค. ๊ฐ ๋ณ€์ˆ˜๋“ค์€ promise๋ฅผ ์ฐธ์กฐํ•˜์ง€ ์•Š๊ณ  ํŒŒ์ผ์„ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.

// ์ˆœ์ฐจ์ ์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋ƒ„
const file1 = await fetchFile('file1') // resolve ๋  ๋•Œ๊นŒ์ง€ ์ •์ง€
const file2 = await fetchFile('file2') 
const file3 = await fetchFile('file3')

์•„๋ž˜ ์˜ˆ์ œ๋„ ์ˆœ์ฐจ์ ์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. order๋ฅผ fetchํ•˜๋ ค๋ฉด fetchUser() Promise๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค.

const user = await fetchUser()
const userOrders = await fetchOrders(user)

ํ•ต์‹ฌ ํŒ : ๋…๋ฆฝ์ ์ธ ๋น„๋™๊ธฐ ์ž‘์—…๋“ค์€ ๋ณ‘๋ ฌ ์š”์ฒญ์„ ์‚ฌ์šฉํ•˜์—ฌ ์‹œ๊ฐ„ ๋ฐ ์„ฑ๋Šฅ์„ ๋‚ญ๋น„ํ•˜์ง€ ๋ง์ž.

2. map()์œผ๋กœ Promise ๋ฐฐ์—ด ์ƒ์„ฑํ•˜๊ธฐ

์œ„ ์˜ˆ์ œ์—์„œ๋Š” ๊ฐ€์ ธ์˜ฌ ํŒŒ์ผ์˜ ์ˆ˜๋ฅผ ์ •ํ™•ํžˆ ์•„๋Š” ์ƒํ™ฉ์—์„œ ํ•ด๋‹น ์ˆ˜๋งŒํผ์˜ promise๋ฅผ ์‹คํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž„์˜์˜ ๊ธธ์ด์˜ ํŒŒ์ผ์„ fetchํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”?

์ •์˜๋˜์ง€ ์•Š์€ ๊ธธ์ด์˜ ์ง‘ํ•ฉ์œผ๋กœ ์ž‘์—…ํ•  ๋•Œ Javascript๋Š” array์™€ array method๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. promise๋ฅผ ๋ฆฌํ„ดํ•˜๊ณ  promise์— fileNames ๋ฐฐ์—ด์˜ ๊ฐ’์„ ๋งคํ•‘ํ•˜๋Š” map()๊ณผ fetchFile()์„ ์‚ฌ์šฉํ•˜์—ฌ promise์˜ ๋ฐฐ์—ด์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// fake fetch function returning a new Promise object
const fetchFile = (file) => new Promise(resolve => fakeFetch(file, resolve))

// ์ž„์˜์˜ ๊ธธ์ด๋ฅผ ๊ฐ€์ง€๋Š” ๋ฐฐ์—ด
const fileNames = ['file1', 'file2', 'file3'/* ... */] 

// Promise ๊ฐ์ฒด๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ์ฝœ๋ฐฑ์„ ๊ฐ€์ง„ promise ๋ฐฐ์—ด ์ƒ์„ฑ
const promises = fileNames.map(fetchFile)

์ผ๋‹จ promise๋“ค์„ ๋ฐฐ์—ด๋กœ ์Œ“์•„๋‘” ๋‹ค์Œ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉด์„œ promise๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜๋„ ์žˆ๊ณ , Promise.all()๊ณผ ๊ฐ™์€ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ๋ฐ›๋Š” Promise ๊ฐ์ฒด ๋ฉ”์†Œ๋“œ์— ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ํŒ : ๋งŽ์€ promise๋ฅผ ๋‹ค๋ฃฐ ๋•Œ, promise๋ฅผ ๋ฐฐ์—ด์— ์ €์žฅํ•˜๋ผ.

[๋ฒˆ์—ญ] Netflix๊ฐ€ GraphQL Federation์œผ๋กœ API๋ฅผ ํ™•์žฅํ•˜๋Š” ๋ฐฉ๋ฒ• (Part 1)

์›๋ฌธ : How Netflix Scales its API with GraphQL Federation (Part 1)

๋„ทํ”Œ๋ฆญ์Šค๋Š” ๋ฃจ์ฆˆํ•œ ๊ฒฐํ•ฉ๊ณผ ํ™•์žฅ์„ฑ์ด ๋›ฐ์–ด๋‚œ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์•Œ๋ ค์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ๋…๋ฆฝ์ ์ธ ์„œ๋น„์Šค๋ฅผ ํ†ตํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ์†๋„๋กœ ๋ฐœ์ „ํ•˜๋ฉฐ ๋…๋ฆฝ์ ์œผ๋กœ ํ™•์žฅ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๋Ÿฌ ์„œ๋น„์Šค์— ๊ฑธ์ณ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ ๋ณต์žก์„ฑ์„ ๊ฐ€์ค‘์‹œํ‚ค๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. UI ๊ฐœ๋ฐœ์ž์—๊ฒŒ 100๊ฐ€์ง€์˜ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๋ฅผ ๋…ธ์ถœ์‹œํ‚ค๋Š” ๋Œ€์‹  ๋„ทํ”Œ๋ฆญ์Šค๋Š” ์—ฃ์ง€์—์„œ ํ†ตํ•ฉ๋œ API ๊ณ„์ธต์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

UI ๊ฐœ๋ฐœ์ž๋Š” ํฐ ๋„๋ฉ”์ธ์— ๋Œ€ํ•œ ํ•˜๋‚˜์˜ ๊ฐœ๋…์ ์ธ API๋กœ ์ž‘์—…ํ•˜๋Š” ๋‹จ์ˆœํ•จ์„ ๊ต‰์žฅํžˆ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๋Š” API ๊ณ„์ธต์ด ์ œ๊ณตํ•˜๋Š” ๋””์ปคํ”Œ๋ง๊ณผ ํƒ„์„ฑ์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ์˜ ๋น„์ฆˆ๋‹ˆ์Šค๊ฐ€ ํ™•์žฅ๋จ์— ๋”ฐ๋ผ, ๋น ๋ฅด๊ฒŒ ํ˜์‹ ํ•˜๋Š” ์šฐ๋ฆฌ์˜ ๋Šฅ๋ ฅ์ด ๋ณด์ด์ง€ ์•Š๋Š” ์ ๊ทผ์„ ์— ๊ฐ€๊นŒ์›Œ์กŒ์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ณ  ๋„๋ฉ”์ธ ๋ณต์žก์„ฑ์ด ์ปค์ง์— ๋”ฐ๋ผ API ์ง‘ํ•ฉ์ฒด ๊ณ„์ธต์„ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ์€ ๋”์šฑ ์–ด๋ ค์›Œ์กŒ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด API ๊ณ„์ธต์„ ๊ฐ•ํ™”ํ•˜๋Š” ์—ฐํ•ฉ๋œ(federated) GraphQL ํ”Œ๋žซํผ์„ ๊ฐœ๋ฐœํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ™•์žฅ์„ฑ ๋ฐ ์šด์˜์„ฑ๊ณผ ๊ฐ™์€ ์ฐจ์›๋“ค์„ ์ตœ์†Œํ™”ํ•˜๋ฉฐ ๋งŽ์€ ์ผ๊ด€์„ฑ๊ณผ ๊ฐœ๋ฐœ์†๋„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋„ทํ”Œ๋ฆญ์Šค ์ŠคํŠœ๋””์˜ค ์ƒํƒœ๊ณ„์—์„œ ์ด ์ ‘๊ทผ๋ฒ•์„ ์„ฑ๊ณต์ ์œผ๋กœ ๊ตฌ์ถ•ํ–ˆ์œผ๋ฉฐ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์—์„œ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋Ÿฌ ํŒจํ„ด๊ณผ ์ ์šฉ๋“ค์„ ํƒ์‚ฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์˜๊ฐ์„ ์ฃผ๊ณ  ๋‹ค๋ฅธ ๊ณณ ๋˜ํ•œ ์ ์šฉ ๊ฐ€๋Šฅ์„ฑ์— ๋Œ€ํ•œ ๋Œ€ํ™”๋ฅผ ์žฅ๋ คํ•˜๊ณ ์ž ์ด์•ผ๊ธฐ๋ฅผ ๋‚˜๋ˆ„๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ๋ก€ ์—ฐ๊ตฌ : Studio Edge

Intro to Studio Ecosystem

Netflix๋Š” ๊ต‰์žฅํžˆ ๋น ๋ฅด๊ฒŒ ์˜ค๋ฆฌ์ง€๋„ ์ปจํ…์ธ ๋ฅผ ์ œ์ž‘ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. TV ์‡ผ๋‚˜ ์˜ํ™”๊ฐ€ ๋„ทํ”Œ๋ฆญ์Šค์—์„œ ๋ฐฉ์˜๋  ๋•Œ๊นŒ์ง€ ์•„์ฃผ ๋งŽ์€ ์ผ๋“ค์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์Šค์นด์šฐํŠธ, ์บ์ŠคํŒ… ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ฑฐ๋ž˜์™€ ๊ณ„์•ฝ ํ˜‘์ƒ, ์ œ์ž‘, ์‹œ๊ฐ ํšจ๊ณผ์™€ ์• ๋‹ˆ๋ฉ”์ด์…˜, ์ž๋ง‰๊ณผ ๋”๋น™ ๋“ฑ์„ ํฌํ•จํ•˜์—ฌ ์•„์ฃผ ๋งŽ์€ ๊ฒƒ๋“ค์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ŠคํŠœ๋””์˜ค ์—”์ง€๋‹ˆ์–ด๋ง์€ ์ด ์›Œํฌํ”Œ๋กœ์šฐ๋“ค์„ ๊ฐ•ํ™”ํ•˜๋Š” ์ˆ˜๋ฐฑ๊ฐ€์ง€์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ํˆด์„ ์ œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

image

Studio API

๋ช‡ ๋…„์ „์œผ๋กœ ๋Œ์•„๊ฐ€๋ณด๋ฉด, ์ŠคํŠœ๋””์˜ค ๊ณต๊ฐ„์—์„œ์˜ ํ•œ ๊ฐ€์ง€ ๋ฌธ์ œ์ ์€ ๋ฐ์ดํ„ฐ์™€ ๋ฐ์ดํ„ฐ ๊ด€๊ณ„๋“ค์˜ ์ฆ๊ฐ€ํ•˜๋Š” ๋ณต์žก์„ฑ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์œ„์—์„œ ์„ค๋ช…ํ•œ ์›Œํฌํ”Œ๋กœ์šฐ๋Š” ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋‚˜ ๋ฐ์ดํ„ฐ์™€ ๋ฐ์ดํ„ฐ ๊ด€๊ณ„๋Š” ์—ฌ๋Ÿฌ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๋กœ ๋ถ„์‚ฐ๋˜์–ด ์กด์žฌํ–ˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๋•ํŠธ ํŒ€์€ ๋‘ ๊ฐ€์ง€ ๊ตฌ์กฐ์  ํŒจํ„ด์œผ๋กœ ์ด๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

  1. ๋‹จ ํ•˜๋‚˜์˜ ๊ฒฐํ•ฉ๋œ ๋ ˆ์ด์–ด : ๋ฃจ์ฆˆํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งŽ์€ ํŒ€๋“ค์ด ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ๊ฐ์ž์˜ ํ”„๋กœ๋•ํŠธ ๋‹ˆ์ฆˆ์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ๊ฒฐํ•ฉ ๋ ˆ์ด์–ด๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ๋งŽ์€ ์‹œ๊ฐ„์„ ์†Œ๋ชจํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” BFF๋ฅผ ํ†ตํ•ด UI ํŒ€์ด๋‚˜ ๋ฏธ๋“œํ‹ฐ์–ด ์„œ๋น„์Šค์˜ ๋ฐฑ์—”๋“œ ํŒ€์— ์˜ํ•ด ์ˆ˜ํ–‰๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  2. ๋‹ค๋ฅธ ํŒ€์˜ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๊ตฌ์ฒดํ™”๋œ ๋ทฐ(materialized views) : ์–ด๋–ค ํŒ€๋“ค์€ ์‹œ์Šคํ…œ์˜ ์š”๊ตฌ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ํŒ€์˜ ๋ฐ์ดํ„ฐ์˜ ๊ตฌ์ฒดํ™”๋œ ๋ทฐ๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ํŒจํ„ด์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ตฌ์ฒดํ™”๋œ ๋ทฐ๋Š” ์„ฑ๋Šฅ์ƒ์˜ ์ด์ ์€ ๊ฐ€์ง€์ง€๋งŒ ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ์— ์žˆ์–ด์„œ๋Š” ๋ถ€์กฑํ–ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ์ŠคํŠœ๋””์˜ค ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐ€๋ฅด๋Š” ์ผ๊ด€๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋Š” 2018๋…„ ์ŠคํŠœ๋””์˜ค ์—”์ง€๋‹ˆ์–ด๋ง์—์„œ ๊ฐ€์žฅ ๋จผ์ € ๋‹ค๋ฃจ์–ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

Graph API : ๊ทผ๋ณธ์ ์ธ ํ•„์š”์„ฑ์„ ๋” ์ž˜ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด, ์šฐ๋ฆฌ ํŒ€์€ "Studio API"๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ํ๋ ˆ์ด์…˜ graph API๋ฅผ ์ œ์ž‘ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ชฉํ‘œ๋Š” ๋ฐ์ดํ„ฐ์™€ ๊ด€๊ณ„๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋‚˜๋กœ ํ†ต์ผ๋œ ์ถ”์ƒํ™”๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. Studio API๋Š” ํ•ต์‹ฌ์ ์ธ ๊ณต์œ  ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ์œ ์šฉ์„ฑ์„ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ API ๊ธฐ์ˆ ์ธ GraphQL์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. Studio API์˜ ์ปจ์Šˆ๋จธ๋Š” ๊ทธ๋ž˜ํ”„๋ฅผ ํƒ์ƒ‰ํ•˜๊ณ  ๋” ๋น ๋ฅด๊ฒŒ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ œ์ž‘ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ GraphQL์˜ ๋ชจ๋“  ํ•„๋“œ๋“ค์ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•˜๋‚˜์˜ ์ฝ”๋“œ๋กœ ํ•ด๊ฒฐ๋˜์—ˆ์œผ๋ฏ€๋กœ ๋‹ค๋ฅธ UI ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋” ์ ์€ ๋ฐ์ดํ„ฐ ๋ถˆ์ผ์น˜๋ฅผ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

image

image

Studio API์˜ ๋ณ‘๋ชฉํ˜„์ƒ

Studio API์—์„œ ๋…ธ์ถœ๋˜๋Š” ํ•˜๋‚˜์˜ ๊ทธ๋ž˜ํ”„๋Š” ์—„์ฒญ๋‚œ ์„ฑ๊ณต์„ ๊ฑฐ๋‘์—ˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๋•ํŠธ ํŒ€๋“ค์€ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์‰ฝ๊ณ  ์ผ๊ด€๋˜๋Š” ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์„ ์•„์ฃผ ์ข‹์•„ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ ์ปจ์Šˆ๋จธ์™€ ๊ทธ๋ž˜ํ”„๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ ๋•๋ถ„์— ๋ณ‘๋ชฉํ˜„์ƒ์— ๋ถ€๋”ชํžˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ € Studio API ํŒ€์€ ๋„๋ฉ”์ธ ์ „๋ฌธ๊ฐ€์™€ ํ”„๋กœ๋•ํŠธ ๋‹ˆ์ฆˆ๋กœ๋ถ€ํ„ฐ ์—ฐ๊ฒฐ์ด ๋Š๊น€์œผ๋กœ์จ ์Šคํ‚ค๋งˆ์— ๋ถ€์ •์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์ณค์Šต๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ๋กœ ๋ฐฑ์—”๋“œ์˜ ์ƒˆ๋กœ์šด ์š”์†Œ๋“ค๊ณผ Graph API๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์€ ์ˆ˜๋™์ด์—ˆ๊ณ  ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜๊ฐ€ ๋ณด์žฅํ•˜๋Š” ๋น ๋ฅธ ์ง„ํ™”๋ฅผ ๋ฐฉํ•ดํ–ˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•˜๋‚˜์˜ ์ž‘์€ ํŒ€์ด ํ™•๋Œ€๋˜๋Š” ๊ทธ๋ž˜ํ”„์— ๋Œ€ํ•œ ์šด์˜๊ณผ ์ง€์›์„ ๋‹ด๋‹นํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊ฐ๋‹นํ•˜๊ธฐ ์–ด๋ ค์šด ์ผ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜๋กœ ํ†ต์ผ๋˜๋ฉด์„œ ๋””์ปคํ”Œ๋ง๋˜๊ณ  ํ๋ ˆ์ดํŠธ๋˜๋ฉฐ ๋น ๋ฅด๊ฒŒ ์›€์ง์ด๋Š” ๊ฒƒ์ด์ฃ .

ํ•ต์‹ฌ ์›์น™์œผ๋กœ ๋Œ์•„์˜ค๊ธฐ

์ด ๋ณ‘๋ชฉํ˜„์ƒ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์™€ ๋ชจ๋…ธ๋ฆฌ์Šค๋ฅผ ๋ถ„ํ•ดํ•œ ์—ฌ๋Ÿฌ ์ด์•ผ๊ธฐ๋“ค์— ๊ธฐ๋Œ”์Šต๋‹ˆ๋‹ค. Studio API์˜ ํ•˜๋‚˜๋กœ ํ†ต์ผ๋œ GraphQL ์Šคํ‚ค๋งˆ๋ฅผ ์œ ์ง€ํ•จ๊ณผ ๋™์‹œ์— ๋ฆฌ์กธ๋ฒ„์˜ ๊ตฌํ˜„์„ ๊ฐ ๋„๋ฉ”์ธ ํŒ€์œผ๋กœ ๋น„์ค‘์•™ํ™”ํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค.

2019๋…„ ์ดˆ ์ƒˆ๋กœ์šด ์•„ํ‚คํ…์ฒ˜์— ๋Œ€ํ•ด ๋ธŒ๋ ˆ์ธ์Šคํ† ๋ฐํ•˜๊ณ  ์žˆ์„ ๋•Œ Apollo๋Š” GraphQL Federation ๋ช…์„ธ๋ฅผ ๋ฐœํ‘œํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ถ„์‚ฐ๋œ ์˜ค๋„ˆ์‹ญ๊ณผ ๊ตฌํ˜„๊ณผ ํ•จ๊ป˜ ํ•˜๋‚˜์˜ ์Šคํ‚ค๋งˆ์˜ ์ด์ ์„ ์•ฝ์†ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋Œ€ํ•˜๋ฉฐ ์ŠคํŽ™์˜ ํ…Œ์ŠคํŠธ ๊ตฌํ˜„์„ ์‹œ๋„ํ–ˆ๊ณ  GraphQL Federation ๋ฏธ๋ž˜์— ๋Œ€ํ•ด ์•„ํด๋กœ์™€ ํ˜‘์—…ํ•˜๋Š” ๊ฒƒ์— ๋„๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ๋‹ค์Œ ์„ธ๋Œ€ ๊ตฌ์กฐ์ธ "Studio Edge"๋Š” federation์„ ์ค‘์š”ํ•œ ์š”์†Œ๋กœ ํ•˜์—ฌ ๋“ฑ์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.

GraphQL Federation ๋„ํ™”์„ 

GraphQL Federation์˜ ๋ชฉํ‘œ๋Š” ๋‘ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ์ปจ์Šˆ๋จธ์—๊ฒŒ ํ•˜๋‚˜์˜ API๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž์—๊ฒŒ๋Š” ์œ ์—ฐํ•จ๊ณผ ์„œ๋น„์Šค์˜ ๋…๋ฆฝ์„ฑ์„ ์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ๋‹ฌ์„ฑํ•˜๊ณ ์ž ์Šคํ‚ค๋งˆ๋Š” ์ƒ์„ฑ๋˜๊ณ  ์–ด๋–ป๊ฒŒ ์†Œ์œ ๊ถŒ์ด ๋ถ„์‚ฐ๋˜์—ˆ๋Š”์ง€ ์•Œ๋ ค์ฃผ๋„๋ก ์„ค๋ช…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์„ธ ๊ฐ€์ง€ ์—”ํ‹ฐํ‹ฐ์™€ ํ•จ๊ป˜ ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค.

  1. Movie : ๋„ทํ”Œ๋ฆญ์Šค์—์„œ ํƒ€์ดํ‹€์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ˆœํ•จ์„ ์œ„ํ•ด ๊ฐ ํƒ€์ดํ‹€์€ Movie ๊ฐ์ฒด๋ผ๊ณ  ํ•ฉ์‹œ๋‹ค.
  2. Production : ๊ฐ Movie๋Š” ์ŠคํŠœ๋””์˜ค ํ”„๋กœ๋•์…˜๊ณผ ์—ฐ๊ด€๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ Production ๊ฐ์ฒด๋Š” ์œ„์น˜ ์„ ์ •, ๋…ธ์ ์ƒ ๋“ฑ Movie๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ๋“ค์„ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.
  3. Talent : Movie์—์„œ ์ผํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด Talent์ž…๋‹ˆ๋‹ค. ๋ฐฐ์šฐ์™€ ๊ฐ๋… ๋“ฑ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

์„ธ ๋„๋ฉ”์ธ์€ ์„ธ ๊ฐœ์˜ ๋ถ„๋ฆฌ๋œ ์—”์ง€๋‹ˆ์–ด๋ง ํŒ€์ด ์†Œ์œ ํ•˜๋ฉฐ ๊ฐ ํŒ€์€ ๊ฐ์ž์˜ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋‚˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง, ์ƒ์‘ํ•˜๋Š” ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๋ฅผ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์—ฐํ•ฉ๋˜์ง€ ์•Š์€ ๊ตฌํ˜„์—์„œ๋Š” Studio API ํŒ€์ด ์†Œ์œ ํ•˜๋ฉฐ ๊ตฌํ˜„ํ•˜๋Š” ์Šคํ‚ค๋งˆ์™€ ๋ฆฌ์กธ๋ฒ„๋ฅผ ๊ฐ€์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. GraphQL ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ์ฟผ๋ฆฌ๋ฅผ ๋ฐ›์•„ ๊ด‘๋ฒ”์œ„ํ•œ ์ˆœํšŒ๋ฅผ ํ†ตํ•ด ํ•ด๋‹นํ•˜๋Š” ๋ฆฌ์กธ๋ฒ„๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

image

์—ฐํ•ฉ๋˜๋Š” ๊ตฌ์กฐ๋กœ ์ „ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด ํ†ตํ•ฉ๋œ ์Šคํ‚ค๋งˆ๋ฅผ ํฌ์ƒ์‹œํ‚ค์ง€ ์•Š๊ณ  ๊ฐ ๋ฆฌ์กธ๋ฒ„๋“ค์˜ ์†Œ์œ ๊ถŒ์„ ๊ฐ ๋‹ด๋‹นํ•˜๋Š” ๋„๋ฉ”์ธ์œผ๋กœ ์˜ฎ๊ฒจ์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด Movie ํƒ€์ž…์„ GraphQL ์„œ๋น„์Šค ๋ฐ”์šด๋”๋ฆฌ๋กœ ํ™•์žฅํ•ด์•ผ ํ–ˆ์ฃ .

image

Movie ํƒ€์ž…์„ GraphQL ์„œ๋น„์Šค ๋ฐ”์šด๋”๋ฆฌ๋กœ ํ™•์žฅํ•˜๋Š” ๊ฒƒ์ด ๊ธฐ๋Šฅ์€ Movie ํƒ€์ž…์„ Federated Type์œผ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ํ•„๋“œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์€ ๊ฒŒ์ดํŠธ์›จ์ด ๊ณ„์ธต์œผ๋กœ๋ถ€ํ„ฐ ์†Œ์œ  ๋„๋ฉ”์ธ ์„œ๋น„์Šค๋กœ ์œ„์ž„ํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Studio Edge ๊ตฌ์กฐ

ํƒ€์ž…์„ ์—ฐํ•ฉํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

image

์ฃผ์š”ํ•œ ๊ตฌ์กฐ์  ์ปดํฌ๋„ŒํŠธ

**Domain Graph Service (DGS)**๋Š” ๋…๋ฆฝ์ ์ด๋ฉฐ ๊ทœ๊ฒฉ์„ ์ค€์ˆ˜ํ•˜๋Š” GraphQL ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” ๊ฐ์ž์˜ ์—ฐํ•ฉ๋œ GrpahQL ์Šคํ‚ค๋งˆ๋ฅผ DGS์—์„œ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. API์˜ ์„ธ๋ถ€ํ•ญ๋ชฉ์„ ๋‹ด๋‹นํ•˜๋Š” ๋„๋ฉ”์ธ ํŒ€์€ DGS๋ฅผ ์†Œ์œ ํ•˜๊ณ  ์šด์˜ํ•ฉ๋‹ˆ๋‹ค. DGS ๊ฐœ๋ฐœ์ž๋Š” ๊ธฐ์กด ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๋ฅผ DGS๋กœ ์ „ํ™˜ํ•  ๊ฒƒ์ธ์ง€ ์•„์˜ˆ ์ƒˆ๋กœ์šด ์„œ๋น„์Šค๋ฅผ ์Šคํ•€์—… ํ•  ๊ฒƒ์ธ์ง€ ์ž์œ ๋กญ๊ฒŒ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

Schema Registry๋Š” ๋ชจ๋“  DGS์— ๋Œ€ํ•ด ๋ชจ๋“  ์Šคํ‚ค๋งˆ์™€ ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ €์žฅํ•˜๋Š” ์ƒํƒœ๊ฐ€ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž ํˆด๊ณผ CI/CD ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์Šคํ‚ค๋งˆ์— ๋Œ€ํ•œ CRUD API๋ฅผ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ณ„์ ์ธ DGS ์Šคํ‚ค๋งˆ์™€ ๊ฒฐํ•ฉ๋œ ์Šคํ‚ค๋งˆ ๋ชจ๋‘์— ๋Œ€ํ•ด ์œ ํšจ์„ฑ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋Š” ํ•˜๋‚˜์˜ ํ†ตํ•ฉ๋œ ์Šคํ‚ค๋งˆ๋ฅผ ๊ตฌ์„ฑํ•˜๋ฉฐ ์ด๋ฅผ ๊ฒŒ์ดํŠธ์›จ์ด์— ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

GraphQL ๊ฒŒ์ดํŠธ์›จ์ด๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ GraphQL ์ฟผ๋ฆฌ๋ฅผ ์ปจ์Šˆ๋จธ์—๊ฒŒ ์ œ๊ณตํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ์ฟผ๋ฆฌ๋ฅผ ๋ฐ›์•„ ์ž‘์€ ์„œ๋ธŒ ์ฟผ๋ฆฌ๋“ค(์ฟผ๋ฆฌํ”Œ๋žœ)๋กœ ์ชผ๊ฐœ๊ณ  ์ ์ ˆํ•œ DGS๋“ค์—๊ฒŒ ํ˜ธ์ถœ์„ ํ”„๋ก์‹ฑํ•˜์—ฌ ์ฟผ๋ฆฌ ํ”Œ๋žœ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ

GrpahQL Federation์„ ๊ฐ•ํ™”ํ•˜๋Š” ์„ธ ๊ฐ€์ง€ ์ฃผ์š”ํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

Schema Composition

Composition์€ ๋ชจ๋“  federated DGS ์Šคํ‚ค๋งˆ๋“ค์„ ๋ฐ›์•„ ํ•˜๋‚˜๋กœ ํ†ตํ•ฉ๋œ ์Šคํ‚ค๋งˆ๋กœ ํ•ฉํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค. ๊ตฌ์„ฑ๋œ ์Šคํ‚ค๋งˆ๋Š” ๊ฒŒ์ดํŠธ์›จ์ด์— ์˜ํ•ด ๊ทธ๋ž˜ํ”„์˜ ์ปจ์Šˆ๋จธ๋“ค์—๊ฒŒ ๋…ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

image

์ƒˆ๋กœ์šด ์Šคํ‚ค๋งˆ๊ฐ€ DGS์— ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค ์Šคํ‚ค๋งˆ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋Š” ๋‹ค์Œ ์‚ฌํ•ญ๋“ค์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

  1. ์ƒˆ๋กœ์šด ์Šคํ‚ค๋งˆ๋Š” ์œ ํšจํ•œ GrpahQL ์Šคํ‚ค๋งˆ์ด๋‹ค.
  2. ์ƒˆ๋กœ์šด ์Šคํ‚ค๋งˆ๊ฐ€ ๋‚˜๋จธ์ง€ DGS ์Šคํ‚ค๋งˆ์™€ ์ž˜ ๊ตฌ์„ฑ๋˜์–ด ์œ ํšจํ•œ ํ•ฉ์„ฑ๋œ ์Šคํ‚ค๋งˆ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
  3. ์ƒˆ๋กœ์šด ์Šคํ‚ค๋งˆ๋Š” ์ด์ „ ๋ฒ„์ „๊ณผ ํ˜ธํ™˜๋œ๋‹ค.

๋งŒ์•ฝ ๋ชจ๋“  ์กฐ๊ฑด์ด ๋งŒ์กฑ๋˜๋ฉด, ๊ทธ ์Šคํ‚ค๋งˆ๋Š” ์Šคํ‚ค๋งˆ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋กœ ์ฒดํฌ์ธ๋ฉ๋‹ˆ๋‹ค.

Query Planning and Execution

federation config๋Š” ๋ชจ๋“  ๊ฐœ๋ณ„์ ์ธ DGS ์Šคํ‚ค๋งˆ์™€ ๊ตฌ์„ฑ๋œ ์Šคํ‚ค๋งˆ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ๊ฒŒ์ดํŠธ์›จ์ด๋Š” ์ฟผ๋ฆฌ ํ”Œ๋žœ์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด federation config์™€ ํด๋ผ์ด์–ธํŠธ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฟผ๋ฆฌ ํ”Œ๋žœ์€ ํด๋ผ์ด์–ธํŠธ ์ฟผ๋ฆฌ๋ฅผ ๋” ์ž‘์€ ์„œ๋ธŒ ์ฟผ๋ฆฌ๋กœ ์ชผ๊ฐ  ๊ฒƒ์ธ๋ฐ ์‹คํ–‰์„ ์œ„ํ•ด DGS๋กœ ๋ณด๋‚ด์ง€๊ณ  ์ˆœ์ฐจ์ ์ธ ์‹คํ–‰ ์ˆœ์„œ์™€ ๋ณ‘๋ ฌ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

image

์œ„์—์„œ ์ฐธ์กฐํ•œ ์Šคํ‚ค๋งˆ๋กœ๋ถ€ํ„ฐ ๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ณ  ์–ด๋–ป๊ฒŒ ์ฟผ๋ฆฌํ”Œ๋žœ์ด ์ƒ์„ฑ๋˜๋Š”์ง€ ๋ด…์‹œ๋‹ค.

image

์ด ์ฟผ๋ฆฌ์—์„œ ๊ฒŒ์ดํŠธ์›จ์ด๋Š” federation config๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜์—ฌ ์–ด๋–ค ํ•„๋“œ๊ฐ€ ์–ด๋–ค DGS์— ์žˆ๋Š”์ง€ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒŒ์ดํŠธ์›จ์ด๋Š” ํด๋ผ์ด์–ธํŠธ ์ฟผ๋ฆฌ๋ฅผ ์„ธ ๊ฐ€์ง€ ๊ฐœ๋ณ„์ ์ธ ์ฟผ๋ฆฌ๋กœ ๋ถ„ํ•ดํ•ฉ๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ์ฟผ๋ฆฌ๋Š” Movie DGS๋กœ ๋ณด๋‚ด์ง€๋Š”๋ฐ ๋ฃจํŠธ ํ•„๋“œ movies๋Š” ํ•ด๋‹น DGS์—์„œ ์†Œ์œ ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋กœ ๋ฐ์ดํ„ฐ์…‹์—์„œ์˜ ์ฒซ 10๊ฐ€์ง€ ์˜ํ™”๋“ค์— ๋Œ€ํ•œ movieId์™€ title์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๊ณ  ๋‚˜์„œ ์ด์ „ ์š”์ฒญ์—์„œ ์–ป์€ movieId๋“ค์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒŒ์ดํŠธ์›จ์ด๋Š” 10๊ฐ€์ง€ ์˜ํ™”์— ๋Œ€ํ•œ production๊ณผ actors ํ•„๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด Prodction DGS์™€ Talent DGS์— ๋‘ ๋ณ‘๋ ฌ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์™„๋ฃŒ๋˜๋ฉด ์„œ๋ธŒ์ฟผ๋ฆฌ์˜ ์‘๋‹ต์€ ํ•˜๋‚˜๋กœ ํ•ฉ์ณ์ ธ ํ˜ธ์ถœ์ž์—๊ฒŒ ๊ฒฐํ•ฉ๋œ ๋ฐ์ดํ„ฐ ์‘๋‹ต์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

์„ฑ๋Šฅ์—์„œ ์ฐธ๊ณ ํ•  ์‚ฌํ•ญ : ์ฟผ๋ฆฌ ํ”Œ๋ž˜๋‹๊ณผ ์‹คํ–‰์€ ์ตœ์•…์˜ ๊ฒฝ์šฐ 1~10ms ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ๋”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ฟผ๋ฆฌ ํ”Œ๋žœ์„ ์ƒ์„ฑํ•˜๊ณ  DGS ์‘๋‹ต์˜ deserialization๊ณผ ํ•ฉ์ณ์ง„ ๊ฒŒ์ดํŠธ์›จ์ด ๊ฒฐ๊ณผ์˜ serialization์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

Entity Resolver

์ด์ œ ์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ์–ด๋–ป๊ฒŒ Prodction๊ณผ Talent DGS์—์„œ ๋ณ‘๋ ฌ์ ์ธ ์„œ๋ธŒ ์ฟผ๋ฆฌ๊ฐ€ ๋™์ž‘ํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•˜์‹ค ๊ฒ๋‹ˆ๋‹ค. DGS๊ฐ€ ์ง€์›ํ•˜๋Š” ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ํผ์ฆ์˜ ๋งˆ์ง€๋ง‰ ์กฐ๊ฐ์ž…๋‹ˆ๋‹ค.

federated ํƒ€์ž…์ธ Movie๋กœ ๋Œ์•„๊ฐ€ ๋ด…์‹œ๋‹ค. ๊ฒŒ์ดํŠธ์›จ์ด๊ฐ€ DGS๋“ค์„ ๋„˜๋‚˜๋“ค๋ฉฐ Movie๋ฅผ ํ•ฉ์น˜๋ ค๋ฉด Movie๋ฅผ ์ •์˜ํ•˜๊ณ  ํ™•์žฅํ•˜๋Š” ๋ชจ๋“  DGS๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ ํ•„๋“œ์— ๋Œ€ํ•ด ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค(e.g. movieId)๋ฅผ ์ •์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ๋™์ž‘์‹œํ‚ค๊ณ ์ž ์•„ํด๋กœ๋Š” @key directive๋ฅผ ๋ช…์„ธ์—์„œ ์†Œ๊ฐœํ–ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ DGS๋“ค์€ ์ผ๋ฐ˜์ ์ธ Query ํ•„๋“œ์ธ _entities์— ๋Œ€ํ•ด ๋ฆฌ์กธ๋ฒ„๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. _entities ์ฟผ๋ฆฌ๋Š” ๋ชจ๋“  federated ํƒ€์ž…๋“ค์— ๋Œ€ํ•œ ํ•˜๋‚˜์˜ ํƒ€์ž…์„ ๋ฐ˜ํ™”ํ•ฉ๋‹ˆ๋‹ค. ๊ฒŒ์ดํŠธ์›จ์ด๋Š” _entities ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ movieId๋กœ Movie๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์ฟผ๋ฆฌํ”Œ๋žœ์ด ์ƒ๊ฒจ๋Š”์ง€ ์‚ดํŽด๋ด…์‹œ๋‹ค.

image

image

ํ‘œํ˜„ ๊ฐ์ฒด๋Š” movieId๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๊ณ  Movie DGS์˜ ์ฒซ ๋ฒˆ์งธ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ฒซ 10๊ฐœ์˜ ์˜ํ™” ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— Prodction๊ณผ Talent DGS์— ๋ณด๋‚ผ 10๊ฐœ์˜ ํ‘œํ˜„ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

์ด๋Š” Realy์˜ ๊ฐ์ฒด ์‹๋ณ„๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ ์•ฝ๊ฐ„์˜ ์ฐจ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. _Entity๋Š” ํ•˜๋‚˜์˜ union ํƒ€์ž…์ด์ง€๋งŒ Relay์˜ Node๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ @key๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณตํ•ฉ ํ‚ค ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ณ€์ˆ˜ ํ‚ค ์ด๋ฆ„๊ณผ ํƒ€์ž…์„ ์ง€์›ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ Relay์—์„œ๋Š” ๋‹จ์ผํ•œ IDํ•„๋“œ์ž…๋‹ˆ๋‹ค.

ํ•จ๊ป˜ ๊ฒฐํ•ฉ๋˜๋ฉด, ์ด๊ฒƒ๋“ค์€ federated API ๊ตฌ์กฐ์˜ ํ•ต์‹ฌ์— ํž˜์„ ์‹ค์–ด์ฃผ๋Š” ์š”์†Œ๋“ค์ž…๋‹ˆ๋‹ค.

์š”์•ฝ

์šฐ๋ฆฌ์˜ ์ŠคํŠœ๋””์˜ค ์ƒํƒœ๊ณ„ ๊ตฌ์กฐ๋Š” ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์–‘๋ฉด์œผ๋กœ ์ง„ํ™”ํ•ด์™”๊ณ , ์•„์ด๋””์–ด์™€ ๊ตฌํ˜„ ์‚ฌ์ด์˜ ์‹œ๊ฐ„์„ ์ค„์ด๋ฉฐ ๊ฐœ๋ฐœ์ž์˜ ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ค๊ณ , ์šด์˜์„ ๊ตญ์†Œํ™”์‹œํ‚ค๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ๋™๊ธฐ๋ถ€์—ฌ๋์Šต๋‹ˆ๋‹ค. ๊ตฌ์กฐ์ ์ธ ๋‹จ๊ณ„๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

image

์ฃผ๋ชฉํ•˜์„ธ์š”

์ง€๋‚œ ๋ช‡๋…„๋™์•ˆ ์šฐ๋ฆฌ๋Š” Studio Edge์—์„œ federated API ๊ตฌ์กฐ ๊ตฌ์„ฑ์š”์†Œ๋“ค์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ๊นŒ์ง€ ๋„๋‹ฌํ•˜๋ ค๋ฉด ๋น ๋ฅธ ๋ฐ˜๋ณต, ๋งŽ์€ ๋ถ€์„œ๊ฐ„์˜ ํ˜‘์—…, ๋ช‡ ๊ฐ€์ง€์˜ ํ”ผ๋ฒ—๊ณผ ์ง€์†์ ์ธ ํˆฌ์ž๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ 70๊ฐ€์ง€์˜ DGS๋ฅผ ๊ฐ€์ง€๋ฉฐ ์ˆ˜๋ฐฑ๋ช…์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ์žˆ๋Š”๋ฐ Studio Edge ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ๋„ทํ”Œ๋ฆญ์Šค ํ…Œํฌ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ „์ฒด์ ์ธ ํ•ด๊ฒฐ์ฑ…์„ ๊ตฌ์ถ•ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ๊ต์ฐจ์ ์ธ ๊ด€์‹ฌ์‚ฌ๋ฅผ ํฌํ•จํ•˜์—ฌ ์šฐ๋ฆฌ๊ฐ€ ๋ฐฐ์šด ๊ฒƒ๋“ค์— ๋Œ€ํ•ด ๊ณต์œ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] NFT ์„ธ๊ณ„์— ์˜ค์‹  ๊ฒƒ์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.

์›๋ฌธ : Welcome to the World of 'NFTs'
๋ถ€์ œ : What are Non Fungible Tokens & Why are they becoming so popular?

๊ฐœ์š”

์ตœ๊ทผ, NFT๋กœ ์ธํ•ด ๋””์ง€ํ„ธ ์ˆ˜์ง‘ํ’ˆ์˜ ์ธ๊ธฐ๊ฐ€ ํญ๋ฐœ์ ์œผ๋กœ ์ฆ๊ฐ€ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ NFT์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ SNS ํ”ผ๋“œ์—์„œ ๋ณด์…จ์„ ๊ฒ๋‹ˆ๋‹ค.
NFT ์‹œ์žฅ์ด ์ปค์ง์— ๋”ฐ๋ผ ์˜ˆ์ˆ , ์Œ์•…, ๊ฒŒ์ž„, ๊ธˆ์œต์‚ฐ์—…์ด ๋’ค์ง‘ํžˆ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. NFT๋ฅผ ์ฒ˜์Œ ๋“ฃ๋Š” ์‚ฌ๋žŒ๋“ค์€ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‹ˆ NFT๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์‚ดํŽด๋ณด๊ณ  ์™œ ๊ฐ‘์ž๊ธฐ ์ธํ„ฐ๋„ท์—์„œ ์ฐจ์„ธ๋Œ€ ์ƒํ’ˆ์ด ๋˜๊ณ  ์žˆ๋Š”์ง€ ์•Œ์•„๋ด…์‹œ๋‹ค.

NFT์— ๋Œ€ํ•ด ์•Œ์•„์•ผ ํ•  ๊ฒƒ๋“ค์„ ๋ชจ๋‘ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿ™‚

NFT๊ฐ€ ๋Œ€์ฒด ๋ฌด์—‡์ธ๊ฐ€์š”?

์•„๋งˆ ์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ํŠธ์œ„ํ„ฐ์˜ ๊ณต๋™ ์„ค๋ฆฝ์ž์ด์ž CEO์ธ Jack Dorsey์˜ ์œ ๋ช…ํ•œ ํŠธ์œ—์„ ์•Œ๊ณ  ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค.
๊ทธ๋Š” ์ž์‹ ์˜ ์ฒซ ๋ฒˆ์งธ ํŠธ์œ—์„ NFT๋กœ ํŒ๋งคํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-01-09 แ„‹แ…ฉแ„’แ…ฎ 10 38 23

์ด ํŠธ์œ—์ด ๋ณด๊ณ ์ž ํ•œ๋‹ค๋ฉด ๋ˆ„๊ตฌ๋‚˜ ๋ฌด๋ฃŒ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ด ๋””์ง€ํ„ธ ์•„์ดํ…œ์ด ๊ณต๊ฐœ์ ์œผ๋กœ ์ด์šฉ์ด ๊ฐ€๋Šฅํ•จ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ , 3์›” 6์ผ ๊ธฐ์ค€์œผ๋กœ ์ด ํŠธ์œ—์— ๋Œ€ํ•ด ๊ฐ€์žฅ ๋†’๊ฒŒ ์ œ์•ˆํ•œ ๊ธˆ์•ก์ด 250๋งŒ ๋‹ฌ๋Ÿฌ๊ฐ€ ๋„˜์—ˆ์Šต๋‹ˆ๋‹ค. ๐Ÿคฏ

์ด ํŠธ์œ—์„ "์‚ฐ๋‹ค๋Š” ๊ฒƒ"์ด ์‹ค์ œ๋กœ ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š” ๊ฑด๊ฐ€์š”?

์—ฌ๋Ÿฌ๋ถ„์ด ๊ตฌ๋งคํ•˜๋Š” ๊ฒƒ์€ ์ด ํŠธ์œ—์˜ ๋””์ง€ํ„ธ ์ฆ๋ช…์„œ ์ธ๋ฐ, ์ƒ์„ฑ์ž์— ์˜ํ•ด ๊ฒ€์ฆ๋˜์—ˆ๊ณ  "์œ ์ผํ•˜๊ฒŒ" ์ด ์šฐ์ฃผ์— ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ๋ถ„์ด ๊ตฌ๋งคํ•˜๋Š” ๊ฒƒ์€ ๊ณ ์œ ํ•œ ์•„์ดํ…œ์ด ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์ •ํ™•ํžˆ NFT๊ฐ€ ๋ฌด์—‡์ธ๊ฐ€์š”?

NFT(Non-Fungible Tokens)๋Š” ๋Œ€์ฒด ๋ถˆ๊ฐ€๋Šฅํ•œ ํ† ํฐ์œผ๋กœ ๋ธ”๋ก์ฒด์ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋ฉฐ ๊ณ ์œ ํ•˜๊ฒŒ ํŠน์ • ๋ฏธ๋””์–ด ์กฐ๊ฐ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ธฐ๋ก์ž…๋‹ˆ๋‹ค.
๋ฏธ๋””์–ด๋Š” ๋””์ง€ํ„ธ๋กœ ๋œ ์–ด๋–ค ๊ฒƒ์ด๋“  ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. "๋Œ€์ฒด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š”" ๊ฒƒ์€ ๊ทธ ์กฐ๊ฐ์ด ๊ณ ์œ ํ•˜๋ฉฐ ์–ด๋– ํ•œ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๋Œ€์ฒด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ์˜ ๋ฒ•์ ์ธ ํ˜„๊ธˆ์€ ๋Œ€์ฒด๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๊ตํ™˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋™์ผํ•œ ๊ฐ€์น˜๋ฅผ ๊ฐ€์ง„ ์–ด๋–ค ๊ฒƒ์œผ๋กœ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์•„์ดํ…œ๋“ค์˜ ์†Œ์œ ๊ถŒ์€ ๋ธ”๋ก์ฒด์ธ์„ ํ†ตํ•ด ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค. NFT๋Š” ์ด๋”๋ฆฌ์›€์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ์•”ํ˜ธํ™”ํ์™€ ๋™์ผํ•œ ๋ธ”๋ก์ฒด์ธ ๋กœ๊ทธ์— ๋ณด๊ด€๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
๋ˆ„๊ตฌ๋‚˜ ๋ณผ ์ˆ˜ ์žˆ๊ณ  ๊ฐํƒ„ํ•  ์ˆ˜ ์žˆ๋Š” ์˜คํ”ˆ ๋งˆ์ผ“์˜ ์œ ๋‹ˆํฌํ•œ ์ˆ˜์ง‘ํ’ˆ๋“ค๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์˜ค์ง ํ•œ ์‚ฌ๋žŒ๋งŒ์ด(๋˜๋Š” ์•”ํ˜ธํ™”ํ ์ง€๊ฐ‘)๋งŒ์ด ์ฃผ์–ด์ง„ ์‹œ๊ฐ„์— ์†Œ์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์™œ NFT๋Š” ์ธ๊ธฐ๊ฐ€ ์ƒ๊ฒผ์„๊นŒ์š”?

NFT๋Š” ์ง€๋‚œ ํ•œ ๋‹ฌ๋™์•ˆ 3์–ต ๋‹ฌ๋Ÿฌ ์ด์ƒ์˜ ๋งค์ถœ์ด ๋ฐœ์ƒํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ตœ๊ทผ ๋งŽ์€ ๊ด€์‹ฌ์„ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ’ฐ ๊ฐ NFT๋Š” ๊ณ ์œ ํ•˜๊ณ  ๋ณต์ œ๋  ์ˆ˜ ์—†์œผ๋ฉฐ ํฌ์†Œ์„ฑ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋™์ผํ•œ ๋””์ง€ํ„ธ ๋ฏธ๋””์–ด๋ฅผ ๋ฌด๋ฃŒ๋กœ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์„ ์ˆœ ์—†๋‚˜์š”?๐Ÿคทโ€โ™‚๏ธ

๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ NFT๋Š” ๋ณต์ œ๋  ์ˆ˜ ์—†๋Š” ๋ฌด์–ธ๊ฐ€๋ฅผ ์—ฌ๋Ÿฌ๋ถ„์—๊ฒŒ ์ฃผ๋„๋ก ์„ค๊ณ„๋ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฑด ๋ฐ”๋กœ ์ž‘์—…๋ฌผ์˜ ์†Œ์œ ๊ถŒ์ž…๋‹ˆ๋‹ค. (๋ฌผ๋ฆฌ์ ์ธ ์˜ˆ์ˆ ์ž‘ํ’ˆ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ์•„ํ‹ฐ์ŠคํŠธ๊ฐ€ ์—ฌ์ „ํžˆ ์ €์ž‘๊ถŒ๊ณผ ์žฌ์ƒ์‚ฐ๊ถŒ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹คํ•ด๋„ ๋ง์ž…๋‹ˆ๋‹ค.) ๋ฌผ๋ฆฌ์ ์ธ ์˜ˆ์ˆ ํ’ˆ ์ˆ˜์ง‘์˜ ๊ด€์ ์—์„œ ๋ณด์ž๋ฉด, ๋ˆ„๊ตฌ๋‚˜ ๋ชจ๋„ค ํŒํ™”๋ฅผ ๊ตฌ๋งคํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์›๋ณธ์€ ํ•œ ์‚ฌ๋žŒ๋งŒ ์†Œ์œ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์ฃ .

๋‹จ์ˆœํžˆ ์ด๋ฏธ์ง€๋‚˜ ๋“œ๋กœ์ž‰์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ธ”๋ก์ฒด์ธ์„ ๋…ํŠนํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋ธ”๋ก์ฒด์ธ์˜ ๋””์ง€ํ„ธ ๊ฐ์ฒด๋กœ์„œ์˜ ์กด์žฌ์ž…๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์•”ํ˜ธํ™”ํ์™€ ๋‹ค๋ฅด๊ฒŒ, NFT๋Š” ์ง์ ‘์ ์œผ๋กœ ๋‹ค๋ฅธ ๊ฒƒ๊ณผ ๊ตํ™˜๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‘ ๊ฐœ์˜ NFT๋Š” ๋™์ผํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
๋‹ค๋ฅธ ์ž์‚ฐ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ์ˆ˜์š”์™€ ๊ณต๊ธ‰์€ ๊ฐ€๊ฒฉ์„ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•œ ์—ด์‡ ์ž…๋‹ˆ๋‹ค. NFT์˜ ํฌ์†Œ์„ฑ์œผ๋กœ ์ธํ•ด ์‚ฌ๋žŒ๋“ค์€ NFT์— ๋งŽ์€ ๋ˆ์„ ์ง€๋ถˆํ•  ์ค€๋น„๊ฐ€ ๋˜์–ด ์žˆ๋Š” ๊ฒ๋‹ˆ๋‹ค.

NFT๊ฐ€ ์ธ๊ธฐ ์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ์ด์œ ๋Š” ์ค‘์•™ํ™”๋œ ์†Œ์…œ ํ”Œ๋žซํผ(ex. ์œ ํŠœ๋ธŒ)์ด ์ฐฝ์ž‘์ž์™€ ํŒฌ๋“ค์„ ์—ฐ๊ฒฐํ•˜๋Š” ์šฐ์„ธํ•œ ๋ฐฉ๋ฒ•์ด ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ตฌ์กฐ์—์„œ ์ฐฝ์ž‘์ž์˜ ๋Œ€๋ถ€๋ถ„ ์ˆ˜์ž…์˜ ์›์ฒœ์€ ๊ด‘๊ณ ์ธ ๊ฒƒ์ด์ฃ . ํ”Œ๋žซํผ์€ ์ฐฝ์ž‘์ž์™€ ์†Œ๋น„์ž ์‚ฌ์ด์— ํ”Œ๋žซํผ ์ž์ฒด์˜ ์ถ”์ฒœ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฝ์ž…ํ•จ์œผ๋กœ์จ ์ž์‹ ๋“ค์˜ ์ˆ˜์ž…์„ ์ง€ํ‚ค๋ฉด์„œ ์ค‘๊ฐœ์ž๊ฐ€ ๋  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค. NFT๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ๋ถ„์€ ์ด๋Ÿฌํ•œ ์ค‘๊ฐœ์ž๋ฅผ ์™„์ „ํžˆ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๊ณ , ์ฐฝ์ž‘์ž์—๊ฒŒ ๊ทผ๋ณธ์ ์œผ๋กœ ๋” ๋‚˜์€ ๊ฒฝ์ œ์„ฑ์„ ์ œ๊ณตํ•˜์—ฌ ๊ณ ๊ฐ ๊ตฌ์ž… ๋น„์šฉ์„ 0์— ๊ฐ€๊น๊ฒŒ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

NFT๋Š” ์–ด๋–ป๊ฒŒ ์‹œ์ž‘ํ•ด์•ผ ํ•˜๋‚˜์š”?

์‚ฌ๋žŒ๋“ค์ด ๋””์ง€ํ„ธ ์ƒํ’ˆ์„ ์‚ฌ๊ณ  ํŒ” ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” NFT ์ค‘์‹ฌ์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ์‹œ์žฅ๋“ค์ด ์—ฌ๋Ÿฟ ์žˆ์Šต๋‹ˆ๋‹ค. MakersPlace.com, SuperRare.co, ๊ทธ๋ฆฌ๊ณ  Rarible.com์€ ๋””์ง€ํ„ธ NFT ์˜ˆ์ˆ ์ž‘ํ’ˆ์— ํŠนํ™”๋œ ์‚ฌ์ดํŠธ๋“ค์ž…๋‹ˆ๋‹ค. Grimes, partner of Elon Musk, mother to X ร† A-12๋Š” "Nfty Gateway"๋ฅผ ํ†ตํ•ด NFT๋ฅผ ํŒ๋งคํ–ˆ์ง€๋งŒ ๋‹ค๋ฅธ ๊ฒƒ๋“ค๋„ ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ€์žฅ ๋น„์‹ผ NFT๋“ค์€? ๐Ÿ’ธ

Dragon the CryptoKitty๋Š” ์ด ์šฐ์ฃผ์—์„œ ๊ฐ€์žฅ ๋น„์‹ผ ๊ฐ€์น˜๋ฅผ ์ง€๋‹Œ NFT ์ค‘ ํ•˜๋‚˜์ธ๋ฐ, ๋Œ€๋žต 600์ด๋”๋ฆฌ์›€์˜ ๊ฐ€์น˜๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
๋†๊ตฌ ์Šคํƒ€ LeBron James์˜ NBA ํƒ‘์ƒท ๋””์ง€ํ„ธ ์ˆ˜์ง‘ ์นด๋“œ๋Š” 10๋งŒ ๋‹ฌ๋Ÿฌ์— ํŒ๋งค๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
NFT ๊ธฐ๋ฐ˜ ๊ฒŒ์ž„์ธ Axie Infinity์˜ Angel์ธ Axie๋Š” 300 ์ด๋”๋ฆฌ์›€์— ํŒ๋งค๋์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

NFT๋Š” ์—ฌ์ „ํžˆ ์•„์ฃผ ์ƒˆ๋กญ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ์‚ฐ์—…์œผ๋กœ์„œ ๊ธฐ์ˆ ๊ฐœ์„ ์„ ์œ„ํ•ด ํ•ด์•ผ ํ•  ์ผ์ด ๋งŽ์Šต๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ ์šฐ๋ฆฌ๊ฐ€ ์ง๋ฉดํ•˜๊ณ  ์žˆ๋Š” ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ๋Š” ๊ต‰์žฅํžˆ ๋งŽ์€ ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•  ์ˆ˜ ์žˆ๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. NFT๋Š” ์•„์ง ์ƒ๋Œ€์ ์œผ๋กœ ๋ฉ”์ธ์ŠคํŠธ๋ฆผ ์‚ฌ์šฉ์ž๋“ค์ด ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š”๋ฐ์š”. ํ˜„์žฌ๋Š” ์–ผ๋ฆฌ์–ด๋‹ตํ„ฐ๋‚˜ ํˆฌ์ž์ž๋งŒ์ด ๋ธ”๋ก์ฒด์ธ ๊ธฐ๋ฐ˜ ํ”Œ๋žซํผ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” NFT์˜ ์ง„์ž…์žฅ๋ฒฝ์„ ๋‚ฎ์ถ”์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๋น„์ค‘์•™ํ™” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๋ณด๋‹ค ์ค‘์•™ํ™”๋œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋” ์‰ฝ๊ฒŒ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์ ๋˜ํ•œ ๊ทน๋ณตํ•ด์•ผ ํ•  ์žฅ์• ๋ฌผ์ด ๋ฉ๋‹ˆ๋‹ค. ์ด ๋˜ํ•œ ์šฐ๋ฆฌ๊ฐ€ ์ ๊ทน์ ์œผ๋กœ ํ•ด๊ฒฐํ•˜๊ณ  ์žˆ๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

[์ •๋ฆฌ] if(kakao) 2021 : Klaytn ๊ด€๋ จ

Klaytn์„ ์ด์šฉํ•˜์—ฌ NFT ํ™œ์šฉํ•˜๊ธฐ : ๋ฐœํ–‰๋ถ€ํ„ฐ ํŒ๋งค๊นŒ์ง€

ํด๋ ˆ์ดํŠผ(Klaytn)

  • ๊ทธ๋ผ์šด๋“œX์—์„œ ๊ฐœ๋ฐœํ•œ ๋ธ”๋ก์ฒด์ธ ํ”Œ๋žซํผ, ์ด๋”๋ฆฌ์›€ ๊ธฐ๋ฐ˜
  • ์„ฑ๋Šฅ ์ธก๋ฉด : ๋งค ๋ธ”๋ก ๋‹น 4000 ํŠธ๋žœ์žญ์…˜, ๋ธ”๋ก์ƒ์„ฑ์‹œ๊ฐ„ 1์ดˆ
  • BFT ์ปจ์„ผ์„œ์Šค ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋„์ž…
  • ์ €๋ ดํ•œ ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ˆ˜๋ฃŒ

ํ† ํฐ ํ‘œ์ค€์ด ํ•„์š”ํ•œ ์ด์œ 

ํด๋ ˆ์ดํŠผ ๊ณ„์ • ์ฒด๊ณ„

  • ํด๋ ˆ์ดํŠผ ์ƒ์—์„œ ๋‹ค์–‘ํ•œ ๊ณ„์ •์ด ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ์Œ, ์‚ฌ์šฉ์ž ๊ณ„์ •์ผ ์ˆ˜๋„ ์žˆ๊ณ  ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ๊ณ„์ •์ผ ์ˆ˜๋„ ์žˆ์Œ
  • ํ† ํฐ ํ‘œ์ค€์ด ์กด์žฌํ•จ์œผ๋กœ์จ ์‰ฝ๊ฒŒ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•จ. ๋ˆ„๊ตฌ๋‚˜ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ...
  • NFT -> KIP-17, KIP-37

NFT ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค

  • ๋ฐœํ–‰ ์ „์†ก ํŒ๋งค ์ „์‹œ
  • ๋ฐœํ–‰-์ „์†ก : KIP-17 ํ•จ์ˆ˜ ์‚ฌ์šฉ
  • ํŒ๋งค : ํŒ๋งค์ž์™€ ๊ตฌ๋งค์ž๊ฐ€ ์›ํ•˜๋Š” ๊ฐ€๊ฒฉ์œผ๋กœ ๋งค๋งคํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ• (์ถ”๊ฐ€์ ์ธ ์„œ๋น„์Šค ๋ ˆ์ด์–ด ๊ธฐ๋Šฅ ํ•„์š”)
  • ์ „์‹œ : NFT ์ •๋ณด์˜ ํšจ์œจ์  ๊ฒ€์ƒ‰, ๋‚˜์˜ NFT ์ „์‹œ ๋“ฑ

NFT ๋งˆ์ผ“ํ”Œ๋ ˆ์ด์Šค ์š”๊ตฌ์‚ฌํ•ญ

  • ์ถ”๊ธ‰๊ถŒ : ์ตœ์ดˆ ์–‘๋„ ์ดํ›„ ์žฌํŒ๋งค๋  ๋•Œ๋งˆ๋‹ค ์ˆ˜์ต์˜ ์ผ์ •๋ถ€๋ถ„ ๋ถ„๋ฐฐ, ํŒ๋งค ์ฆ‰์‹œ ์ถ”๊ธ‰๊ถŒ ์ ์šฉ
  • ํŒ๋งค ๋ฐฉ์‹ : ๊ณ ์ •๊ฐ€, ๊ฒฝ๋งค
  • ๊ฒฐ์ œ ์ˆ˜๋‹จ : KIP-7, KLAY
  • ํ™˜๋ถˆ : ๊ตฌ๋งค ํ›„ ์ผ์ฃผ์ผ๊ฐ„ ํ™˜๋ถˆ๊ธฐ๋Šฅ ์ œ๊ณต

์ถ”๊ธ‰๊ถŒ

  • ๋Œ€๋ถ€๋ถ„์˜ NFT ๋งˆ์ผ“ํ”Œ๋ ˆ์ด์Šค์—์„œ ์ œ๊ณต
  • ํ‘œ์ค€ํ™” ๋˜์–ด ์žˆ์ง€๋Š” ์•Š์Œ (ํ˜ธํ™˜์„ฑX)
  • ์ด๋”๋ฆฌ์›€ 2021.07.25 ๋กœ์—ดํ‹ฐ์— ๋Œ€ํ•œ ํ‘œ์ค€ํ™” ์ •๋ฆฝ ์ง„ํ–‰ (ํด๋ ˆ์ดํŠผ์—์„œ๋„ ํ•ด๋‹น ํ‘œ์ค€์— ๋Œ€ํ•œ ์ •๋ฆฝ ํ•„์š”)

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-01-15 แ„‹แ…ฉแ„’แ…ฎ 9 23 55

๋‹ค์ˆ˜์˜ ์ถ”๊ธ‰๊ถŒ์ž๋Š” ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ๊ณ ๋ ค ๋ถ€์กฑ

์ถ”๊ธ‰๊ถŒ ์กฐํšŒ

  • RoyaltyRouter : ๋ชจ๋“  ์ถ”๊ธ‰๊ถŒ์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ์ปจํŠธ๋ž™ํŠธ, ์ถ”๊ธ‰๊ถŒ ์กฐํšŒ๋ฅผ ์œ„ํ•ด ์ด ์ปจํŠธ๋ž™ํŠธ๋งŒ ์•Œ๋ฉด ๋จ

NFT ๋งˆ์ผ“ํ”Œ๋ ˆ์ด์Šค ์„ค๊ณ„/๊ตฌํ˜„

  • ๊ณ ์ •๊ฐ’์ผ ๋•Œ FixedPriceExchange > ํ™˜๋ถˆ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ Escrow ์ปจํŠธ๋ž™ํŠธ ํ•„์š”

NFT ๋ฐœํ–‰

  1. minter(== ์ž‘๊ฐ€)๋Š” ์„œ๋ฒ„์—๊ฒŒ ํ† ํฐ์— ํ•ด๋‹นํ•˜๋Š” ๋ฏธ๋””์–ด, ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ, RoyaltyInfo๋ฅผ ์ œ๊ณต
  2. ์„œ๋ฒ„๋Š” KIP-17 ์ปจํŠธ๋ž™ํŠธ์™€ ๋กœ์—ดํ‹ฐ์ธํฌ ์ปจํŠธ๋ž™ํŠธ์— ํ•„์š”ํ•œ ํ•จ์ˆ˜ ํ˜ธ์ถœ -> ์ƒˆ๋กœ์šด NFT ๋ฐœํ–‰

NFT ํŒ๋งค ๋“ฑ๋ก (KIP-7)

  1. ํŒ๋งค๋“ฑ๋ก์„ ํ•˜๊ธฐ ์ „์— ํ•ด๋‹น ํ† ํฐ์˜ ์ „์†ก ๊ถŒํ•œ์„ exchange contract์— ๋ถ€์—ฌ (approve)
  2. ํŒ๋งค ๋“ฑ๋ก (๊ฐ€๊ฒฉ๊ณผ ์ฃผ์†Œ ์ „๋‹ฌ)

NFT ๊ตฌ๋งค

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-01-15 แ„‹แ…ฉแ„’แ…ฎ 9 38 35

  1. ๊ตฌ๋งค์ž๊ฐ€ KIP-7์œผ๋กœ transfer ํ•จ์ˆ˜ ํ˜ธ์ถœ (ํŒ๋งค ๋Œ€๊ธˆ ์ „์†ก)
  2. Received ํ•จ์ˆ˜ ํ˜ธ์ถœ
  3. ๋กœ์—ดํ‹ฐ ๋ผ์šฐํ„ฐ๋ฅผ ํ†ตํ•ด ์ถ”๊ธ‰๊ถŒ ์ •๋ณด๋ฅผ ์–ป์–ด์˜ด
  4. ์ด ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ •์‚ฐ ์ •๋ณด๋ฅผ escrow์— ์ „๋‹ฌ
  5. exchange ์ปจํŠธ๋ž™ํŠธ๋Š” ํŒ๋งค์ž๋กœ๋ถ€ํ„ฐ ๊ตฌ๋งค์ž์—๊ฒŒ ํ•ด๋‹น NFT ์ „์†ก
  6. ํŒ๋งค๋Œ€๊ธˆ์ด ์•„์ง escrow์— ์˜ˆ์น˜๋œ ์ƒํƒœ์ด๊ณ  ์ผ์ • ์‹œ๊ฐ„ ํ›„์— transfer๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉฐ ์ •์‚ฐ ์ง„ํ–‰

[๋ฒˆ์—ญ] React์—์„œ BLoC ํŒจํ„ด ์‚ฌ์šฉํ•˜๊ธฐ

2021๋…„ 7์›” 28์ผ์— ์ž‘์„ฑ๋œ Using BLoC Pattern with React์„ ์ฝ๊ณ  ๋ฒˆ์—ญํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

์ฒ˜์Œ์— BLoC(Business Logic Component) ํŒจํ„ด์€ ๊ตฌ๊ธ€์ด ํ”Œ๋Ÿฌํ„ฐ ์•ฑ์—์„œ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์†Œ๊ฐœํ–ˆ์Šต๋‹ˆ๋‹ค.
์ด ํŒจํ„ด์€ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋ถ„๋ฆฌํ•จ์œผ๋กœ์จ UI ์ปดํฌ๋„ŒํŠธ์˜ ์›Œํฌ๋กœ๋“œ๋ฅผ ์ค„์—ฌ์ค๋‹ˆ๋‹ค.

์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉฐ ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ ๋˜ํ•œ BLoC ํŒจํ„ด์„ ์ง€์›ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ์ด ๊ธ€์—์„œ๋Š” ๋ฆฌ์•กํŠธ์—์„œ BLoC ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ ํ•ด๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ์—์„œ BLoC ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ์–ป๋Š” ์žฅ์ 

BLoC ํŒจํ„ด ๋’ค์— ์žˆ๋Š” ๊ฐœ๋…์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์œ„์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด UI ์ปดํฌ๋„ŒํŠธ์—์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
๋จผ์ € ์˜ต์ €๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ BLoC์— ์ด๋ฒคํŠธ๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ๊ทธ ํ›„ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋ฉด UI ์ปดํฌ๋„ŒํŠธ๋“ค์€ BLoC์˜ ์˜ต์ €๋ฒ„๋ธ”์„ ํ†ตํ•ด ์•Œ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ž, ์ด ์ ‘๊ทผ๋ฒ•์„ ์‚ฌ์šฉํ•  ๋•Œ์˜ ์žฅ์ ์„ ์ž์„ธํ•˜๊ฒŒ ์‚ดํŽด๋ด…์‹œ๋‹ค.

1. ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์œ ์—ฐํ•จ

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด UI ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ๋…๋ฆฝ์ ์ผ ๋•Œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๊ฐ€ํ•ด์ง€๋Š” ์˜ํ–ฅ๋„ ์ž‘์•„์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
UI ์ปดํฌ๋„ŒํŠธ์— ์–ด๋– ํ•œ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

2. ๋กœ์ง์˜ ์žฌ์‚ฌ์šฉ

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ํ•œ ๊ตฐ๋ฐ์— ์žˆ๋‹ค๋ฉด, UI ์ปดํฌ๋„ŒํŠธ๋Š” ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ ์—†์ด ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ์•ฑ์˜ ๋‹จ์ˆœํ•จ์„ ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค.

3. ํ…Œ์ŠคํŠธ๊ฐ€ ์‰ฌ์›Œ์ง

ํ…Œ์ŠคํŠธ์ผ€์ด์Šค๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๊ฐœ๋ฐœ์ž๋“ค์€ BLoC ์ž์ฒด์—๋งŒ ์ง‘์ค‘ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฒ ์ด์Šค๊ฐ€ ์ง€์ €๋ถ„ํ•ด์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

4. ํ™•์žฅ์„ฑ

์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉฐ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์š”๊ตฌ์‚ฌํ•ญ์€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๊ณ  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋„ ์ปค์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
์ด๋Ÿฐ ์ƒํ™ฉ์—์„œ ์ฝ”๋“œ๋ฒ ์ด์Šค์˜ ๋ช…๋ฃŒํ•จ์„ ์œ ์ง€ํ•˜๊ณ ์ž ๊ฐœ๋ฐœ์ž๋“ค์€ ์—ฌ๋Ÿฌ BLoC๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒŒ๋‹ค๊ฐ€ BLoC ํŒจํ„ด์€ ํ”Œ๋žซํผ์ด๋‚˜ ํ™˜๊ฒฝ์— ์ข…์†๋˜์ง€ ์•Š์•„ ๊ฐœ๋ฐœ์ž๋“ค์€ ๋‹ค์–‘ํ•œ ํ”„๋กœ์ ํŠธ์—์„œ ๋™์ผํ•œ BLoC ํŒจํ„ด์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ๋…์—์„œ ์‹ค์ „์œผ๋กœ

BLoC ํŒจํ„ด์˜ ์‚ฌ์šฉ์„ฑ์„ ์ž…์ฆํ•˜๊ณ ์ž ์ž‘์€ ์นด์šดํ„ฐ ์•ฑ์„ ๋งŒ๋“ค์–ด๋ด…์‹œ๋‹ค.

1๋‹จ๊ณ„ : ๋ฆฌ์•กํŠธ ์•ฑ์„ ์ƒ์„ฑํ•˜๊ณ  ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋จผ์ € ๋ฆฌ์•กํŠธ ์•ฑ์„ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ €๋Š” ์ด ์•ฑ์„ bloc-counter-app์ด๋ผ ์ด๋ฆ„ ์ง“๊ฒ ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ rxjs๋„ ์‚ฌ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

// Create React app
npx create-react-app bloc-counter-app
// Install rxjs
yarn add rxjs

๊ทธ ํ›„ ํ•„์š”์—†๋Š” ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ์ง€์šฐ๊ณ  ์•„๋ž˜ ๋ชฉ๋ก์— ๋”ฐ๋ผ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

  • Blocs - ํ•„์š”ํ•œ bloc ํด๋ž˜์Šค ์ €์žฅ
  • Components - UI ์ปดํฌ๋„ŒํŠธ ์ €์žฅ
  • Utils - ํ”„๋กœ์ ํŠธ์˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํŒŒ์ผ ์ €์žฅ

2๋‹จ๊ณ„ : BLoC๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค

์ด์ œ BLoC ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•ด๋ด…์‹œ๋‹ค. BLoC ํด๋ž˜์Šค๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  subject๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
์ด ์˜ˆ์‹œ์—์„œ๋Š” ์นด์šดํ„ฐ ๋กœ์ง์— ๋Œ€ํ•œ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜์ฃ .

bloc ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์— CounterBloc.js๋ผ๋Š” ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  pipe๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ UI ์ปดํฌ๋„ŒํŠธ์— ์นด์šดํ„ฐ๋ฅผ ์ „๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

import { Subject } from 'rxjs';
import { scan } from 'rxjs/operators';

export default class CounterBloc {
  constructor() {
    this._subject = new Subject();
  }

  get counter() {
    return this._subject.pipe(scan((count, v) => count + v, 0));
  }

  increase() {
    this._subject.next(1);
  }

  decrease() {
    this._subject.next(-1);
  }

  dispose() {
    this._subject.complete();
  }
}

ํด๋ž˜์Šค์—๋Š” ๊ฐ„๋‹จํ•œ ๋กœ์ง๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์•ฑ์˜ ์‚ฌ์ด์ฆˆ๊ฐ€ ์ปค์กŒ๋Š”๋ฐ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋ถ„๋ฆฌํ•˜์ง€ ์•Š์•˜์„ ๋•Œ ์–ผ๋งˆ๋‚˜ ๋ณต์žกํ• ์ง€ ์ƒ์ƒํ•ด๋ณด์„ธ์š”.

3๋‹จ๊ณ„ : ์ค‘๊ฐ„ ํด๋ž˜์Šค๋กœ BLoC์— ์•„๋ฆ„๋‹ค์›€์„ ๋”ํ•˜์„ธ์š”.

์ด ๋‹จ๊ณ„์—์„œ UI๋กœ๋ถ€ํ„ฐ ์˜ค๋Š” ์นด์šดํ„ฐ ์š”์ฒญ์„ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด utils ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์— StreamBuilder.js ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
๊ฒŒ๋‹ค๊ฐ€ ๊ฐœ๋ฐœ์ž๋“ค์€ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  customer ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

class AsyncSnapshot {
  constructor(data, error) {
    this._data = data;
    this._error = error;
    this._hasData = data ? true : false;
    this._hasError = error ? true : false;
  }

  get data() {
    return this._data;
  }

  get error() {
    return this._error;
  }

  get hasData() {
    return this._hasData;
  }

  get hasError() {
    return this._hasError;
  }
}

AsyncSnapshot ํด๋ž˜์Šค ๋‚ด์—์„œ ์ƒ์„ฑ์ž๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๊ณ , ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ์ด ์˜ˆ์ œ์—์„œ๋Š” ์„ค๋ช…์„ ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ๋‹จ์ˆœํžˆ ๋ฐ์ดํ„ฐ๋งŒ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

class StreamBuilder extends Component {
  constructor(props) {
    super(props);

    const { initialData, stream } = props;

    this.state = {
      snapshot: new AsyncSnapshot(initialData),
    };

    stream.subscribe(
      data => {
        this.setState({
          snapshot: new AsyncSnapshot(data, null),
        });
      }
    );
  }

  render() {
    return this.props.builder(this.state.snapshot);
  }
}

์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋Š” AysncSnapshot์— ์ „๋‹ฌ๋˜์–ด ๊ฐ ๊ตฌ๋…๋งˆ๋‹ค ์Šค๋ƒ…์ƒท ์ƒํƒœ ๋‚ด์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
๊ทธ ํ›„ UI ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ๋ Œ๋”๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

import { Component } from 'react';

class AsyncSnapshot {
  constructor(data) {
    this._data = data;
  }
  get data() {
    return this._data;
  }
}

class StreamBuilder extends Component {
  constructor(props) {
    super(props);

    const { initialData, stream } = props;

    this.state = {
      snapshot: new AsyncSnapshot(initialData),
    };

    stream.subscribe(
      data => {
        this.setState({
          snapshot: new AsyncSnapshot(data, null),
        });
      }
    );
  }

  render() {
    return this.props.builder(this.state.snapshot);
  }
}

export default StreamBuilder;

์ฃผ์˜ : UI ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ธ๋งˆ์šดํŠธ ๋  ๋•Œ ๋ชจ๋“  ์˜ต์ €๋ฒ„๋ธ”๋กœ๋ถ€ํ„ฐ ๊ตฌ๋…์„ ํ•ด์ œํ•˜๊ณ  BLoC๋ฅผ ํ๊ธฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

4๋‹จ๊ณ„ : UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค

increase()์™€ decrease() ๋ฉ”์†Œ๋“œ๋“ค์€ UI ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ๋ฐ”๋กœ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ถœ๋ ฅ ๋ฐ์ดํ„ฐ๋Š” stream builder์— ์˜ํ•ด ๋‹ค๋ค„์ง‘๋‹ˆ๋‹ค.

์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ปค์Šคํ…€ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์ค‘๊ฐ„ ์ธต์„ ๋‘๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

import { Fragment } from 'react';

import StreamBuilder from '../utils/StreamBuilder';

const Counter = ({ bloc }) => (
    <Fragment>
        <button onClick={() => bloc.increase()}>+</button>
        <button onClick={() => bloc.decrease()}>-</button>
        <lable size="large" color="olive">
            Count:
            <StreamBuilder
                initialData={0}
                stream={bloc.counter}
                builder={snapshot => <p>{snapshot.data}</p>}
            />
        </lable>
    </Fragment>
);

export default Counter;

app.js ํŒŒ์ผ์—์„œ BLoC๋Š” CounterBloc ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ Counter ์ปดํฌ๋„ŒํŠธ๋Š” BLoC๋ฅผ prop์œผ๋กœ ์ „๋‹ฌํ•˜์—ฌ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

// App.js
import React, { Component } from 'react';
import Counter from './components/Counter';
import CounterBloc from './blocs/CounterBloc';

const bloc = new CounterBloc();

class App extends Component {
  componentWillUnmount() {
    bloc.dispose();
  }
  render() {
    return (
      <div>
        <Counter bloc={bloc} />
      </div>
    );
  }
}
export default App;

์ด๊ฒƒ์ด ์ „๋ถ€์ž…๋‹ˆ๋‹ค. ์ด์ œ ์—ฌ๋Ÿฌ๋ถ„์€ UI ์ปดํฌ๋„ŒํŠธ ๋ฐ–์—์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋ถ„๋ฆฌ๋œ ์—”ํ„ฐํ‹ฐ๋กœ์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ  ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ์˜ˆ์ œ ์•ฑ์„ ์‚ฌ์šฉํ•˜๊ณ  ๊ฐœ์„ ์‹œํ‚ค๊ณ  ์‹ถ๋‹ค๋ฉด ํ”„๋กœ์ ํŠธ ์ €์žฅ์†Œ๋ฅผ ์ฐธ์กฐํ•˜์‹œ๊ณ  PR์„ ๋‚ ๋ ค์ฃผ์„ธ์š”. ๐Ÿ˜ƒ

์ •๋ฆฌ

์ œ ๊ฒฝํ—˜์— ๋น„์ถ”์–ด ๋ณด๋ฉด, BLoC ํŒจํ„ด์€ ์ž‘์€ ๊ทœ๋ชจ์˜ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์˜คํžˆ๋ ค ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก BLoC ํŒจํ„ด์€ ๋ชจ๋“ˆํ™”๋œ ์•ฑ์„ ๋งŒ๋“œ๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ rxjs์— ๋Œ€ํ•œ ๊ธฐ๋ณธ์ ์ธ ์ดํ•ด์™€ ์–ด๋–ป๊ฒŒ ์˜ต์ €๋ฒ„๋ธ”์ด BLoC ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๋Š”์ง€๋ฅผ ์•„๋Š” ๊ฒƒ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ €๋Š” ์—ฌ๋Ÿฌ๋ถ„์—๊ฒŒ BLoC ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋„๋ก ์ดˆ๋Œ€ํ–ˆ์œผ๋‹ˆ ๋Œ“๊ธ€์—์„œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๊ณต์œ ํ•ด์ฃผ์„ธ์š”.
์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค !!!

Bit์„ ์‚ฌ์šฉํ•˜์—ฌ ๋…๋ฆฝ์ ์ธ JS ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ณต์œ ํ•˜์„ธ์š”

**Bit**์€ ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘์„ฑ๋˜๊ณ  ๋ฒ„์ „ ๊ด€๋ฆฌ๋˜๋ฉฐ ์œ ์ง€๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์™„์ „ํžˆ ๋ชจ๋“ˆํ™”๋œ ์•ฑ์„ ์ƒ์„ฑํ•˜๋„๋ก ํ•˜๋Š” ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ํˆด์ž…๋‹ˆ๋‹ค.
๋ชจ๋“ˆ๋Ÿฌ ์•ฑ๊ณผ ๋””์ž์ธ ์‹œ์Šคํ…œ์„ ์„ค๊ณ„ํ•˜๊ฑฐ๋‚˜ ๋งˆ์ดํฌ๋กœ ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์ œ๊ณตํ•˜๊ฑฐ๋‚˜ ์•ฑ ์‚ฌ์ด์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ณต์œ ํ•  ๋•Œ ์‚ฌ์šฉํ•ด๋ณด์„ธ์š”.

[๋ฒˆ์—ญ] useEffect ๋ฌดํ•œ๋ฃจํ”„ ํŒจํ„ด 5๊ฐ€์ง€

2021๋…„ 7์›” 23์ผ์— ์ž‘์„ฑ๋œ 5 useEffect Infinite Loop Patterns์„ ์ฝ๊ณ  ๋ฒˆ์—ญํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ, ๋ฌดํ•œ๋ฃจํ”„๋Š” ๋‚˜์œ ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค. ์ผ๋ถ€ ์—ฃ์ง€์ผ€์ด์Šค์—์„œ๋Š” ๋ฌดํ•œ๋ฃจํ”„ ๋ง๊ณ  ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•  ์ˆ˜ ์—†์„ ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
React์˜ ๋ฌดํ•œ๋ฃจํ”„ ํŒจํ„ด์„ ์•Œ๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋ฌดํ•œ๋ฃจํ”„๊ฐ€ ์ค‘๋‹จ ์—†์ด ์ž‘๋™๋  ๋•Œ, ํŠนํžˆ ๋ธŒ๋ผ์šฐ์ €๋Š” ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๊ฐ€ ๋Œ์•„๊ฐ€๋Š” ํƒญ์„ ์ฃฝ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‹ˆ ์ค‘๋‹จ์  ์—†์ด Infinite Loop๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”.

useEffect

useEffect๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. React 16๋ฒ„์ „์—์„œ ์†Œ๊ฐœ๋˜์—ˆ์„ ๋•Œ ๋‹ค๋ฅธ ๊ฒƒ๋ณด๋‹ค ๋” ๋งŽ์ด ์ธ๊ธฐ๋ฅผ ๋Œ์—ˆ๋Š”๋ฐ์š”. ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฉ”์†Œ๋“œ์ธ componentDidMount, componentDidUpdate, componentWillUnmount๋ฅผ ๊ฒฐํ•ฉํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด์ฃ .

useEffect๋Š” ์˜์กด์„ฑ์— ์†ํ•œ ๊ฐ’๋“ค์ด ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ๋งŒ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ณ€๊ฒฝ์„ ์ฒดํฌํ•  ๋•Œ๋Š” ์–•์€ ๋น„๊ต๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
์—ฌ๋Ÿฌ๋ถ„์€ ์•„๋งˆ useEffect๋ฅผ ์•„์ฃผ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๋กœ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๊ณ  ์‹ค์ œ๋กœ๋„ ๊ทธ๋ ‡๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์—ฌ๋Ÿฌ๋ถ„์ด ์ œ๋Œ€๋กœ ๋‹ค๋ฃจ์ง€ ๋ชปํ•˜๋ฉด ์—ฌ๋Ÿฌ๋ถ„์„ ํŒŒ๊ดดํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜์กด์„ฑ ์—†์ด

์˜์กด์„ฑ ์—†๋Š” useEffect๋Š” ๋‚˜์œ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ณ ๋ ค๋˜๋‹ˆ ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ์ง€์–‘ํ•˜์„ธ์š”.
๋‹ค์Œ ์ฝ”๋“œ์—์„œ useEffect๋Š” API๋ฅผ ํ‰์ƒ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

useEffect(() => {
  fetch("/api/user")
    .then((res) => res.json)
    .then((res) => {
      setData(res);
    });
});

๋ฌด์Šจ ์ผ์ด ๋ฐœ์ƒํ•˜๋‚˜์š”?

๋””ํŽœ๋˜์‹œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ useEffect๊ฐ€ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์—ฌ๊ธฐ์—์„œ ๋ฌดํ•œ๋ฃจํ”„๋ฅผ ๋งŒ๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๋ฌด์—‡๋„ ์•„๋‹ŒReact์˜ ์ขŒ์šฐ๋ช… "state๋‚˜ props๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ๋ Œ๋”๋ง๋œ๋‹ค"๋ฅผ ํ•ญ์ƒ ๊ธฐ์–ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ด ์ฝ”๋“œ์—์„œ ๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ์ด ์„ฑ๊ณตํ–ˆ์„ ๋•Œ setData๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ ๊ฐ’์„ ์„ค์ •ํ•˜๋Š”๋ฐ ์ด๋Š” ์ปดํฌ๋„ŒํŠธ ๋ฆฌ๋ Œ๋”๋ง์„ ์•ผ๊ธฐ์‹œํ‚ต๋‹ˆ๋‹ค.
useEffect๋Š” ๋น„๊ตํ•  ๊ฐ’์ด ์—†์œผ๋ฏ€๋กœ ๋˜ ๋‹ค์‹œ ์ฝœ๋ฐฑ์„ ํ˜ธ์ถœํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ fetch๋Š” setData๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  setData๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ๋ Œ๋”๋ง๋˜๋Š”๋ฐ ์ด๊ฒƒ์ด ๋ฐ˜๋ณต๋ฉ๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋‚˜์š”?

๋นˆ ๋ฐฐ์—ด๋กœ ์˜์กด์„ฑ์„ ๊ตฌ์ฒดํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

useEffect(() => {
  fetch("/api/user")
    .then((res) => res.json)
    .then((res) => {
      setData(res);
    });
}, []); // <- dependencies

๊ณต์‹ ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด ๋””ํŽœ๋˜์‹œ๋ฅผ ์ƒ๋žตํ•˜๋Š” ๊ฒƒ์€ ์•ˆ์ „ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜์กด๊ฐ’์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ํ•จ์ˆ˜

useEffect๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•  ๋•Œ ์–•์€ ๋น„๊ต๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์กฐ๊ฑด๋ถ€ ์‹œ์Šคํ…œ ๋•Œ๋ฌธ์ด์ฃ . ๐Ÿ˜ˆ

var mark1 = function(){ return ('100')}; // has a unique object reference
var mark2 = function(){ return('100')}; // has a unique object reference
mark1 == mark2; // false
mark1 === mark2; // false

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋ณด์‹œ์ฃ .

import React, { useCallback, useEffect, useState } from "react";
export default function App() {
  const [count, setCount] = useState(0);
  const getData = () => {
    return window.localStorage.getItem("token");
  }; 
  const [dep, setDep] = useState(getData());
  useEffect(() => {
    setCount(count + 1);
  }, [getData]);
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <button onClick={() => setCount(count + 1)}>{count}</button>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

ํ•จ์ˆ˜ getData๊ฐ€ ์˜์กด์„ฑ ๊ฐ’์œผ๋กœ ์ „๋‹ฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ฌดํ•œ๋ฃจํ”„๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค๋Š” Maximum update depth exceeded ์—๋Ÿฌ๋ฅผ ๋ฑ‰์„ ๊ฒ๋‹ˆ๋‹ค.

๋ฌด์Šจ ์ผ์ด ๋ฐœ์ƒํ–ˆ๋‚˜์š”?

useEffect๋Š” ์–•์€ ๋น„๊ต๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์–•์€ ๋น„๊ต๋Š” ์–ธ์ œ๋‚˜ false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ์ˆ˜์ •ํ•˜๋‚˜์š”?

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” useCallback์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
useCallback์€ ์ฝœ๋ฐฑ์˜ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ๋ฒ„์ „์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ๋””ํŽœ๋˜์‹œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ๋งŒ ๋ณ€๊ฒฝ๋˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

const getData = useCallback(() => {
    return window.localStorage.getItem("token");
  }, []); // <- dependencies

์˜์กด๊ฐ’์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋ฐฐ์—ด

๋‘ ๋ฐฐ์—ด์˜ ์–•์€ ๋น„๊ต๋Š” ์–ธ์ œ๋‚˜ false๋ฅผ ๋ฆฌํ„ดํ•˜๋ฏ€๋กœ ๋ฐฐ์—ด์„ ์˜์กด๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ฌดํ•œ๋ฃจํ”„๋ฅผ ๋งŒ๋“ค์–ด ๋ƒ…๋‹ˆ๋‹ค.
๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋ณด์‹œ์ฃ .

import React, { useCallback, useEffect, useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
  const dep = ['a'];
  const [value, setValue] = useState(['b']);
  useEffect(() => {
    setValue(['c']);
  }, [dep]);
  
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <button onClick={() => setCount(count + 1)}>{count}</button>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

์—ฌ๊ธฐ useEffect์˜ ๋””ํŽœ๋˜์‹œ๋กœ dep์ด ์ „๋‹ฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์€ ์—๋Ÿฌ๋ฅผ ๋˜์ง‘๋‹ˆ๋‹ค.

๋ฌด์Šจ ์ผ์ด ๋ฐœ์ƒํ•˜๊ณ  ์žˆ๋‚˜์š”?

๋‘ ๋ฐฐ์—ด์— ๋Œ€ํ•œ ์–•์€ ๋น„๊ต๋Š” ์–ธ์ œ๋‚˜ false์ด๋ฏ€๋กœ useEffect๋Š” ์–ธ์ œ๋‚˜ ์ฝœ๋ฐฑ์„ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ์ˆ˜์ •ํ•˜๋‚˜์š”?

useCallback์€ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด? ์šฐ๋ฆฌ๋Š” useRef๋ผ๋Š” ๋‹ค๋ฅธ ํ›…์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

useRef์€ ์ดˆ๊ธฐ๊ฐ’์„ ๊ฐ€์ง€๋Š” .current๊ณผ ํ•จ๊ป˜ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

import React, { useEffect, useState, useRef } from 'react';
export default function Home() {
  const [value, setValue] = useState(['b']);
  const {current:a} = useRef(['a'])
  useEffect(() => {
    setValue(['c']);
  }, [a])
}

์˜์กด๊ฐ’์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ์ฒด

๋‘ ๊ฐ์ฒด์˜ ์–•์€ ๋น„๊ต๋Š” ์–ธ์ œ๋‚˜ false์ด๋ฏ€๋กœ ๋‹น์—ฐํ•˜๊ฒŒ useEffect๋Š” ์ฝœ๋ฐฑ์„ ๊ณ„์† ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

import React, { useCallback, useEffect, useState } from "react";
export default function App() {
  const [count, setCount] = useState(0);
  const data = {
    is_fetched:false
  };
  useEffect(() => {
    setCount(count + 1);
  }, [data]);
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <button onClick={() => setCount(count + 1)}>{count}</button>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

data๋Š” useEffect์˜ ๋””ํŽœ๋˜์‹œ๋กœ ์ „๋‹ฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์—์„œ ๋ฌดํ•œ๋ฃจํ”„ ์—๋Ÿฌ๋ฅผ ๋ฑ‰์Šต๋‹ˆ๋‹ค.

๋ฌด์Šจ ์ผ์ด ๋ฐœ์ƒํ•˜๊ณ  ์žˆ๋‚˜์š”?

๋‘ ๊ฐ์ฒด์˜ ์–•์€ ๋น„๊ต๋Š” ์–ธ์ œ๋‚˜ false์ด๋ฏ€๋กœ useEffect์˜ ์ฝœ๋ฐฑ์„ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜์ฃ .

์–ด๋–ป๊ฒŒ ์ˆ˜์ •ํ•˜๋‚˜์š”?

๋””ํŽœ๋˜์‹œ๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜๊ฒŒ ๋˜๋ฉด ๋ฌดํ•œ๋ฃจํ”„๋ฅผ ์ค‘๋‹จ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”?
๋„ค, ๋˜ ๋‹ค๋ฅธ ํ›…์ธ useMemo๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

useMemo๋Š” ๋””ํŽœ๋˜์‹œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ๋งŒ ๊ธฐ์–ต๋œ ๊ฐ’์„ ์žฌ์—ฐ์‚ฐํ•ฉ๋‹ˆ๋‹ค.

import React, { useMemo, useEffect, useState } from "react";

export default function App() {
  const [count, setCount] = useState(0);
  const data = useMemo(()=>({
    is_fetched:false
  }), []); // <- dependencies
  useEffect(() => {
    setCount(count + 1);
  }, [data]);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <button onClick={() => setCount(count + 1)}>{count}</button>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

์ž˜๋ชป๋œ ์˜์กด์„ฑ

์ž˜๋ชป๋œ ์˜์กด์„ฑ์€ React, ์‹ฌ์ง€์–ด javascript์™€ ๊ด€๊ณ„๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ ์˜์กด์„ฑ์ด ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์€ ์šฐ๋ฆฌ์˜ ์ฑ…์ž„์ž…๋‹ˆ๋‹ค.

import React, { useEffect, useState } from "react";
const App = () => {
  const [text, setText] = useState("");
  useEffect(() => {
    setText(text);
  }, [text]);
  return null;
};
export default App;

์ด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•  ์ด์œ ๊ฐ€ ์—†๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋Œ“๊ธ€๋กœ ์•Œ๋ ค์ฃผ์„ธ์š”.

์ฃผ๋ชฉ : ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ๋ฌดํ•œ๋ฃจํ”„๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ๋งŽ์€ ๋ฐฉ๋ฒ•๋“ค์ด ์žˆ์ง€๋งŒ ์ €๋Š” ์ผ๋ถ€๋งŒ ์†Œ๊ฐœํ–ˆ์Šต๋‹ˆ๋‹ค.

์–ธ์ œ๋‚˜ eslint-plugin-react-hooks๋‚˜ CRA๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ์ด๋Š” ํ”„๋กœ๋•์…˜ ์„œ๋ฒ„์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์ „์— ์—ฌ๋Ÿฌ๋ถ„๋“ค์—๊ฒŒ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.
์–ด๋–ค ํšŒ์‚ฌ๋Š” ๋ฌดํ•œ๋ฃจํ”„ ๋•Œ๋ฌธ์— ์ผ์ฃผ์ผ ๋งŒ์— 72k๋ฅผ ์žƒ์—ˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‹ˆ ์šฐ๋ฆฌ์˜ ๊ฐ•๋ ฅํ•œ useEffect์—๊ฒŒ ํŠน๋ณ„ํžˆ ์‹ ๊ฒฝ์„ ์จ์ฃผ์„ธ์š”.
๋˜ํ•œ ๋ฆฌ์•กํŠธ์— ๊ด€ํ•ด ์ œ๊ฐ€ ์ž‘์„ฑํ•œ ์ตœ๊ทผ ๊ธ€๋„ ๊ฐ™์ด ๋ณด์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.

1. API๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋™์•ˆ Fetch ๋Œ€์‹  useQuery๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ
2. API๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ useState ๋Œ€์‹  useSWR๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ 
3. React ์•ฑ์—์„œ Axios๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ž์„ธํ•œ ๊ฐ€์ด๋“œ

[์ •๋ฆฌ] LINE DEVELOPER DAY 2021 : Frontend

LINE NEWS์—์„œ ๋ ˆ์ด์•„์›ƒ ์‹œํ”„ํŠธ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ ๋ฐฉ๋ฒ•

LINE Akinori Inoue๋‹˜ ๊ฐ•์—ฐ

  • ๋ผ์ธ ๋‰ด์Šค ํƒญ : ์›น๋ทฐ(TypeScript, React) / (ํŽ˜์ด์ง€์— ๋”ฐ๋ผ ๊ธฐ์ˆ ์Šคํƒ์ด ๋‹ค๋ฆ„)
  • Layout Shift ํ˜„์ƒ : ์ผ์ •์‹œ๊ฐ„๋™์•ˆ ๋ฐœ์ƒํ•˜๋Š” ๋ ˆ์ด์•„์›ƒ์˜ ์ด๋™ํ•˜๋Š” ๊ฒƒ, ๋ ˆ์ด์•„์›ƒ์ด ์ฝ˜ํ…์ธ ์˜ ๋กœ๋”ฉ์— ๋”ฐ๋ผ์„œ ์›€์ง์ด๋Š” ํ˜„์ƒ -> ์ž˜๋ชป๋œ ์กฐ์ž‘ ์œ ๋ฐœ

๋ผ์ธ ๋‰ด์Šค ํŠน์ง•

  • Personalization : ๊ฐ ์œ ์ €๋ณ„๋กœ ๋ณด์—ฌ์ฃผ๋Š” ์ปจํ…์ธ ๋กœ CDN ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ณ , response time์ด ๋‹ค๋ฅธ API๋ณด๋‹ค ๋Šฆ์–ด์ง€๊ฒŒ ๋จ
  • A/B Testing : UI ์ปดํฌ๋„ŒํŠธ ์กฐํ•ฉ์„ ์—ฌ๋Ÿฌ ๊ฐœ ์ค€๋น„ํ•ด์„œ ์‚ฌ์šฉ์ž๊ตฐ์œผ๋กœ ๋‹ค๋ฅด๊ฒŒ ๋ณด์—ฌ์คŒ
  • Advertisements : ๊ด‘๊ณ  API์—๋Š” ๊ฐ ์œ ์ €๋ณ„ ํ‚ค๊ฐ€ ์žˆ์–ด response time์ด ๋Šฆ์–ด์ง

Skeleton screen ์ ์šฉ

  • ํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ฝ์„ ๋•Œ๊นŒ์ง€ ์ปจํ…์ธ ์˜ ํ‹€์„ ๋ณด์—ฌ์ฃผ๋Š” ๋ฐฉ๋ฒ•, ์ปจํ…์ธ  ๋ฆฌ์†Œ์Šค๊ฐ€ ๋„์ฐฉํ•˜๋ฉด ์Šค์ผˆ๋ ˆํ†ค๊ณผ์˜ ๋ณ€๊ฒฝ -> ์ด๋™์ด ์—†์–ด์ง
  • ๋‹จ, ๋†’์ด๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ๋™์ผํ•ด์•ผ ํ•˜๋Š”๋ฐ ๊ฐœ์ธํ™”๋œ ์ปจํ…์ธ ์—์„œ๋Š” ์–ด๋ ค์›€
  • ํ™”๋ฉด ์ „์ฒด๋ฅผ ํ•˜๋‚˜์˜ skeleton์œผ๋กœ ๋ฎ์–ด์ฃผ๊ฒŒ ํ•ด๊ฒฐ
    • ํŽ˜์ด๋“œ์•„์›ƒ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋””ํ…Œ์ผํ•˜๊ฒŒ ์กฐ์ •
    • ์Šค์ผˆ๋ ˆํ†ค ์Šคํฌ๋ฆฐ์„ ์ถœํ˜„ ๋นˆ๋„๊ฐ€ ๋†’์€ ๋ ˆ์ด์•„์›ƒ์œผ๋กœ ์ž‘์„ฑ
    • ์‹œ์„  ์ง‘์ค‘์ด ๊ฐ€์žฅ ๋†’์€ ๋ถ€๋ถ„์€ ์‹ค์ œ์™€ ๋™์ผํ•˜๊ฒŒ๋”

์–ธ์ œ Skeleton screen์„ ์‚ฌ๋ผ์ง€๊ฒŒ ํ•  ๊ฒƒ์ธ์ง€?

  • ๋ชจ๋“  API ์š”์ฒญ์ด ์˜ฌ ๋•Œ๊นŒ์ง€? ๐Ÿ™…๐Ÿฝ 20๊ฐœ๊ฐ€ ๋„˜๋Š” API๋ฅผ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์—†์Œ
  • ์ผ๋ถ€ API๋งŒ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ? ๐Ÿ™…๐Ÿฝ ๊ฐœ์ธํ™”๋กœ ์ธํ•ด ์œ ์ €๋งˆ๋‹ค API๊ฐ€ ๋‹ฌ๋ผ์ง
  • ๋ทฐํฌํŠธ์— ๋“ค์–ด๊ฐ€๋Š” ์ปจํ…์ธ ์˜ ๋†’์ด๊ฐ€ ํ™•์ •๋˜์—ˆ์„ ๋•Œ

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜

์›๋ฌธ : Garbage Collection in JavaScript

์šฐ๋ฆฌ๋Š” ๊ฐ€๋น„์ง€(garbage)๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์••๋‹ˆ๋‹ค. ๊ฐ€๋น„์ง€๋ž€ ๋ณธ์งˆ์ ์œผ๋กœ ๋” ์ด์ƒ ํ•„์š”์—†๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰์…˜์ด๋ž€ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ์ •๋ฆฌํ•˜๊ณ  ํ•ด๋‹น ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์œผ๋กœ ์žฌํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ฑฐ์˜ ๋ชจ๋“  ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—์„œ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์˜ ๊ธฐ๋ณธ์ ์ธ ๊ณผ์ •์ž…๋‹ˆ๋‹ค. ์ผ๋ถ€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๊ฐœ์ž…ํ•ด์•ผ ํ•˜์ง€๋งŒ ์–ด๋–ค ์–ธ์–ด๋“ค์€ ์ž๋™์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. C์–ธ์–ด ๊ฐ™์ด ์ €์ˆ˜์ค€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋” ์ด์ƒ ํ•„์š”์—†๋Š” ๋ณ€์ˆ˜๋‚˜ ๊ฐ์ฒด๋“ค์— ๋Œ€ํ•ด malloc()์™€ free()์™€ ๊ฐ™์€ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ง์ ‘ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ’€์–ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•˜๋Š” ๊ฒƒ์€ ๊ฐœ๋ฐœ์ž์˜ ํŠน๊ถŒ์ด๋ฉฐ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•  ๊ฒƒ์ธ์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์€ ๊ฐœ๋ฐœ์ž ์† ์•ˆ์— ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•ญ์ƒ ๊ทธ๋Ÿฐ ๊ฒƒ๋งŒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ๊ฐ™์ด ๊ณ ์ˆ˜์ค€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—์„œ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ž๋™์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์•Œ์•„์„œ ํ•ด์ค๋‹ˆ๋‹ค.

์ด ์„น์…˜์—์„œ๋Š” ์•„๋ž˜ ๋‚ด์šฉ์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  1. ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๋ผ์ดํ”„์‚ฌ์ดํด
  2. ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜
  3. ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์˜ ์œ„ํ—˜

๊ด€๋ฆฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋” ์ž˜ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๋จผ์ € ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์˜ ์ผ๋ฐ˜์ ์ธ ๋ผ์ดํ”„์‚ฌ์ดํด์„ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • ๋จผ์ € ๋ณ€์ˆ˜์™€ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ๋งˆ๋‹ค ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์ด ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค.
  • ๊ทธ ๋‹ค์Œ์œผ๋กœ๋Š” ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ Read/Write ์ž‘์—…์„ ํ†ตํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ ํ•ด๋‹น ๊ณต๊ฐ„์ด ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„๊ฐ€ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋ผ๊ณ  ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ์ž๋™์œผ๋กœ ์ง„ํ–‰๋˜๋ฉฐ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๊ฐœ์ฒด๊ฐ€ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋ธŒ๋ผ์šฐ์ € ์—”์ง„์—์„œ ์ง์ ‘ ์ฐพ์„ ์ˆ˜๋Š” ์—†์ง€๋งŒ ๋ง์ž…๋‹ˆ๋‹ค. ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ์˜ ๋ชฉ์ ์€ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์„ ๊ฐ์‹œํ•˜๊ณ  ํŠน์ • ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋” ์ด์ƒ ํ•„์š”์—†๋Š”์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋” ์ด์ƒ ํ•„์š” ์—†๋‹ค๋ฉด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋˜์ฐพ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ์˜ ํŠน์ • ๋ธ”๋ก์ด ์œ ์šฉํ•˜์ง€๋Š” ๊ฒฐ์ •ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํ•ญ์ƒ ๊ทผ์‚ฌ์น˜์˜ ๊ฐ’์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์•„๋ž˜ ๋‘ ๊ฐ€์ง€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ์˜ํ•ด ์ œ์–ด๋ฉ๋‹ˆ๋‹ค.

  1. ์ฐธ์กฐ ์นด์šดํŒ… ์•Œ๊ณ ๋ฆฌ์ฆ˜
  2. Mark and Sweep ์•Œ๊ณ ๋ฆฌ์ฆ˜

ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ด…์‹œ๋‹ค.

์ฐธ์กฐ ์นด์šดํŒ… ์•Œ๊ณ ๋ฆฌ์ฆ˜

๋จผ์ € ์ฐธ์กฐ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ดํ•ดํ•ด๋ด…์‹œ๋‹ค. ๋‘ ๊ฐœ์˜ ๊ฐ์ฒด๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ ํ•œ ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ๊ฐ์ฒด์˜ ๋ฉ”์†Œ๋“œ๋‚˜ ์†์„ฑ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ ์ด ๊ฐ์ฒด๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ’์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์˜ฎ๊ฒจ๊ฐ‘์‹œ๋‹ค. ์ฐธ์กฐ ์นด์šดํŠธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ณ  ๋‹ค๋ฅธ ๊ฐ์ฒด์— ์˜ํ•ด ์ฐธ์กฐ๋˜๋Š”์ง€ ์•„๋‹Œ์ง€์— ๋”ฐ๋ผ ์–ด๋–ค ๊ฐ์ฒด์˜ ์œ ์šฉ์„ฑ์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ๊ฐ์ฒด์— ์ฐธ์กฐ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ฐ€๋น„์ง€ ๊ฐ’์œผ๋กœ ๊ฐ„์ฃผํ•˜๊ณ  ์ˆ˜์ง‘ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ๋Š” ์•„๋ž˜๋ฅผ ๋ณด์„ธ์š”.

var obj = { // first object created 
 property1: { // second object created
 property2 : 10
 }
}

๋‘ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๊ณ  ํ•œ ๊ฐ์ฒด๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฐ์ฒด๋Š” obj ๊ฐ์ฒด์— ํ• ๋‹น๋˜์–ด ์ฐธ์กฐ๋ฉ๋‹ˆ๋‹ค. ์ฐธ์กฐ๋ฅผ ํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์˜ ๋ฒ”์œ„๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

var newObj = obj; // ์กด์žฌํ•˜๋Š” ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
obj = 10; // `obj`๋Š” `newObj` ๊ฐ’์— ์˜ํ•ด ์—ฌ์ „ํžˆ ์ฐธ์กฐ๋˜๋ฏ€๋กœ GC์˜ ๋Œ€์ƒ์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๊ตฌํ˜„์„ ๋ด…์‹œ๋‹ค.

var anotherObj = newObj.property1;

property1์€ ๋‘ ๊ฐœ์˜ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” newObj ๋ณ€์ˆ˜์˜ ํ”„๋กœํผํ‹ฐ์ด๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” anotherObj ๋ณ€์ˆ˜๋กœ๋ถ€ํ„ฐ ์ฐธ์กฐ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰์…˜์˜ ๋Œ€์ƒ์ด ์•„๋‹™๋‹ˆ๋‹ค.

newObj = โ€˜Some stringโ€™;

obj ๋ณ€์ˆ˜์— ์˜ํ•ด ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋Š” ๋” ์ด์ƒ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ property1์ด anotherObj ๋ณ€์ˆ˜์— ์˜ํ•ด ์ฐธ์กฐ๋˜๋ฏ€๋กœ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์˜ ๋Œ€์ƒ์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

anotherObj = null;

์ด์ œ ์–ด๋””์—์„œ๋„ property1 ๊ฐ์ฒด์— ๋Œ€ํ•ด ์ฐธ์กฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์ƒํ™”์—์„œ ๊ฐ์ฒด๋Š” ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์˜ ๋Œ€์ƒ์ด ๋ฉ๋‹ˆ๋‹ค.

์ฐธ์กฐ ์นด์šดํŒ… ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋ณธ์งˆ์ ์œผ๋กœ ๋„ˆ๋ฌด ๋‚˜์ด๋ธŒํ•ด์„œ ์™„์ „ํžˆ ์˜์กดํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์—์„œ ์ฐธ์กฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ํž˜์ด ํฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

function foo() {
   var obj1 = {};
   var obj2 = {}; 
   obj1.a = obj2; 
   obj2.a = obj1;
   console.log(obj1);
   console.log(obj2);
}
foo();

์ถœ๋ ฅ๋˜๋Š” ๊ฐ์ฒด๋ฅผ ํ†ต๊ณผํ•ด๋ณด์„ธ์š”. ์ค‘์ฒฉ๋œ ์†์„ฑ๋“ค์ด ๋ณด์ด์‹œ๋‚˜์š”? ์ด๋Š” ์ˆœํ™˜ ์ฐธ์กฐ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—์„œ ์ฐธ์กฐ ์นด์šดํŒ… ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ์ค‘์ฒฉ๋œ ๊ฐ์ฒด๋“ค์—๊ฒŒ ์ฒ˜์ฐธํžˆ๋„ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์„ ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค์Œ์— ์‚ดํŽด๋ณผ Mark and Sweep ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

Mark and Sweep ์•Œ๊ณ ๋ฆฌ์ฆ˜

Mark and Sweep ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๊ฐ์ฒด๋“ค์— ๋„๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ GC ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ๊ฐ์ฒด๊ฐ€ ๋„๋‹ฌํ•  ์ˆ˜ ์—†๋Š” ๊ฑฐ๋ผ๋ฉด ๊ฐ€๋น„์ง€๋กœ ์ธ์‹ํ•˜์—ฌ ์ˆ˜์ง‘๋ฉ๋‹ˆ๋‹ค. ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์–ด๋–ค ๊ฐ์ฒด๊ฐ€ ์ „ํ˜€ ์ฐธ์กฐ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋„๋‹ฌํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์›๋ฆฌ๋ฅผ ๋”ฐ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๊ฐ€๋น„์ง€๋กœ ์ทจ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค.
์ด ๊ณผ์ •์€ window์™€ ๊ฐ™์ด ๋ฃจํŠธ ๊ฐ์ฒด๋ฅผ ์‹๋ณ„ํ•˜๊ณ  ๊ฑฐ๊ธฐ์„œ๋ถ€ํ„ฐ ๋ชจ๋“  ์ž์‹ ๊ฐ์ฒด๋“ค, ๊ทธ๋ฆฌ๊ณ  ๊ฐ์ฒด๋“ค์˜ ์ž์‹๋“ค์„ ์ˆœํšŒํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ ๋„๋‹ฌํ•  ์ˆ˜ ์—†๋Š” ์ผ๋ถ€ ๊ฐ์ฒด๋“ค์ด ์žˆ๋‹ค๋ฉด ๊ทธ ๊ฐ์ฒด๋“ค์€ ๊ฐ€๋น„์ง€๋กœ ์ˆ˜์ง‘๋˜๊ณ  ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค. ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ํšจ๊ณผ์ ์œผ๋กœ ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์˜ ๋ฌธ์ œ

๊ฐœ๋ฐœ์ž๋“ค์€ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋งŽ์€ ๊ฒƒ๋“ค์„ ํ•ฉ๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ์ผ์œผํ‚ค๋Š” ์•„์ฃผ ์ผ๋ฐ˜์ ์ธ ์›์ธ๋“ค์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ์ง€๋‚˜์น˜๊ฒŒ ์ „์—ญ๋ณ€์ˆ˜๋ฅผ ๋งŽ์ด ์ƒ์„ฑํ•˜๊ณ  ๋กœ์ปฌ ์Šค์ฝ”ํ”„์—์„œ var ํ‚ค์›Œ๋“œ๋ฅผ ์ƒ๋žตํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ
  2. setInterval()๊ณผ ๊ฐ™์€ ํƒ€์ด๋จธ๋ฅผ ํด๋ฆฌ์–ดํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ
  3. ํด๋กœ์ €๋ฅผ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ (ํด๋กœ์ ธ๋Š” ๋ถ€๋ชจ ํ•จ์ˆ˜๊ฐ€ ๋‹ค ์‹คํ–‰๋์Œ์—๋„ ๋ถ€๋ชจ ํ•จ์ˆ˜๋กœ๋ถ€ํ„ฐ ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„ ํ•ญ์ƒ ์ฐธ์กฐํ•จ)

๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๋Š” ์œ„์™€ ๊ฐ™์€ ์‹ค์ˆ˜๋“ค์„ ํ”ผํ•ด์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธ€์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ต‰์žฅํžˆ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ๊ณผ์ •์„ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค. ์ด ํ† ํ”ฝ์€ ๊ต‰์žฅํžˆ ๋ฐฉ๋Œ€ํ•˜์ง€๋งŒ ๋” ํฐ ์ง€์‹์„ ์œ„ํ•œ ์ถœ๋ฐœ์ ์ž…๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] ๋ฆฌ์•กํŠธ hooks์— ๋Œ€ํ•ด ์ดํ•ดํ•˜๊ธฐ

์›๋ฌธ : Making Sense of React Hooks์„ ์ฝ๊ณ  ๋ฒˆ์—ญํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

์ด๋ฒˆ์ฃผ์— Sopie Alpert์™€ ์ €๋Š” ๋ฆฌ์•กํŠธ ์ปจํผ๋Ÿฐ์Šค์—์„œ "Hooks" ์„ธ์…˜์—์„œ ๋ฐœํ‘œํ–ˆ๊ณ , Ryan Florence์˜ ์‹ฌ์ธต์ ์ธ ์„ค๋ช…์„ ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

์ €๋Š” Hooks proposal๋กœ ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฌธ์ œ๋“ค์„ ๋ณด๊ธฐ ์œ„ํ•ด ์ด ์˜คํ”„๋‹ ํ‚ค๋…ธํŠธ๋ฅผ ๋ณด์‹œ๋Š” ๊ฒƒ์„ ๊ฐ•๋ ฅํ•˜๊ฒŒ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ 1์‹œ๊ฐ„์€ ๊ฝค ํฐ ํˆฌ์ž์ด๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์—์„œ ๋ช‡ ๊ฐ€์ง€ Hooks์— ๋Œ€ํ•œ ์ƒ๊ฐ๋“ค์„ ๊ณต์œ ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ๋ชฉ : Hooks๋Š” ๋ฆฌ์•กํŠธ์—์„œ ์‹คํ—˜์ ์ธ ์ œ์•ˆ์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ ๋‹น์žฅ ๋ฐฐ์šธ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด ํฌ์ŠคํŒ…์€ ์ €์˜ ๊ฐœ์ธ์  ๊ฒฌํ•ด๋ฅผ ๋‹ด๊ณ  ์žˆ์œผ๋ฉฐ ๋ฆฌ์•กํŠธ ํŒ€์˜ ์ž…์žฅ์„ ๋ชจ๋‘ ๋ฐ˜์˜ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

์™œ Hooks์ธ๊ฐ€์š”?

์ปดํฌ๋„ŒํŠธ์™€ top-down ๋ฐฉ์‹์˜ ๋ฐ์ดํ„ฐ ํ๋ฆ„์ด ํฐ UI๋ฅผ ์ž‘๊ณ  ๋…๋ฆฝ์ ์ด๋ฉฐ ์žฌ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ๋‹จ์œ„๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ์šฐ๋ฆฌ๋Š” ๋กœ์ง์ด ์ƒํƒœ์— ์—ฐ๊ด€๋˜์–ด ์žˆ๊ฑฐ๋‚˜ ํ•จ์ˆ˜๋‚˜ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ณต์žกํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ชผ๊ฐค ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ๋•Œ๋•Œ๋กœ ์‚ฌ๋žŒ๋“ค์€ React์—์„œ "๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ"๋ฅผ ํ•˜์ง€ ๋ชปํ•œ๋‹ค๊ณ  ํ•˜์ฃ .

์ด๋Ÿฐ ๊ฒฝ์šฐ๋“ค์€ ์•„์ฃผ ํ”ํ•˜๊ณ  ์• ๋‹ˆ๋ฉ”์ด์…˜์ด๋‚˜ ํผ ํ•ธ๋“ค๋ง, ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ์†Œ์Šค์™€ ์—ฐ๊ฒฐ๋˜๋Š” ๊ฒฝ์šฐ ๋“ฑ ์šฐ๋ฆฌ๊ฐ€ ์ปดํฌ๋„ŒํŠธ๋กœ ํ•˜๊ณ  ์‹ถ์€ ๋งŽ์€ ๊ฒƒ๋“ค์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ๋ฅผ ์ปดํฌ๋„ŒํŠธ๋กœ๋งŒ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ์ƒ๊ฒจ๋‚ฉ๋‹ˆ๋‹ค.

  • ๋ฆฌํŒฉํ† ๋ง๊ณผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์šด ๊ฑฐ๋Œ€ํ•œ ์ปดํฌ๋„ŒํŠธ
  • ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋“ค๊ณผ ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฉ”์†Œ๋“œ ์‚ฌ์ด์˜ ์ค‘๋ณต๋˜๋Š” ๋กœ์ง
  • props ๋ Œ๋”๋‚˜ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ์™€ ๊ฐ™์€ ๋ณต์žกํ•œ ํŒจํ„ด

์ด๋Ÿฐ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์„ Hooks๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. Hooks๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ ๋ถ„๋ฆฌ๋œ ๋‹จ์œ„๋กœ ์กฐ์งํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. Hooks์€ ๋ฆฌ์•กํŠธ ์ฒ ํ•™(๋ช…์‹œ์ ์ธ ๋ฐ์ดํ„ฐ ํ๋ฆ„๊ณผ ๊ตฌ์„ฑ)์„ ์ปดํฌ๋„ŒํŠธ _์‚ฌ์ด_๊ฐ€ ์•„๋‹Œ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์— ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค. ์ œ๊ฐ€ Hooks๊ฐ€ React ์ปดํฌ๋„ŒํŠธ ๋ชจ๋ธ๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ž˜ ๋ถ€ํ•ฉํ•œ๋‹ค๊ณ  ๋Š๋‚€ ์ด์œ ์ž…๋‹ˆ๋‹ค.

props์˜ ๋ Œ๋”๋‚˜ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ์™€ ๊ฐ™์€ ํŒจํ„ด๊ณผ ๋‹ค๋ฅด๊ฒŒ Hooks๋Š” ์—ฌ๋Ÿฌ๋ถ„์˜ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์—์„œ ๋ถˆํ•„์š”ํ•œ ์ค‘์ฒฉ์„ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. mixin์˜ ๋‹จ์ ์œผ๋กœ๋ถ€ํ„ฐ ๊ณ ํ†ต๋ฐ›์ง€ ์•Š์•„๋„ ๋˜์ฃ .

(์ œ๊ฐ€ ๊ทธ๋žฌ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ) ์—ฌ๋Ÿฌ๋ถ„์ด ์ฒ˜์Œ์—๋Š” ๋ณธ๋Šฅ์ ์œผ๋กœ ๊ฑฐ๋ถ€ํ•˜๊ณ ์ž ํ•œ๋‹ค ํ•ด๋„, ์ผ๋‹จ์€ ์‹œ๋„ํ•ด๋ณด๊ณ  ๋‹ค๋ค„๋ณด๊ธฐ๋ฅผ ๊ถŒํ•ฉ๋‹ˆ๋‹ค. ์•„๋งˆ ์ข‹์•„ํ•˜์‹ค ๊ฒ๋‹ˆ๋‹ค.

Hooks์ด ๋ฆฌ์•กํŠธ๋ฅผ ์–ด๋ ต๊ฒŒ ๋งŒ๋“œ๋‚˜์š”?

Hooks์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ธฐ ์ „์—๋Š” Hooks์„ ์‚ฌ์šฉํ•˜๋ฉด ๋” ๋งŽ์€ ์ปจ์…‰์„ ๋”ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์šฐ๋ คํ•˜์‹ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ฉ๋ฆฌ์ ์ธ ๋น„ํŒ์ž…๋‹ˆ๋‹ค. Hooks์„ ๋ฐฐ์šฐ๋Š”๋ฐ ๋‹จ๊ธฐ์ ์œผ๋กœ๋Š” ์ธ์ง€์  ๋น„์šฉ์ด ๋“ค๊ธฐ๋Š” ํ•˜๊ฒ ์ง€๋งŒ, ์ตœ์ข… ๊ฒฐ๊ณผ๋กœ๋Š” ๊ทธ ๋ฐ˜๋Œ€๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ Hooks๋ฅผ ์ž˜ ์ˆ˜์šฉํ•œ๋‹ค๋ฉด, Hooks์€ ๋ฆฌ์•กํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ž‘์„ฑํ•˜๋ฉด์„œ ํ•„์š”ํ•œ ๊ฐœ๋…์˜ ์ˆ˜๋ฅผ ์ค„์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. Hooks์€ ํ•จ์ˆ˜, ํด๋ž˜์Šค, ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ, props ๋ Œ๋” ์‚ฌ์ด์— ๋Š์ž„์—†์ด ์Šค์œ„์นญํ•  ํ•„์š” ์—†์ด ํ•จ์ˆ˜๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ฒŒ๋” ํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์‚ฌ์ด์ฆˆ์˜ ๊ด€์ ์—์„œ Hooks์€ ~1.5kB๋งŒ ์ฆ๊ฐ€์‹œํ‚ฌ ๋ฟ์ž…๋‹ˆ๋‹ค. ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค Hooks๋ฅผ ์ฑ„ํƒํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์ฝ”๋“œ์˜ ์–‘์„ ์ค„์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ Hooks๋Š” ๊ฒฐ๊ตญ ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์‹œ๋Š” ๋‹ค์†Œ ๊ทน๋‹จ์ ์ด์ง€๋งŒ Hooks๋ฅผ ์ฑ„ํƒํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์›๋ฌธ์—์„œ ์˜ˆ์‹œ๊ฐ€ ์‚ฌ๋ผ์ง

Hooks๋ฅผ ์ฑ„ํƒํ•˜์—ฌ ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ๋ฅผ Hooks ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘์„ฑํ•ด๋„ ํ˜„์žฌ ์ฝ”๋“œ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค์€ ์šฐ๋ฆฌ๊ฐ€ Hooks๋ฅผ ๊ถŒ์žฅํ•˜๋Š” ์ด์œ ๋Š” ์ฝ”๋“œ์˜ ์žฌ์ž‘์„ฑ์ด ํ•„์š”์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ ์ฝ”๋“œ์—์„œ Hooks๋กœ ์ž‘์„ฑํ•˜๊ณ  ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. React 16.7 ์•ŒํŒŒ๋ฒ„์ „์œผ๋กœ ์‹คํ—˜ํ•ด๋ณด์‹œ๊ณ  ํ”ผ๋“œ๋ฐฑ์ด ์žˆ๊ฑฐ๋‚˜ ๋ฒ„๊ทธ๊ฐ€ ์žˆ์œผ๋ฉด ์ œ๋ณดํ•ด์ฃผ์‹ ๋‹ค๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Hooks๊ฐ€ ์ •ํ™•ํžˆ ๋ฌด์—‡์ธ๊ฐ€์š”?

Hooks๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ•œ ๊ฑธ์Œ ๋Œ์•„๊ฐ€ ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด๋ณด์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋Š˜๋‚  ๋ฆฌ์•กํŠธ ์•ฑ์—์„œ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ํ•จ์ˆ˜๋“ค์„ ์ž‘์„ฑํ•ด์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์—ฐ์‚ฐํ•  ๋•Œ ํ•จ์ˆ˜๋“ค์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ์ฃ . ์ปดํฌ๋„ŒํŠธ๋Š” ๋” ๊ฐ•๋ ฅํ•˜์ง€๋งŒ UI๋ฅผ ๋ Œ๋”๋งํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‹œ๊ฐ์ ์ด์ง€ ์•Š์€ ๋กœ์ง์„ ๊ณต์œ ํ•  ๋•Œ ๋ถˆํŽธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ render props๋‚˜ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ์™€ ๊ฐ™์€ ๋ณต์žกํ•œ ํŒจํ„ด์ด ๋งŒ๋“ค์–ด์ง„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ํ•˜๋‚˜์˜ ๊ณตํ†ต์ ์ธ ์žฌ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๋ฉด ๋” ๊ฐ„๋‹จํ•˜์ง€ ์•Š์„๊นŒ์š”?

ํ•จ์ˆ˜๋Š” ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์— ์žˆ์–ด ์™„๋ฒฝํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ์‚ฌ์ด์— ๋กœ์ง์„ ์ด๋™์‹œํ‚ค๋Š” ๊ฒƒ์€ ์ ์€ ๋…ธ๋ ฅ์ด ๋“ญ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ React์˜ ๋กœ์ปฌ state๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ์žฌ๊ตฌ์„ฑํ•˜๊ฑฐ๋‚˜ ์˜ต์ €๋ฒ„๋ธ”๊ณผ ๊ฐ™์€ ์ถ”์ƒํ™”๋ฅผ ๋„์ž…ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ "์œˆ๋„์šฐ ์‚ฌ์ด์ฆˆ๋ฅผ ๋ณด๊ณ  ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ"ํ•˜๊ฑฐ๋‚˜ "์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด์„œ ๊ฐ’ ๋ณ€๊ฒฝํ•˜๊ธฐ"์™€ ๊ฐ™์€ ๋™์ž‘์„ ๊บผ๋‚ด์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‘ ์ ‘๊ทผ๋ฒ•์€ ๋ฆฌ์•กํŠธ์˜ ๋‹จ์ˆœํ•œ ์„ฑ์งˆ์„ ํ•ด์น˜๊ฒŒ ๋˜์ฃ .

Hooks๋Š” ๊ทธ ๋ฌธ์ œ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. Hooks๋Š” ํ•จ์ˆ˜๋กœ๋ถ€ํ„ฐ ๋ฆฌ์•กํŠธ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ๋ฆฌ์•กํŠธ๋Š” ์ƒํƒœ, ๋ผ์ดํ”„์‚ฌ์ดํด, ์ปจํ…์ŠคํŠธ์™€ ๊ฐ™์€ "๊ตฌ์„ฑ์š”์†Œ"๋ฅผ ๋…ธ์ถœํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ๋นŒํŠธ์ธ Hooks๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Hooks๋Š” ์ผ๋ฐ˜์ ์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜์ด๋ฏ€๋กœ ์—ฌ๋Ÿฌ๋ถ„์€ ๋ฆฌ์•กํŠธ์—์„œ ์ œ๊ณตํ•˜๋Š” ๋นŒํŠธ์ธ Hooks์™€ ์—ฌ๋Ÿฌ๋ถ„์˜ "์ปค์Šคํ…€ ํ›…"์„ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ณต์žกํ•œ ๋ฌธ์ œ๋ฅผ ํ•œ ์ค„๋กœ ํ•ด๊ฒฐํ•˜๊ณ  ์—ฌ๋Ÿฌ๋ถ„์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋‚˜ ๋ฆฌ์•กํŠธ ์ปค๋ฎค๋‹ˆํ‹ฐ์— ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ปค์Šคํ…€ ํ›…์€ ๊ธฐ์ˆ ์ ์œผ๋กœ๋Š” ๋ฆฌ์•กํŠธ์˜ ๋ฏธ๋ž˜๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ํ›…์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ Hooks์ด ์„ค๊ณ„๋œ ๊ฒƒ์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋”ฐ๋ผ๊ฐ„ ๊ฒฐ๊ณผ๋ฌผ์ž…๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ๋ณด์—ฌ์ฃผ์„ธ์š”!

์ปดํฌ๋„ŒํŠธ๋ฅผ ํ˜„์žฌ ์œˆ๋„์šฐ width์— ๊ตฌ๋…ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค. (์ข์€ ๋ทฐํฌํŠธ์— ๋‹ค๋ฅธ ์ปจํ…์ธ ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค๊ณ  ๊ฐ€์ •)

์ด๋Ÿฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์— ์žฌ์‚ฌ์šฉ์„ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด render prop, ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋„ ๋ฐฉ๋ฒ•์— ํฌํ•จ๋˜์ฃ . ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•๋ณด๋‹ค ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

function MyResoponsiveComponent() {
    const width = useWindowWidth(); // custom hook
    return (
        <p>window width is {width}</p>
    )
}

์ด ์ฝ”๋“œ๋ฅผ ์ฝ์œผ์‹ ๋‹ค๋ฉด ๋ฌด์—‡์„ ํ•˜๊ณ ์ž ํ•˜๋Š”์ง€ ๋ฐ”๋กœ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ _window width_๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ๋ฆฌ์•กํŠธ๋Š” ํ•ด๋‹น ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ์— ์ƒํƒœ๋‚˜ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ์žˆ๋”๋ผ๋„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง„์ •ํ•œ ์„ ์–ธ์ ์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด Hooks์˜ ๋ชฉํ‘œ์ž…๋‹ˆ๋‹ค.

์ด ์ปค์Šคํ…€ ํ›…์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ด…์‹œ๋‹ค. ํ˜„์žฌ window width๋ฅผ ์œ ์ง€ํ•˜๋„๋ก React ๋กœ์ปฌ ์ƒํƒœ ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , window ์‚ฌ์ด์ฆˆ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์ƒํƒœ ๊ฐ’์„ ์„ค์ •ํ•˜๋„๋ก ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

import { useState, useEffect } from 'react';

function useWindowWidth() {
    const [width, setWidth] = useState(window.innerWidth);
    
    useEffect(() => {
        const handleResize = () => setWidth(window.innerWidth);
        window.addEventListener('resize', handleResize);
        return  () => {
            window.removeEventListener('resize', handleResize);
        }
    });
    
    return wudth;
}

์œ„์—์„œ ๋ดค๋“ฏ์ด useState ์™€ useEffect ์™€ ๊ฐ™์€ ๋นŒํŠธ์ธ ๋ฆฌ์•กํŠธ Hooks๊ฐ€ ๊ธฐ๋ณธ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ์ง์ ‘์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ  useWindowWidth ๊ฐ™์€ ์ปค์Šคํ…€ ํ›…๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปค์Šคํ…€ ํ›…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๊ด€์šฉ์ ์œผ๋กœ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค.

๋นŒํŠธ์ธ Hooks์— ๋Œ€ํ•ด ๋” ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด ์ด ๊ฐœ์š”๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

Hooks์€ ์™„์ „ํžˆ ์บก์Šํ™” ๋˜์–ด ์žˆ์–ด, ์—ฌ๋Ÿฌ๋ถ„์ด Hook์„ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค Hook์€ ์‹คํ–‰ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด์— ๋…๋ฆฝ์ ์ธ ๋กœ์ปฌ ์ƒํƒœ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ์˜ˆ์‹œ์—์„œ๋Š” ์ค‘์š”ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์ด ํŠน์ง•์ด Hooks๋ฅผ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค. ์ƒํƒœ ๋ฅผ ๊ณต์œ ํ•˜๋Š” ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ ์ƒํƒœ ์ €์žฅ ๋…ผ๋ฆฌ ๋ฅผ ๊ณต์œ ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. top-down ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ๋ง์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐ Hook์€ ๋กœ์ปฌ ์ƒํƒœ์™€ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ํ•จ์ˆ˜๋“ค ์‚ฌ์ด์—์„œ ํ•˜๋“ฏ์ด ์—ฌ๋Ÿฌ Hooks ์‚ฌ์ด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Hooks๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ์ธ์ˆ˜๋ฅผ ๋ฐ›์•„ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

Hooks ์‚ฌ์ด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์• ๋‹ˆ๋ฉ”์ด์…˜, ๋ฐ์ดํ„ฐ ๊ตฌ๋…, ํผ ๊ด€๋ฆฌ, ๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ ์ƒํƒœ ์ถ”์ƒํ™”๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋ฐ ์ž˜ ๋“ค์–ด ๋งž์Šต๋‹ˆ๋‹ค. render props๋‚˜ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ์™€ ๋‹ค๋ฅด๊ฒŒ Hooks๋Š” ๋ Œ๋” ํŠธ๋ฆฌ์— "false hierarchy"๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ์— ๋ถ€์ฐฉ๋œ ํ‰ํ‰ํ•œ "๋ฉ”๋ชจ๋ฆฌ ์…€" ๋ฆฌ์ŠคํŠธ์— ๋” ๊ฐ€๊น์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€์ ์ธ ๋ ˆ์ด์–ด๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ํด๋ž˜์Šค์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ํ•˜๋‚˜์š”?

์šฐ๋ฆฌ์˜ ์˜๊ฒฌ์œผ๋กœ๋Š” ์ปค์Šคํ…€ ํ›…์ด Hooks ์ œ์•ˆ์—์„œ ๊ฐ€์žฅ ๋งค๋ ฅ์ ์ธ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Hooks๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ React๋Š” ์ƒํƒœ์™€ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ์„ ์–ธํ•  ๋ฐฉ๋ฒ•์œผ๋กœ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  useState ์™€ useEffect ๊ฐ€ ์‹ค์ œ๋กœ ํ•˜๋Š” ๋ฐฉ์‹์ด์ฃ . ์ด ๋ฌธ์„œ์—์„œ ์ด Hooks์— ๋Œ€ํ•ด ๋” ๋ฐฐ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋นŒํŠธ์ธ Hooks๊ฐ€ ์ปค์Šคํ…€ ํ›…์„ ์ƒ์„ฑํ•  ๋•Œ๋งŒ ์œ ์šฉํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. Hooks๋Š” ๋˜ํ•œ ์ผ๋ฐ˜์ ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฐ ์žˆ์–ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ณ  ์ƒํƒœ์™€ ๊ฐ™์ด ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋ฏธ๋ž˜์— ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฐ ์žˆ์–ด Hooks๊ฐ€ 1์ฐจ์ ์ธ ๋ฐฉ๋ฒ•์ด ๋˜๊ธฐ๋ฅผ ์›ํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค.

ํด๋ž˜์Šค๋ฅผ ์—†์•จ ๊ณ„ํš์€ ์—†์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํŽ˜์ด์Šค๋ถ์—์„œ๋„ ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ณ  ์ด๋ฅผ ์žฌ์ž‘์„ฑํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฆฌ์•กํŠธ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ Hooks๋ฅผ ๋ฐ›์•„๋“ค์ธ๋‹ค๋ฉด, ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ๋‘˜ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. Hooks๋Š” ํด๋ž˜์Šค์˜ ๋ชจ๋“  ์ƒํ™ฉ์„ ๋‹ค ์ปค๋ฒ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜คํžˆ๋ ค ์ถ”์ถœ, ํ…Œ์ŠคํŒ…, ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋ฉด์— ์žˆ์–ด ๋” ์œ ์—ฐํ•จ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๋ฆฌ์•กํŠธ์˜ ๋ฏธ๋ž˜์—์„œ Hooks๋ฅผ ์šฐ๋ฆฌ์˜ ๋น„์ „์œผ๋กœ ์ œ์‹œํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค.

Hooks๋Š” ๋งˆ๋ฒ•์ด ์•„๋‹Œ๊ฐ€์š”?

Hooks์˜ ๊ทœ์น™์— ๋†€๋ผ์…จ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Hooks๋Š” ํƒ‘ ๋ ˆ๋ฒจ์—์„œ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ์ผ๋ฐ˜์ ์ด์ง€ ์•Š์ง€๋งŒ, ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ์—๋„ ์ƒํƒœ๋ฅผ ์ •์˜ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํด๋ž˜์Šค์—์„œ ์ƒํƒœ๋ฅผ ์กฐ๊ฑด๋ถ€๋กœ ์ •์˜ํ•  ์ˆ˜ ์—†๊ณ  ๋ฆฌ์•กํŠธ ์‚ฌ์šฉ์ž์—๊ฒŒ๋„ ์ด๋Ÿฐ ๋ถˆ๋งŒ์„ ๋“ค์€ ์ ์€ ์—†์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์„ค๊ณ„๋Š” ์ถ”๊ฐ€์ ์ธ ๊ตฌ๋ฌธ์ด๋‚˜ ์—ฌ๋Ÿฌ ํ•จ์ •์„ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ์ปค์Šคํ…€ ํ›…์„ ํ™œ์„ฑํ™”ํ•˜๋Š” ๋ฐ ์•„์ฃผ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” ์ƒ์†Œํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ฒฐ๊ตญ์€ Hooks๋งŒ์˜ ๊ธฐ๋Šฅ์ด ๊ฐ€์ง€๋Š” ๊ฐ€์น˜๋กœ ํŠธ๋ ˆ์ด๋“œ ์˜คํ”„ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋™์˜ํ•˜์ง€ ์•Š์œผ์‹ ๋‹ค๋ฉด ์ผ๋‹จ ์—ฐ์Šต์œผ๋กœ ๊ฐ–๊ณ  ๋†€์•„๋ณด๋ฉด์„œ ๋งˆ์Œ์ด ๋ฐ”๋€Œ์‹œ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ €ํฌ๋Š” ์—”์ง€๋‹ˆ์–ด๋“ค์ด Hooks์˜ ๊ทœ์น™์— ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œ ํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ฌ๋™์•ˆ ์‹ค์ œ ๊ฐœ๋ฐœํ•  ๋•Œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๊ฐœ๋ฐœ์ž๋“ค์ด ๋ช‡ ์‹œ๊ฐ„ ์•ˆ์— ์ต์ˆ™ํ•ด์ง„๋‹ค๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ์ €๋„ ์ฒ˜์Œ์— ๊ทœ์น™๋“ค์ด ์ž˜๋ชป๋˜์—ˆ๋‹ค๊ณ  ๋Š๊ผˆ๊ธฐ๋Š” ํ•˜์ง€๋งŒ ๊ธˆ๋ฐฉ ๊ทน๋ณตํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝํ—˜์€ ๋ฆฌ์•กํŠธ๋ฅผ ์ฒ˜์Œ ๊ฒฝํ—˜ํ–ˆ์„ ๋•Œ์™€ ๋น„์Šทํ–ˆ์Šต๋‹ˆ๋‹ค. (๋ฐ”๋กœ ๋ฆฌ์•กํŠธ๋ฅผ ์ข‹์•„ํ•˜์…จ๋‚˜์š”? ์ €๋Š” ๋‘ ๋ฒˆ ํ•ด๋ณด๊ณ  ์ข‹์•„ํ–ˆ์Šต๋‹ˆ๋‹ค.)

Hooks์˜ ๊ตฌํ˜„์— ์žˆ์–ด "๋งˆ๋ฒ•"์€ ์—†์Šต๋‹ˆ๋‹ค. Jamie๊ฐ€ ์ง€์ ํ•œ ๋ฐ”์™€ ๊ฐ™์ด ์ด๊ฒƒ์€ ์•„๋ž˜์™€ ๋น„์Šทํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ prototype๊ณผ __proto__์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ธ๊ฐ€?

์›๋ฌธ : https://javascript.plainenglish.io/proto-vs-prototype-in-js-140b9b9c8cd5
๋ถ€์ œ : An explanation of the relationship between the two concepts.

prototype์— ๋Œ€ํ•œ ์„ค๋ช…

์• ํ”Œ์€ ์ตœ๊ทผ์— ์ƒˆ๋กœ์šด ์•„์ดํฐ ๋ชจ๋ธ์ธ iPhone 11์„ ์ถœ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋ชจ๋ธ์€ ํŠน์ •ํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๋Š”๋ฐ ์˜ˆ๋ฅผ ๋“ค์–ด Face ID์™€ 4K ๋น„๋””์˜ค๊ฐ™์€ ๊ฒƒ๋“ค์ด์ฃ . ๋ชจ๋“  ์•„์ดํฐ 11์€ ๋™์ผํ•œ ๊ธฐ๋Šฅ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด, ์ƒˆ๋กœ์šด ์•„์ดํฐ 11์ด ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์•„์ดํฐ11์„ ๋งŒ๋“œ๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค. ์ ์ ˆํ•˜๊ฒŒ ์•„์ดํฐ 11์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋ชจ๋ธ์„ ์ฐธ๊ณ ํ•˜๋Š” _prototype_์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ”„๋กœํ† ํƒ€์ž… ๋˜๋Š” ๋ชจ๋ธ์€ ๋ชจ๋“  ์•„์ดํฐ์ด Face ID๋ฅผ ๊ฐ€์ง€๋ฉฐ 4K ๋น„๋””์˜ค๋ฅผ ์ฐ์„ ์ˆ˜ ์žˆ๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์•„์ดํฐ ์ƒ์„ฑ์ž๋Š” ๋ฐ˜๋“œ์‹œ ์ œ์ž‘ํ•ด์•ผ ํ•˜๋Š” ํ”„๋กœํ† ํƒ€์ž…์„ ์•Œ๊ณ  ์ ‘๊ทผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ƒ์„ฑ์ž์˜ prototype ํ”„๋กœํผํ‹ฐ์ž…๋‹ˆ๋‹ค.

function iPhone() {}; // ์ƒ์„ฑ์ž

// a method for recognizing faces
iPhone.prototype.faceID = function() { ... };

// a method for taking 4k video
iPhone.prototype.video = function() { ... };

let newPhone = new iPhone(); // ์•„์ดํฐ11

์—ฌ๊ธฐ๊นŒ์ง€ ์ดํ•ด๊ฐ€ ๋˜์…จ๋‚˜์š”? ๊ทธ๋Ÿผ __proto__์— ๋Œ€ํ•ด ์•Œ์•„๋ด…์‹œ๋‹ค.

__proto__์™€ prototype์˜ ๊ด€๊ณ„

์ƒˆ๋กœ์šด iPhone 11์„ ๋งŒ๋“ค๊ณ  newPhone์ด๋ผ๋Š” ๋ณ€์ˆ˜์— ์ €์žฅํ–ˆ์Šต๋‹ˆ๋‹ค. newPhone์˜ ๋‚ด์šฉ๋ฌผ์€ ์•„๋ž˜์™€ ๊ฐ™์„ ๊ฒ๋‹ˆ๋‹ค.

image

์ด ์•„์ดํฐ11์€ FaceID์™€ video ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค! ์‚ฌ์‹ค ์—ฌ๋Ÿฌ๋ถ„์€ newPhone.faceID()๋‚˜ newPhone.video()๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ณ  ์ด ๋ฉ”์†Œ๋“œ๋“ค์ด ์ž˜ ๋™์ž‘ํ•˜๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฐ ํ•จ์ˆ˜๋“ค์ด __proto__๋ผ๋Š” ๊ฐ์ฒด์— ์ €์žฅ๋˜๊ณ  ์ง์ ‘์ ์œผ๋กœ newPhone์˜ ํ”„๋กœํผํ‹ฐ๋กœ ์ €์žฅ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์ผ๊นŒ์š”?

__proto__๋Š” ์ƒ์„ฑ๋œ ํ”„๋กœํ† ํƒ€์ž…์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ชจ๋“  ํด๋ž˜์Šค _์ธ์Šคํ„ด์Šค_์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. newPhone.__proto__๋Š” iPhone.prototype์— ๋Œ€ํ•œ ์ฐธ์กฐ์ด๊ณ  ๋”ฐ๋ผ์„œ ์ •ํ™•ํžˆ ๋™์ผํ•œ ๊ฒƒ๋“ค์„ ์ง€๋‹ˆ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. iPhone.prototype๊ณผ ๋™์ผํ•œ proto ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง์œผ๋กœ์จ, newPhone์€ ๋ณธ์งˆ์ ์œผ๋กœ "๋ณด์„ธ์š”, ์ €๋Š” ์•„์ดํฐ11์ด๋ผ์„œ ๋‹ค๋ฅธ ์•„์ดํฐ11๊ณผ ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์š”! ํŽ˜์ด์Šค ์•„์ด๋””, 4K ํ™”์งˆ ๋“ฑ ๋ญ๋“ ์š”." ๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ฃ .

ํ˜„์‹ค์„ธ๊ณ„์—์„œ prototype๊ณผ __proto__์˜ ์œ ์ผํ•œ ์ง„์งœ ์ฐจ์ด์ ์€ ์ „์ž๋Š” ํด๋ž˜์Šค ์ƒ์„ฑ์ž์˜ ํ”„๋กœํผํ‹ฐ๋ผ๋Š” ์ ์ด๊ณ  ํ›„์ž๋Š” ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์˜ ํ”„๋กœํผํ‹ฐ๋ผ๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ง๋กœ ๋งํ•˜๋ฉด iPhone.prototype์€ iPhone์„ ๋งŒ๋“œ๋Š” ์ฒญ์‚ฌ์ง„์„ ์ œ๊ณตํ•˜๋ฉฐ, newPhone.__proto__๋Š” ๊ทธ ์ฒญ์‚ฌ์ง„์— ๋”ฐ๋ผ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งŒ๋“ค์–ด์กŒ๋‹ค๋Š” ๊ฒƒ์„ ๋งํ•ด์ค๋‹ˆ๋‹ค. ๋‘ ๊ฐ์ฒด์— ์กด์žฌํ•˜๋Š” ํ”„๋กœํผํ‹ฐ๋“ค๊ณผ ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•ด์„œ๋Š”... ์Œ ์ •ํ™•ํžˆ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, ์—ฌ๋Ÿฌ๋ถ„์€ ์œ„ ์ด๋ฏธ์ง€์˜ ๋งˆ์ง€๋ง‰ ๋ผ์ธ์— ์žˆ๋Š” proto: Object์˜ ๋œป์— ๋Œ€ํ•ด ๊ถ๊ธˆํ•˜์…จ์„ ๊ฒ๋‹ˆ๋‹ค. newPhone.__proto__๋Š” ์‚ฌ์‹ค ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด๋“ค ๋˜ํ•œ ํŠน์ •ํ•œ "์ฒญ์‚ฌ์ง„"์œผ๋กœ๋ถ€ํ„ฐ ๋งŒ๋“ค์–ด์ง„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์˜ˆ์‹œ์—์„œ newPhone.__proto__.__proto__๋Š” Object.prototype์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ด๋Š” ๋ชจ๋“  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด๊ฐ€ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ํ”„๋กœํ† ํƒ€์ž…์ด์ฃ . ๊ทธ๊ฒŒ ๋‹ค์ž…๋‹ˆ๋‹ค!

[๋ฒˆ์—ญ] await์ด ์ฝ”๋“œ๋ฅผ ๋Š๋ฆฌ๊ฒŒ ํ•˜๋Š” ๋ฐฉ์‹

์›๋ฌธ : How return await can slow down your code

๋ฆฌํ„ดํ•˜๊ธฐ ์ „์— ํ”„๋กœ๋ฏธ์Šค๋ฅผ awaitํ•˜๋Š” ๊ฒƒ์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋ฅผ ๋Š๋ฆฌ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

์š”์•ฝ: ESLint no-return-await rule์„ ์‚ฌ์šฉํ•˜์„ธ์š”

ํฐ ์Šค์ผ€์ผ์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์˜ ์ฃผ์š” ํŒจ๋Ÿฌํƒ€์ž„์€ ๊ณ ์ˆ˜์ค€์˜ ์–ธ์–ด๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ณ ์ˆ˜์ค€์˜ ์–ธ์–ด๋Š” ๊ฐœ๋ฐœ์„ ๋น ๋ฅด๊ฒŒ ํ•˜๋Š” ๋Œ€์‹  ๋Ÿฐํƒ€์ž„์—์„œ ์†๋„๊ฐ€ ๋Š๋ฆฌ๋‹ค๋Š” ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ๊ฒฝ์šฐ์—์„œ๋Š” ๊ทธ ์–ธ์–ด๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์„ ํƒํ•œ ๊ฒƒ์ด์ฃ .

์—ฌ๋Ÿฌ๋ถ„์€ ์•„๋งˆ "์ง„์งœ ์„ฑ๋Šฅ์ด ์ค‘์š”ํ–ˆ๋‹ค๋ฉด, Rust๋กœ ์ฝ”๋“œ๋ฅผ ์งฐ๊ฒ ์ง€" ๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹ค ์ˆ˜๋„ ์žˆ์ง€๋งŒ ๊ทธ๋ ‡๊ฒŒ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋Š๋ฆฐ ๊ฑด ์•„๋‹™๋‹ˆ๋‹ค. NodeJs ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์ƒํ™ฉ์—์„œ ๊ฐœ๋ฐœ๊ณผ ๋Ÿฐํƒ€์ž„ ์†๋„ ์ถฉ๋ถ„ํžˆ ๋น ๋ฆ…๋‹ˆ๋‹ค. Techempower ๋ฒค์น˜๋งˆํฌ ๊ฒฐ๊ณผ ๋˜ํ•œ NodeJs๊ฐ€ ์ถฉ๋ถ„ํžˆ ์ข‹์€ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์„ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

Web API๊ฐ™์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋ฅผ 1ํผ์„ผํŠธ๋ผ๋„ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์ดˆ๋‹น 9์ฒœ๊ฐœ์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ๊ฒฝ์šฐ 800๊ฐœ๋ฅผ ์ถ”๊ฐ€๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ด์ฃ . ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฑด ์˜ค๋Š˜์˜ ์„ฑ๋Šฅ ์œผ๋กœ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

๋ฆฌํ„ดํ•˜๊ธฐ ์ „์— ํ”„๋กœ๋ฏธ์Šค๋ฅผ awaitํ•˜๊ธฐ

๋‹ค๋ฅธ ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ๊ฐ์‹ธ๊ณ  ๊ธฐ๋‹ค๋ฆฌ๋„๋ก ํ•จ์ˆ˜๋ฅผ ์งœ๋Š” ๊ฒƒ์€ ๋น„๋™๊ธฐ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์•„์ฃผ ํ”ํ•œ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

async function example() {
  const server = await createServer();
  const endpoints = await createEndpoints(server);

 return await startServer(server, endpoints);
}

๋ณด์‹œ๋‹ค์‹œํ”ผ ์œ„์˜ ํ•จ์ˆ˜๋Š” return ๋ฌธ ์ „์— await๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ๋ถ€๋ถ„์ด ๊นŒ๋‹ค๋กญ๊ฒŒ ๋งŒ๋“œ๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.
๋ฌธ์ œ๋ฅผ ๊นŠ๊ฒŒ ์„ค๋ช…ํ•˜๊ธฐ ์ „์— ์ด๊ฒƒ์ด ์–ผ๋งˆ๋‚˜ ๋Š๋ฆฌ๊ฒŒ ๋งŒ๋“œ๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ๊ฐ„๋‹จํ•œ ๋ฒค์น˜๋งˆํฌ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

benchmark

์—ฌ๊ธฐ์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ์ฝ”๋“œ๋Š” [arthur-place/the-cost-of-return-await](https://github.com/arthur-place/the-cost-of-return-await) ๊นƒํ—ˆ๋ธŒ ์ €์žฅ์†Œ์— ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฉ”์ธ ํ•จ์ˆ˜์ธ work()๋Š” setImmediate ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์ž๋งˆ์ž resolve๋˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ 3๊ฐœ์˜ ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š”๋ฐ ์ด ํ•จ์ˆ˜๋“ค์€ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค์ง€๋งŒ ํ•˜๋‚˜๋Š” ๋น„๋™๊ธฐ์ด๋ฉฐ await์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ๊ทธ๋ƒฅ ๋น„๋™๊ธฐ์ด๊ณ  ๋งˆ์ง€๋ง‰ ํ•˜๋Š” ๋‹จ์ˆœํžˆ return ๋ฌธ๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

// function work(): Promise<any>;

async function doWait() {
  return await work();
}

async function dontWait() {
  return work();
}

function justReturn() {
  return work();
}

์‹ค์ œ๋กœ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋” ์ด์ „์˜ EcamScript ๋ฒ„์ „์œผ๋กœ ํŠธ๋žœ์ŠคํŒŒ์ผ๋˜๋Š”๋ฐ ๊ทธ ์ ์ด ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋นŒ๋“œ ๋Œ€์ƒ๊ณผ ์ƒ์„ฑ๋œ ์ฝ”๋“œ

๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋™์ผํ•œ ์†Œ์Šค ํŒŒ์ผ์„ ES3์—์„œ ES2022๊นŒ์ง€ ํŠธ๋žœ์ŠคํŒŒ์ผํ–ˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์— ๊ฐ ๊ฒฐ๊ณผ๋ฌผ๋“ค์˜ ์ฐจ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

Babel(Regenerator Runtime)
function doWait() {
  return _doWait.apply(this, arguments);
}

function _doWait() {
  _doWait = (0, _asyncToGenerator2['default'])(
    /*#__PURE__*/ _regenerator['default'].mark(function _callee() {
      return _regenerator['default'].wrap(function _callee$(_context) {
        while (1) {
          switch ((_context.prev = _context.next)) {
            case 0:
              _context.next = 2;
              return work();

            case 2:
              return _context.abrupt('return', _context.sent);

            case 3:
            case 'end':
              return _context.stop();
          }
        }
      }, _callee);
    })
  );
  return _doWait.apply(this, arguments);
}

function dontWait() {
  return _dontWait.apply(this, arguments);
}

function _dontWait() {
  _dontWait = (0, _asyncToGenerator2['default'])(
    /*#__PURE__*/ _regenerator['default'].mark(function _callee2() {
      return _regenerator['default'].wrap(function _callee2$(_context2) {
        while (1) {
          switch ((_context2.prev = _context2.next)) {
            case 0:
              return _context2.abrupt('return', work());

            case 1:
            case 'end':
              return _context2.stop();
          }
        }
      }, _callee2);
    })
  );
  return _dontWait.apply(this, arguments);
}
ES5 (Tslib Awaiter and Tslib Generator)
function doWait() {
  return __awaiter(this, void 0, void 0, function () {
    return __generator(this, function (_a) {
      switch (_a.label) {
        case 0:
          return [4 /*yield*/, work()];
        case 1:
          return [2 /*return*/, _a.sent()];
      }
    });
  });
}

function dontWait() {
  return __awaiter(this, void 0, void 0, function () {
    return __generator(this, function (_a) {
      return [2 /*return*/, work()];
    });
  });
}
ES6 (Tslib Awaiter)
function doWait() {
  return __awaiter(this, void 0, void 0, function* () {
    return yield work();
  });
}

function dontWait() {
  return __awaiter(this, void 0, void 0, function* () {
    return work();
  });
}
ES2017 (Native)
async function doWait() {
  return await work();
}
async function dontWait() {
  return work();
}

์ œ ์ปดํ“จํ„ฐ๋Š” ์•„๋ž˜์˜ ์ŠคํŽ™์‚ฌํ•ญ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • Node v16.14.0
  • NVM 0.39.1
  • i5 9600K @5ghz OC
  • 32GB @ 32mmMhz
  • 1TB SSD PCIe 4.0

๋ฒค์น˜๋งˆํฌ ๊ฒฐ๊ณผ

image

์•„๋งˆ ์—ฌ๋Ÿฌ๋ถ„๋“ค์€ Es6๊ฐ€ ์™œ ์ด๋ ‡๊ฒŒ ๋Š๋ฆฐ์ง€ ๊ถ๊ธˆํ•ดํ•˜์‹ค ์ˆ˜๋„ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ €์˜ ๊ฐ„๋‹จํ•œ ์‹คํ—˜๊ฒฐ๊ณผ๋Š” tslib generator ํด๋ฆฌํ•„(__generator)์€ Node 17 native function*๊ณผ yield๋ณด๋‹ค ๋น ๋ฅด๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ ์ด๊ฑด ๋˜ ๋‹ค๋ฅธ ์–˜๊ธฐ์ฃ .

์™œ return await์ด ์ž˜๋ชป๋œ๊ฑธ๊นŒ?

Babel, ES5, ES6์œผ๋กœ ํŠธ๋žœ์ŠคํŒŒ์ผ๋œ ๊ฒƒ๋“ค์€ ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์„ฑ๋Šฅ์„ ๋ณด์—ฌ์ค„ ๊ฒƒ์ด๋ผ๊ณ  ์˜ˆ์ƒ๋ฉ๋‹ˆ๋‹ค. ๊ฐ๊ฐ ๋‹ค๋ฅธ ํด๋ฆฌํ•„๊ณผ ECMAScript ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ช…๋ฐฑํ•œ ์ผ์ž…๋‹ˆ๋‹ค.
๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ, await์€ ๋ง ๊ทธ๋Œ€๋กœ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ‰๊ฐ€๋œ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํ„ดํ•˜๊ธฐ ์ „์— ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ๋๋‚˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์ด์ฃ .
๋˜ํ•œ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋Š” ๊ฒฐ๊ณผ ์ž์ฒด๋Š” ํ”„๋กœ๋ฏธ์Šค์™€ ๊ฐ™์€ ๋Œ€์ƒ์ผ ๊ฒƒ์ด๋ผ๊ณ  ์˜ˆ์ƒํ•˜๋ฏ€๋กœ await(promise)์™€ await(non-promise)๋Š” ๋™์ผํ•œ ๋™์ž‘์„ ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒ๋‹ˆ๋‹ค.
NodeJS Event Loop๋Š” ์ด๋ฏธ ์ง€์ •๋œ ์ฝ”๋“œ ๋ผ์ธ์ด ํ˜„์žฌ์˜ iteration์ด ๋๋‚  ๋•Œ ์‹คํ–‰๋˜๋„๋ก ์Šค์ผ€์ฅด๋ง์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ์—์•ผ ๋‚˜๋จธ์ง€๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋‚ด๋ถ€ ํ”„๋กœ๋ฏธ์Šค๋‚˜ ์ผ๋“ค์— ๋Œ€ํ•ด ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์œ„์˜ ์ œ ์ฃผ์žฅ์„ ๋’ท๋ฐ›์นจํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

async function withAwait() {
  console.log(1);

  // This will make nodejs wait for the
  // end of the current loop. Because it
  // "expects" that a promise was given
  // in place of 0
  await 0;

  console.log(2);
}

async function withoutAwait() {
  console.log(3);
}

withAwait();
withoutAwait();
$ node example.js
#> 1
#> 3
#> 2

๋‹ค์‹œ ๋ฒค์น˜๋งˆํฌ ์–˜๊ธฐ๋กœ ๋Œ์•„๊ฐ€์„œ, ์•ž์„œ ์–˜๊ธฐํ•œ 1%๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ 1%๋Š” 10,000ops/s์—์„œ 100์ด ๋  ์ˆ˜๋„ ์žˆ๊ณ  ์‹ฌ์ง€์–ด๋Š” 1,000,000 ops/s์ธ ์„œ๋ฒ„์—์„œ 10,000์ด ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ await ํ‚ค์›Œ๋“œ๋ฅผ ์ž˜๋ชป ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜๋ณต๋˜๋Š” ํ”Œ๋กœ์šฐ๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ์ค‘๋‹จ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์ฃ . return๋ฌธ์ด ์ ์ ˆํ•˜๊ฒŒ ์‚ฌ์šฉ๋  ๋•Œ๋งˆ๋‹ค ์„ธ์ด๋ธŒ๋˜๋Š” ๊ฐ ๋ฐ€๋ฆฌ์ดˆ๋“ค์ด ๋”ํ•ด์ ธ ์ดˆ๋‹น ๋” ๋งŽ์€ ์ž‘์—…๋“ค์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. return await์„ ํ”ผํ•˜๋Š” ๊ฒƒ์€ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์˜ˆ์™ธ ์ฒ˜๋ฆฌ

์ด์ „์— ๋ฐœํ–ˆ๋“ฏ์ด, ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฆฌํ„ดํ•˜๊ธฐ ์ „์— ๊ธฐ๋‹ค๋ฆด ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด, ์ฆ‰์‹œ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.Chain of Responsibility๊ณผ ๋น„์Šทํ•˜๊ฒŒ ๋ง์ž…๋‹ˆ๋‹ค. ์ฆ‰ ๋ฆฌํ„ดํ•˜๋Š” ๊ฒƒ์— ์ฑ…์ž„์„ ์ง€๋Š” ๋Œ€์‹  ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ์ž์—๊ฒŒ ์ฑ…์ž„์„ ๋„˜๊ธฐ๊ฒŒ ๋˜๋Š”๋ฐ์š”. ์ด๋Ÿฐ ๊ฒฝ์šฐ Try-Catch Blocks์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

// Correct usage of `return await`
async function fn() {
  try {
    return await work();
  } catch (err) {
    return handleWorkError(error);
  }
}

์œ„์˜ ์˜ˆ์‹œ์—์„œ await ํ‚ค์›Œ๋“œ๋ฅผ ์ œ๊ฑฐํ•ด๋ณธ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

// return await work();
return work();

ํ•จ์ˆ˜ ๋‚ด์—์„œ ์–ด๋–ค ์˜ˆ์™ธ๋ฅผ ์ง์ ‘ throwํ•œ๋‹ค ํ•˜๋”๋ผ๊ณ  catch ๋ธ”๋ก์€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. work() ํ•จ์ˆ˜๊ฐ€ ๋ฆฌํ„ดํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋Š” fn() ํ˜ธ์ถœ์ž์—๊ฒŒ ์ž์‹ ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฑ…์ž„์„ ์ง์ ‘ ์ „๋‹ฌํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. fn() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์™ธ๋ถ€์— try-catch ๋ธ”๋ก์„ ๋‘๋ฉด, ๋‚ด๋ถ€ fn() catch ๋ธ”๋ก์€ ์‹คํ–‰๋˜์ง€ ์•Š๊ณ  ์™ธ๋ถ€์— ์žˆ๋Š” ๋ธ”๋ก๋งŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…

์œ„์˜ ์˜ˆ์™ธ์‚ฌํ•ญ์„ ๋ฌด์‹œํ•˜๊ณ , ์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ๊ฐ„๋‹จํžˆ await์„ ์ œ๊ฑฐํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ESLint๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด(์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์‚ฌ์šฉํ•˜์„ธ์š”) no-return-awaitrule์„ ์ผœ๋‘์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Zero cost async ์Šคํƒ ์ถ”์ 

์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์ข‹์€ ๋…์ž๋ผ๋ฉด ์•„๋งˆ no-return-await์— ๋Œ€ํ•ด ์ฝ์—ˆ์„ ๊ฒƒ์ด๊ณ  ์Šคํƒ ์ถ”์ ์„ ๋ณด์กดํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด์„œ๋„ ๋ณด์…จ์„ ๊ฒ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์•˜๋”๋ผ๋„ ์ œ๊ฐ€ ์„ค๋ช…๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

์š”์•ฝํ•˜์ž๋ฉด, ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฆฌํ„ดํ•˜๊ณ  ํ˜ธ์ถœ์ž๊ฐ€ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋˜๋ฉด ์Šคํƒ ์ถ”์ ์— ๋Œ€ํ•œ ์†์‹ค(loss)๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ๋งž์ดํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ๋ฅผ ๋ณด์—ฌ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

async function foo() {
  await bar();
  return 42;
}

async function bar() {
  await Promise.resolve();
  throw new Error('BEEP BEEP');
}

foo().catch((error) => console.log(error.stack));
$ node index.js
Error: BEEP BEEP
  at bar (index.js:8:9) --> (ONLY SHOWS BAR) <--
  at process._tickCallback (internal/process/next_tick.js:68:7)
  at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
  at startup (internal/bootstrap/node.js:266:19)
  at bootstrapNodeJSCore (internal/bootstrap/node.js:595:3)
But as written on the official [v8.dev](https://v8.dev/blog) blog, they solved this problem with something called [zero-cost async stack traces](https://bit.ly/v8-zero-cost-async-stack-traces) and now you can see the exact stack trace in the console:

๊ทธ๋Ÿฌ๋‚˜ v8.dev ๊ณต์‹ ๋ธ”๋กœ๊ทธ์— ์“ฐ์ธ ๊ฒƒ์ฒ˜๋Ÿผ zero-cost async stack traces๋ฅผ ํ†ตํ•ด ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์œผ๋ฉฐ ์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ์ด์ œ ์ฝ˜์†”์—์„œ ์ •ํ™•ํ•œ ์—๋Ÿฌ ์Šคํƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

$ node index.js

Error: BEEP BEEP
   at bar (index.js:8:9)
   at process._tickCallback (internal/process/next_tick.js:68:7)
   at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
   at startup (internal/bootstrap/node.js:266:19)
   at bootstrapNodeJSCore (internal/bootstrap/node.js:595:3)
   at async foo (index.js:2:3)

์ œ๊ฐ€ ๋ชจ๋“  ๊ฒƒ์„ ์„ค๋ช…ํ•˜์ง„ ์•Š์•˜์œผ๋‹ˆ ์ž์„ธํ•œ ๊ฑด official blog post๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

๋!

์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์ œ ๊ธ€์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๊ฒƒ์„ ๋ฐฐ์›Œ ์ฝ”๋“œ๋ฅผ ๋” ์ข‹๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

[์ •๋ฆฌ] TypeScript : Utility Types

Typescript docs ์ฐธ๊ณ 

Utility Types

  • ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ํƒ€์ž… ๋ณ€ํ™˜์„ ์šฉ์ดํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด utility types ์ œ๊ณต
  • ์ „์—ญ์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

Partial<Type>

  • Type์˜ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๋ฅผ optional๋กœ ๊ตฌ์„ฑ
  • ์ฃผ์–ด์ง„ ํƒ€์ž…์˜ ๋ชจ๋“  ์„œ๋ธŒ์…‹์— ๋Œ€ํ•œ ํƒ€์ž…์œผ๋กœ ์ œ๊ณต (์˜ต์…˜์ด๋‹ˆ๊นŒ ์„œ๋ธŒ์…‹์˜ ๊ฒฝ์šฐ์˜ ์ˆ˜๊ฐ€ ๋งŽ์Œ)

Require<Type>

  • Partial๊ณผ ๋ฐ˜๋Œ€๋กœ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๋ฅผ required๋กœ ๊ตฌ์„ฑ

Readonly<Type>

  • Type์˜ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๋ฅผ readonly๋กœ ์ƒ์„ฑํ•˜์—ฌ ์žฌํ• ๋‹น์„ ํ•  ์ˆ˜ ์—†๊ฒŒ ํ•จ
  • Object.freeze์™€ ๊ฐ™์ด ๋Ÿฐํƒ€์ž„์— ํ• ๋‹น์‹์— ๋Œ€ํ•œ ์—๋Ÿฌ๋ฅผ ๋‚˜ํƒ€๋‚ผ ๋•Œ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์€ ํƒ€์ž…

์˜ˆ์‹œ

interface Todo {
  title: string;
}

const todo: Readonly<Todo> = {
  title: "Delete inactive users",
};

todo.title = "Hello";
// Cannot assign to 'title' because it is a read-only property.

Record<Keys, Type>

  • Key๋Š” Type์— ๋Œ€ํ•œ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๋Š” ๊ฐ์ฒด์˜ ํ‚ค

์˜ˆ์‹œ

interface CatInfo {
  age: number;
  breed: string;
}

type CatName = "miffy" | "boris" | "mordred";

const cats: Record<CatName, CatInfo> = {
  miffy: { age: 10, breed: "Persian" },
  boris: { age: 5, breed: "Maine Coon" },
  mordred: { age: 16, breed: "British Shorthair" },
};

Pick<Type, Keys>

  • Type์—์„œ Keys์— ๋Œ€ํ•œ ํ”„๋กœํผํ‹ฐ๋ฅผ picking ํ•ด์™€์„œ ํƒ€์ž… ๊ตฌ์„ฑ
  • Keys๋Š” string ๋ฆฌํ„ฐ๋Ÿด์ด๋‚˜ string ์—ฌ๋Ÿฌ ๊ฐœ

์˜ˆ์‹œ

interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Pick<Todo, "title" | "completed">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};

Omit<Type, Keys>

  • Type์˜ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ์—์„œ Keys๋ฅผ ์ œ์™ธ

Exclude<Type, ExcludeUnion>

  • Type์—์„œ ExcludeUnion์— ์†ํ•œ ํ•ฉ์ง‘ํ•ฉ ๊ฐ’๋“ค์„ ์ œ๊ฑฐ

์˜ˆ์‹œ

type T0 = Exclude<"a" | "b" | "c", "a">;
// type T0 = "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">;
// type T1 = "c"

Extract<Type, Union>

  • Type์—์„œ Union์— ์†ํ•˜๋Š” ๊ฐ’๋“ค๋งŒ ํƒ€์ž…์œผ๋กœ ๊ตฌ์„ฑ

์˜ˆ์‹œ

type T1 = Extract<string | number | (() => void), Function>;
// type T1 = () => void
// Function์— ์†ํ•˜๋Š” ๊ฒƒ๋งŒ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ

NonNullable<Type>

  • Type์—์„œ null๊ณผ undefined ์ œ๊ฑฐ

Parameters<Type>

  • ํ•จ์ˆ˜ ํƒ€์ž…์ธ Type์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํŠœํ”Œ์˜ ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉ

ConstructorParameters<Type>

  • ์ƒ์„ฑ์ž ํ•จ์ˆ˜ ํƒ€์ž…์—์„œ ํŠœํ”Œ ๋˜๋Š” ๋ฐฐ์—ด ํƒ€์ž…์„ ๊ตฌ์„ฑ
  • Type์ด ํ•จ์ˆ˜๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ never

ReturnType<Type>

  • ํ•จ์ˆ˜ ํƒ€์ž…์ธ Type์˜ ๋ฆฌํ„ด ํƒ€์ž…์„ ์‚ฌ์šฉ

InstanceType<Type>

  • Type์˜ ์ƒ์„ฑ์ž ํ•จ์ˆ˜์˜ ์ธ์Šคํ„ด์Šค ํƒ€์ž…์œผ๋กœ ๊ตฌ์„ฑ

ThisParameterType<Type>

  • ํ•จ์ˆ˜ ์œ ํ˜• ๋˜๋Š” unknown์˜ this ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”์ถœํ•˜์—ฌ ์‚ฌ์šฉ
  • ํ•จ์ˆ˜์— this ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†์„ ๋•Œ unknown

OmitThisParameter<Type>

  • Type์—์„œ this ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ œ๊ฑฐ
  • this๊ฐ€ ์ •์˜๋˜์ง€ ์•Š์•˜์œผ๋ฉด ๋‹จ์ˆœํžˆ Type๋งŒ

[๋ฒˆ์—ญ] null์„ ES6 Symbols๋กœ ๋Œ€์ฒดํ•˜์„ธ์š”

์›๋ฌธ : Replace null with ES6 Symbols

์ž‘์€ ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž‘์—…์„ ํ•  ๋•Œ missing value๋ฅผ ํ‘œํ˜„ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ณผ๊ฑฐ์—๋Š” ๊ฐ„๋‹จํ•œ ์„ธํŒ…์„ ํ•˜๊ฑฐ๋‚˜ ๋” ๋งŽ์ด ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด Option์„ ํ†ตํ•ด nullableํ•œ ์ ‘๊ทผ๋ฒ•์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” ๋‘˜ ๋‹ค ๋งž์ง€ ์•Š์•„์„œ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

์™œ Nullable์€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์€๊ฐ€

Nullable์€ ๊ฐ’์ด ์กด์žฌํ•  ๋•Œ ๊ทธ ๊ฐ’์€ ๋ฌธ์ž์—ด, ์ˆซ์ž, ๋˜๋Š” ๊ฐ์ฒด์ž„์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๊ฐ’์ด ์—†์„ ๋•Œ ์šฐ๋ฆฌ๋Š” null์ด๋‚˜ undefined๋ฅผ ์‚ฌ์šฉํ•˜์ฃ .

ํŒ: ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ nullable types๋กœ ์ž‘์—…ํ•  ๋•Œ strictNullChecks ์˜ต์…˜์„ ์ผœ๋‘์„ธ์š”.

์ด ๋ฐฉ์‹์€ ์ข…์ข… ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๊ดœ์ฐฎ์ง€ ์•Š์€ ๋‘ ๊ฐ€์ง€ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ๊ฐ’์ด null์ด๋‚˜ undefined๊ฐ€ ๋  ์ˆ˜ ์žˆ์„ ๋•Œ. ๊ฒฐ๊ตญ ์ด ๊ฐ’๋“ค์€ ์œ ํšจํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์›์‹œ๊ฐ’์ด๊ณ  ์‚ฌ๋žŒ๋“ค์€ ๋‹ค์–‘ํ•˜๊ฒŒ ์ด ๊ฐ’๋“ค์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  2. ๋” ๋ณต์žกํ•œ ๋กœ์ง์„ ๋งŒ๋“ค๊ณ ์ž ํ•  ๋•Œ x == null์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ๊ท€์ฐฎ์€ ์ผ์ž…๋‹ˆ๋‹ค.

๋งŽ์€ ๊ฒฝ์šฐ์—์„œ Promise์˜ ์ถœ๋ ฅ๊ฐ’์„ ์ œ์–ดํ•˜๊ณ  ์–ด๋–ค ๊ฐ’์„ ๋ฆฌํ„ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ €๋Š” missing๋œ ๋‘ ๊ฐ’์ด ๊ฒฐ๊ตญ ๋ฆฌํ„ด๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜ˆ๊ฒฌํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฌธ์ œ 1๊ณผ 2๋Š” ๋™์ผํ•œ ํ•ด๊ฒฐ๋ฒ•์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. Option type์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์™œ Option์€ too muchํ•œ๊ฐ€

(๋•Œ๋•Œ๋กœ Maybe๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š”) Option ํƒ€์ž…์€ ๋‘ ๊ฐ€์ง€ ๊ฐ€๋Šฅ์„ฑ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ๊ฐ’์ด ์—†๊ฑฐ๋‚˜(None, Nothing) ๊ฐ’์ด ์žˆ๋Š” ๊ฒฝ์šฐ(Some, Just)์ด์ฃ .
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ์ด๋Š” ๊ฐ’์„ ๊ฐ์‹ธ๋Š” ์ƒˆ๋กœ์šด ๊ตฌ์กฐ๋ฅผ ๋„์ž…ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ€๋Šฅํ•œ ์†์„ฑ์„ ์ •์˜ํ•˜๋Š” tag ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

์ด๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ์–ผ๋งˆ๋‚˜ ์—ฌ๋Ÿฌ๋ถ„์ด ๋น ๋ฅด๊ฒŒ Option์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š”์ง€๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

type Option<T> = { tag: 'none' } | { tag: 'some', value: T }

๋ณดํ†ต ์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ํƒ€์ž…์„ ์ •์˜ํ•˜๊ณ  ์œ ์šฉํ•œ ์œ ํ‹ธ์„ ์ œ๊ณตํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

[์ •๋ฆฌ] ์‚ฌ์šฉ์ž ์—์ด์ „ํŠธ(User Agent)

  • ์‚ฌ์šฉ์ž ์—์ด์ „ํŠธ(User Agent) : ์‚ฌ์šฉ์ž์˜ ์‹ ๋ถ„์„ ๋Œ€์‹ ํ•  ์ˆ˜ ์žˆ๋Š” ์†Œํ”„ํŠธ์›จ์–ด๋กœ, ์›น์—์„œ๋Š” ๋ธŒ๋ผ์šฐ์ € ์ข…๋ฅ˜์™€ ๋ฒ„์ „, ์šด์˜์ฒด์ œ ๋“ฑ์„ ํฌํ•จํ•œ๋‹ค.
  • HTTP header๋กœ์„œ๋„ ์‚ฌ์šฉ๋˜์ง€๋งŒ navigator ์ธํ„ฐํŽ˜์ด์Šค์˜ ์†์„ฑ์ด๊ธฐ๋„ ํ•˜๋‹ค.
  • ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ €๋Š” ๋น„์Šทํ•œ ์ง€์› ๋ฒ”์œ„๋ฅผ ๊ฐ–๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋ชจ๋ฐ”์ผ ๋””๋ฐ”์ด์Šค ๊ธฐ๊ธฐ ์—ฌ๋ถ€์™€ OS ๋ฒ„์ „์„ ์ฒดํฌํ•˜๋Š” ์šฉ๋„๊ฐ€ ๋” ๊ฐ•ํ•˜๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-02-04 แ„‹แ…ฉแ„’แ…ฎ 12 14 57

์‚ฌ์šฉ์ž ์—์ด์ „ํŠธ๊ฐ€ ๋ณต์žกํ•ด์ง„ ์ด์œ 

  • 1993๋…„ ๋งˆํฌ ์•ค๋“œ๋ฆฌ์Šจ์€ NCSA Mosaic๋ผ๋Š” ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๊ฐœ๋ฐœ. ์ด๋•Œ๋ถ€ํ„ฐ UA๊ฐ€ ๋“ค์–ด๊ฐ€๋Š”๋ฐ ๋‹น์‹œ ๊ตฌ์กฐ๋Š” ์ œํ’ˆ๋ช…/๋ฒ„์ „์ด์—ˆ๋‹ค.
    • ex.Mosaic/0.9
  • ์ €์ž‘๊ถŒ ๋ฌธ์ œ๋กœ ์•ค๋“œ๋ฆฌ์Šจ์€ ํšŒ์‚ฌ์ด๋ฆ„์„ _๋„ท์Šค์ผ€์ดํ”„ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์ฆˆ_๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  Netscape Navigator๋ผ๋Š” ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋‹ค์‹œ ๊ฐœ๋ฐœํ–ˆ๋‹ค. ์ด ๋„ท์Šค์ผ€์ดํ”„์—๋Š” Mozilla๋ผ๋Š” ์ฝ”๋“œ๋„ค์ž„์ด ์กด์žฌํ–ˆ๊ณ  ์ด๊ฒƒ์ด UA์— ๊ทธ๋Œ€๋กœ ๋ฐ˜์˜๋˜์—ˆ๋‹ค. ์—ฌ๊ธฐ์— ์–ธ์–ด์„ค์ •, ์šด์˜์ฒด์ œ ๋“ฑ์˜ ๋ถ€๊ฐ€์ ์ธ ์ •๋ณด๋ฅผ ๋ง๋ถ™์˜€๊ณ  ๋ฒ„์ „์— ๋”ฐ๋ผ UA ํ˜•์‹์„ ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.
    • ex. `Mozilla/2.02 [fr] (WinNT; I)
  • ์ดํ›„ ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ ์‚ฌ์—์„œ ๋ชจ์ž์ดํฌ ๋ธŒ๋ผ์šฐ์ €์˜ ๋ผ์ด์„ผ์Šค๋ฅผ ๊ตฌ๋งคํ•˜์—ฌ Trident๋ผ๋Š” ์—”์ง„์„ ๋งŒ๋“ค๊ณ  IE๋ฅผ ๊ฐœ๋ฐœํ–ˆ๋‹ค.
  • ๋‹น์‹œ ์›น ์„œ๋ฒ„๋“ค์€ (IE๋„ ํ”„๋ ˆ์ž„ ํƒœ๊ทธ๋ฅผ ์ง€์›ํ–ˆ์Œ์—๋„) UA๋ฅผ ์ฒดํฌํ•˜์—ฌ ๋„ท์Šค์ผ€์ดํ”„๋ผ๋ฉด <frame>์„ ์ง€์›ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ ์‚ฌ๋Š” ์ž์‹ ๋“ค์˜ UA๋ฅผ Mozilla๋กœ ์‹œ์ž‘ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์›น ์„œ๋ฒ„๋ฅผ ์†์ด๊ฒŒ๋” ํ•˜์—ฌ ํ”„๋ ˆ์ž„ ํƒœ๊ทธ๊ฐ€ ์ ์šฉ๋œ HTML ํŒŒ์ผ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.
    • ex. Mozilla/2.0 (compatible; MSIE 3.02; Windows 95) (IE)
  • 1999๋…„ IE๊ฐ€ ์‹œ์žฅ์ ์œ ์œจ 99%๋ฅผ ์ฐจ์ง€ํ•˜๋ฉฐ ๋„ท์Šค์ผ€์ดํ”„ ๊ฐœ๋ฐœ์ž๋Š” ๋„ท์Šค์ผ€์ดํ”„๋ฅผ ์˜คํ”ˆ์†Œ์Šค๋กœ ๋งŒ๋“ค๊ณ  ๋ชจ์งˆ๋ผ ์žฌ๋‹จ์„ ์„ค๋ฆฝํ•œ๋‹ค. ์ด๋•Œ Gecko ์—”์ง„์„ ๊ณต๊ฐœํ•˜์˜€์œผ๋ฉฐ, 2002๋…„ ๋ธŒ๋ผ์šฐ์ € Firefox๋ฅผ ๊ณต๊ฐœํ•œ๋‹ค.
    • ex. Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1
    • Gecko ์—”์ง„ ๋“ฑ์žฅ ์ดํ›„ Mozilla/5.0์€ ๋ฌด์˜๋ฏธํ•œ ์กด์žฌ๊ฐ€ ๋˜์—ˆ์œผ๋‚˜ ์ด์ „ ์ฝ”๋“œ์™€์˜ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•œ๋‹ค. ์ด ๋•Œ๋ถ€ํ„ฐ ๋ชจ๋“  UA ๋ฌธ์ž์—ด์€ Mozilla/5.0๋กœ ์‹œ์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค.
  • Gecko ์—”์ง„์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ €๋“ค์ด ๋‹ค์ˆ˜ ๋“ฑ์žฅํ•˜์ž ์›น ์„œ๋ฒ„๋“ค์€ UA์— Gecko๋ผ๋Š” ๋ฌธ์ž์—ด์ด ํฌํ•จ๋œ ๋ธŒ๋ผ์šฐ์ €์— ๋Œ€ํ•œ ์ง€์›์„ ๊ฐ•ํ™”ํ•œ๋‹ค.
  • 2003๋…„ ์• ํ”Œ์€ Webkit ๊ธฐ๋ฐ˜์˜ ์›น ๋ธŒ๋ผ์šฐ์ € Safari๋ฅผ ๋ฐœํ‘œํ•œ๋‹ค. ์• ํ”Œ๋„ ์ด์ „ ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ์™€ ๋™์ผํ•œ ํ•ด๊ฒฐ์ฑ…์œผ๋กœ Gecko ๊ธฐ๋ฐ˜์˜ ๋ธŒ๋ผ์šฐ์ € ์ƒํƒœ๊ณ„์—์„œ Safari๋ฅผ ์•ˆ์ฐฉ์‹œํ‚ค๊ณ ์ž ํ•œ๋‹ค.
    • ex. Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5
  • ๊ตฌ๊ธ€์˜ Chrome์€ webkit ๊ธฐ๋ฐ˜์˜ ๋ธŒ๋ผ์šฐ์ €์˜€๊ธฐ ๋•Œ๋ฌธ์— Safari์ฒ˜๋Ÿผ ์ธ์‹๋˜๊ธฐ๋ฅผ ์›ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— Safari์˜ UA๋ฅผ ๋”ฐ๋ผํ•˜๋ฉด์„œ Chrome์ด๋ผ๋Š” ๋ฌธ์ž์—ด์„ ์ถ”๊ฐ€ํ•œ๋‹ค.
    • ex. Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13

image

์ถœ์ฒ˜ : https://wormwlrm.github.io/2021/10/11/Why-User-Agent-string-is-so-complex.html


์ฐธ๊ณ 

[๋ฒˆ์—ญ] ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์‚ฌ์žฅ๋˜์—ˆ๋Š”๊ฐ€? ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์ด ์ด์–ด๋ฐ›์€ ์ด์œ ์— ๋Œ€ํ•ด

๋ถ€์ œ : ํŽ˜์ด์Šค๋ถ์ด ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์„ ํƒํ•œ ์ด์œ 
์›๋ฌธ <Is offset pagination dead? Why cursor pagination is taking over>

ํŽ˜์ด์Šค๋ถ ๊ฐœ๋ฐœ์ž ํŽ˜์ด์ง€๋Š” ์ด๋ ‡๊ฒŒ ๋งํ•ฉ๋‹ˆ๋‹ค.

"์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๊ฐ€์žฅ ํšจ์œจ์ ์ธ ํŽ˜์ด์ง• ๊ธฐ๋ฒ•์ด๊ณ  ๊ฐ€๋Šฅํ•œ ์ปค์„œ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค."

๊ทธ๋ ‡๋‹ค๋ฉด ํŽ˜์ด์ง€๋„ค์ด์…˜์ด๋ž€ ๋ฌด์—‡์ผ๊นŒ์š”?

ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๋ฐ์ดํ„ฐ ์ง‘ํ•ฉ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค. ์ฑ…์˜ ํŽ˜์ด์ง€๋“ค๊ณผ ๊ฐ™์ฃ .

์›น์‚ฌ์ดํŠธ์—์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ตฌํ˜„ํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ์ฃผ๋œ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์–ด๋–ค ๋ฐฉ๋ฒ•์ด ๋” ์ข‹์€ ๊ฑธ๊นŒ์š”? ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ด…์‹œ๋‹ค.

์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜

์ด ๋ฐฉ๋ฒ•์€ ์ˆ˜์‹ญ ๋…„ ๋™์•ˆ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด OFFSET ๊ฐ’์„ ๊ฐ€์ง€๋Š” SQL ์ฟผ๋ฆฌ๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

SELECT * FROM table
ORDER BY timestamp
OFFSET 10
LIMIT 5

๋ช…์‹œ์ ์œผ๋กœ ํŽ˜์ด์ง€ ์ˆ˜๋ฅผ ๋ณด์—ฌ์ฃผ์–ด ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋ก ํŠธ์—”๋“œ์™€ ํ•จ๊ป˜ ์Œ์„ ์ด๋ฃจ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ๋งˆ์น˜ ์ฑ…์˜ ํŽ˜์ด์ง€๋ฅผ ๋„˜๊ธฐ๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜์ฃ .

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜

์ด ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด (๋ณดํ†ต ํƒ€์ž„์Šคํƒฌํ”„๋ฅผ ๋น„๊ตํ•˜๋Š”) <, >์™€ ๊ฐ™์€ ๋น„๊ต ์—ฐ์‚ฐ์ž๋ฅผ ํฌํ•จํ•˜๋Š” SQL ์ฟผ๋ฆฌ๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

SELECT * FROM table 
WHERE cursor > timestamp 
ORDER BY timestamp 
LIMIT 5

์—ฌ๋Ÿฌ๋ถ„์ด ๋งŽ์€ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ์›น์‚ฌ์ดํŠธ(ํŽ˜์ด์Šค๋ถ, ์Šฌ๋ž™, ํŠธ์œ„ํ„ฐ ๋“ฑ๊ณผ ๊ฐ™์€)๋ฅผ ๋ณด๊ณ  ์žˆ๋‹ค๋ฉด ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์ด ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ํ”„๋ก ํŠธ์—”๋“œ์— ๋ฌดํ•œ ์Šคํฌ๋กค ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ์„ ํ˜ธ๋˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๋ฌดํ•œ ์Šคํฌ๋กค์€ ์—ฌ๋Ÿฌ๋ถ„์ด ํŽ˜์ด์Šค๋ถ ํ”ผ๋“œ๋ฅผ ๋‚ด๋ฆฌ๋‹ค๊ฐ€ ๋ฐ”๋‹ฅ์— ๋‹ค๋‹ค๋ž์„ ๋•Œ, ๋” ๋งŽ์€ ํ”ผ๋“œ๋“ค์ด ์–ด๋–ป๊ฒŒ ๋” ๋‚˜ํƒ€๋‚ฌ๋Š”์ง€ ์ƒ๊ฐํ•ด๋ณด์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

infinite scroll

๊ทธ๋Ÿฐ๋ฐ ์™œ ์ด๋ ‡๊ฒŒ ๋งŽ์€ ๊ธฐ์—…๋“ค์ด ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜์—์„œ ์ปค์„œ ๊ธฐ๋ฐ˜์œผ๋กœ ์ „ํ™˜ํ•œ ๊ฒƒ์ผ๊นŒ์š”?

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์˜ ์žฅ์ 

1. ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ์˜ ์ œ๊ณต์ด ๋›ฐ์–ด๋‚˜๋‹ค

์•„๋งˆ๋„ ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์˜ ๊ฐ€์žฅ ํฐ ์žฅ์ ์€ ํšจ์œจ์ ์œผ๋กœ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์ปค์„œ๋“ค์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ •์ ์œผ๋กœ ์œ ์ง€ํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . ์ฆ‰, ์•„์ดํ…œ๋“ค์ด๋‚˜ ํ–‰๋“ค์ด ์ถ”๊ฐ€๋˜๊ณ  ์‚ญ์ œ๋œ๋‹ค ํ•ด๋„ ๊ฐ ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋“ค์ด ์—ฌ์ „ํžˆ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋กœ๋“œ๋œ๋‹ค๋Š” ๊ฒ๋‹ˆ๋‹ค.

์ง€๋‚œ 10๋…„๊ฐ„ real-time ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ•ด์ผ ์†์—์„œ, ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋ฐฉ๋ฒ•์€ ํฐ ํƒ„๋ ฅ์„ ์–ป๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ๋งŒ์•ฝ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ณ ์ •๋œ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ๋‘ ๊ฐ€์ง€ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ฐ์ดํ„ฐ๊ฐ€ ์Šคํ‚ต๋จ
  • ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ 2๋ฒˆ ๋ฐ˜ํ™˜๋จ

์ด ๋‘ ๊ฐ€์ง€ ์ƒํ™ฉ์— ๋Œ€ํ•ด์„œ ์ข€ ๋” ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

2. ์Šคํ‚ต๋˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค

๋ฐ์ดํ„ฐ๊ฐ€ ์Šคํ‚ต๋˜๋Š” ์‹ค์‹œ๊ฐ„ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ํŽ˜์ด์Šค๋ถ ๋‰ด์Šคํ”ผ๋“œ์— ์ฒ˜์Œ ๋„๋‹ฌํ–ˆ์„ ๋•Œ ์—ฌ๋Ÿฌ๋ถ„์€ ์นœ๊ตฌ๋“ค์ด ์ž‘์„ฑํ•œ ์ตœ๊ทผ 5๊ฐœ์˜ ๊ฒŒ์‹œ๋ฌผ์„ ๋ฐ”๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์™•์ขŒ์˜ ๊ฒŒ์ž„ ๋ฐˆ
  • ์ƒ˜์ด ์ˆ ์— ์ทจํ•ด ์˜ฌ๋ฆฐ ์ฐฝํ”ผํ•œ ์‚ฌ์ง„๋“ค...
  • ์ •์น˜์  ์ฃผ์žฅ

... ๋“ฑ๋“ฑ. ๋‹ค์Œ ํŽ˜์ด์ง€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•  ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒˆ๋กœ์šด ๊ฒŒ์‹œ๋ฌผ์ด ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค.

  • ์นด๋ Œ ์ด๋ชจ์˜ ๊ณ ์–‘์ด ์‚ฌ์ง„
  • ์นœ๊ตฌ ์˜ฌ๋ฆฌ๋น„์•„์˜ ํ˜ธ์ฃผ ์—ฌํ–‰ ์ถ”์–ตํŒ”์ด ์‚ฌ์ง„๋“ค
  • ์˜คํ”„๋ผ์˜ ์ธ์ƒ์ ์ธ ์ธ์šฉ๊ตฌ๋“ค

์—ฌ๋Ÿฌ๋ถ„์€ ์œ„์˜ ๋‘ ํŽ˜์ด์ง€๋ฅผ ๊ธฐ๋Œ€ํ–ˆ๊ฒ ์ง€๋งŒ ์—ฌ๋Ÿฌ๋ถ„์ด ํŽ˜์ด์ง€ 1์„ ๋ณด๊ณ  ์žˆ๋Š” ๋™์•ˆ ์ƒ˜์ด ์ž ๊ณผ ์ˆ ์—์„œ ๊นจ์–ด ์–ด์ ฏ๋ฐค์— ์˜ฌ๋ฆฐ ์ž์‹ ์˜ ์‚ฌ์ง„์„ ์ง€์šฐ๊ธฐ๋กœ ํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์ด ๋” ๋งŽ์€ ๊ฒŒ์‹œ๋ฌผ์„ ๋กœ๋“œํ•˜๊ธฐ ์œ„ํ•ด ์Šคํฌ๋กค ํ–ˆ์„ ๋•Œ, ๊ฐ‘์ž๊ธฐ ์—ฌ๋Ÿฌ๋ถ„์ด ๋ณด๋Š” ํŽ˜์ด์ง€ 2๋Š” ์ด์™€ ๊ฐ™์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ž ์‹œ๋งŒ! ๊ณ ์–‘์ด ์‚ฌ์ง„๋“ค์€ ์–ด๋”” ๊ฐ„๊ฑธ๊นŒ์š”?

๋ถˆํ–‰ํ•˜๊ฒŒ๋„ ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ˆ˜์ •๋œ ๊ฒƒ์— ๋Œ€ํ•ด ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ ๋‹ค์Œ 5๊ฐœ์˜ ๊ฒŒ์‹œ๋ฌผ์— ๋Œ€ํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆด ๋ฟ์ด์ฃ . ์ด 5๊ฐœ์˜ ๊ฒŒ์‹œ๋ฌผ์€ ์—ฌ์ „ํžˆ 5์˜ ์˜คํ”„์…‹์— ์œ„์น˜ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ๋งค๋ฒˆ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฟผ๋ฆฌ๋  ๊ฒ๋‹ˆ๋‹ค.

SELECT * FROM table ORDER BY timestamp OFFSET  0 LIMIT 5
SELECT * FROM table ORDER BY timestamp OFFSET  5 LIMIT 5
SELECT * FROM table ORDER BY timestamp OFFSET 10 LIMIT 5
SELECT * FROM table ORDER BY timestamp OFFSET 15 LIMIT 5
...

๊ฐ ๋ผ์ธ์€ ํŽ˜์ด์ง€ 1, ํŽ˜์ด์ง€ 2, ํŽ˜์ด์ง€ 3 ๋“ฑ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ด๋Š” ์—ฌ๋Ÿฌ๋ถ„์ด ๊ท€์—ฌ์šด ๊ณ ์–‘์ด ์‚ฌ์ง„๋“ค์„ ๋ณผ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค! ๊ทธ๋ฆฌ๊ณ  ๋”์šฑ ์•ˆํƒ€๊น๊ฒŒ๋„ ์—ฌ๋Ÿฌ๋ถ„์€ ๊ณ ์–‘์ด ์‚ฌ์ง„์„ ์žƒ์–ด๋ฒ„๋ ธ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜๋„ ์—†๋‹ค๋Š” ๊ฑฐ์ฃ . ์ด๊ฒŒ ๋‹ค ์ƒ˜ ๋•Œ๋ฌธ์ด์˜ˆ์š”!

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์ธ๋ฑ์Šค๋กœ ์‚ฌ์šฉ๋˜๋Š” ์˜คํ”„์…‹ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ๋ฐ์ดํ„ฐ์…‹์˜ ํŠน์ • ๋ ˆ์ฝ”๋“œ์˜ ํฌ์ธํ„ฐ ์—ญํ• ์„ ํ•˜๋Š” ์ปค์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋งˆ์ง€๋ง‰ ํŽ˜์ด์ง€๊ฐ€ ์ค‘๋‹จ๋œ ์œ„์น˜๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด ์ปค์„œ๋Š” September 12, 4:02 PM ํƒ€์ž„์Šคํƒฌํ”„๋ฅผ ๊ฐ€์ง€๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฐ›์•˜๋‹ค๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—๊ฒŒ ์•Œ๋ ค์ฃผ์–ด ํ•ด๋‹น ํƒ€์ž„์Šคํƒฌํ”„ ์ด์ „์˜ 5๊ฐœ์˜ ๊ฒŒ์‹œ๋ฌผ์„ ๋ฐ˜ํ™˜๋ฐ›์Šต๋‹ˆ๋‹ค.

SELECT * FROM table WHERE cursor > timestamp ORDER BY timestamp LIMIT 5

์ด ๋ฐฉ๋ฒ•์€ ์ƒ˜์ด ๋‘ ์žฅ์˜ ์‚ฌ์ง„์„ ์ง€์šด ๊ฒƒ๊ณผ ์ƒ๊ด€์—†์ด ๊ณ ์–‘์ด ์‚ฌ์ง„์ด ํฌํ•จ๋œ ์ด์ „ ๋ฐ์ดํ„ฐ๋“ค์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒ๋‹ˆ๋‹ค. ์ •๋ง ๋‹คํ–‰์ด์ฃ .

3. ์ค‘๋ณต ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค

๋‘ ๋ฒˆ์งธ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ํŽ˜์ด์ง€ 1์„ ๋ณด๊ณ  ์žˆ๊ณ  ์ƒ˜์€ ์—ฌ์ „ํžˆ ์ˆ ์— ์ทจํ•ด ์‚ฌ์ง„์„ ๋” ์˜ฌ๋ฆฐ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ํŽ˜์ด์ง€ 2๋ฅผ ๋ณด๋ ค๊ณ  ํ•  ๋•Œ ์˜คํ”„์…‹์ด ์ค‘๋ณต๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ €๋„ ์ทจํ•œ ๊ฑธ๊นŒ์š”? ์•„๋‹ˆ๋ฉด ์ด๋ชจ๊ฐ€ ์ทจํ•œ ๊ฑธ๊นŒ์š”?

์•„๋‹ˆ์š”. ์˜คํ”„์…‹์ด 5๊ฐ€ ์•„๋‹Œ 6์—์„œ ์‹œ์ž‘๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ ์—ฌ๋Ÿฌ๋ถ„์€ ๊ฒŒ์‹œ๋ฌผ 1๊ฐœ๊ฐ€ ์ถ”๊ฐ€๋จ์— ๋”ฐ๋ผ ๋ณด์—ฌ์ง€๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์ค‘๋ณต๋˜๋ฒ„๋ฆฐ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ์ƒํ™ฉ์€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ ค์ฃผ๊ณ  ์‹ค์ œ๋กœ๋Š” ์ž˜ ์ž‘๋™ํ•˜๊ณ  ์žˆ์ง€๋งŒ ๋ถˆ์•ˆ์ •ํ•˜๊ฒŒ ๋ณด์ด๊ธฐ ๋•Œ๋ฌธ์— ์•„์ฃผ ์ตœ์•…์˜ ์‹œ๋‚˜๋ฆฌ์˜ค์ž…๋‹ˆ๋‹ค.

4. ํšจ์œจ์ ์œผ๋กœ ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฌ๋‹ค

์—ฌ๋Ÿฌ๋ถ„์€ SQL์˜ OFFSET ์ ˆ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•˜์‹  ์ ์ด ์žˆ๋‚˜์š”? ์ € ์—ญ์‹œ ๊ทธ๋ ‡์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ปค์„œ ๊ธฐ๋ฐ˜์ด ๊ฐ€์žฅ ํšจ์œจ์ ์ธ ํŽ˜์ด์ง€๋„ค์ด์…˜์ด๋ผ๊ณ  ํŽ˜์ด์Šค๋ถ์—์„œ ์ฃผ์žฅํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋ง์ด์ฃ .

์ œ๊ฐ€ ์ฐพ์•„๋ณธ ๊ฒƒ์€ ์ €๋ฅผ ๋†€๋ผ๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์˜คํ”„์…‹์€ ๋‹จ์ˆœํžˆ ๋ ˆ์ฝ”๋“œ๋ฅผ ์„ ํƒํ•˜๊ธฐ ์ „์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ๊ฑด๋„ˆ๋›ธ ๋ ˆ์ฝ”๋“œ ์ˆ˜์ž…๋‹ˆ๋‹ค.

์ฆ‰, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์š”์ฒญํ•œ ๋‹ค์Œ ๋ฐ์ดํ„ฐ์…‹์„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ด์ „์— ์ œ๊ณตํ–ˆ๋˜ ๋ฐ์ดํ„ฐ๋“ค์„ ๋ชจ๋‘ ์Šค์บ”ํ•œ๋‹ค๋Š” ๊ฒƒ์ธ๋ฐ์š”. ์˜คํ”„์…‹ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•  ์ˆ˜๋ก ์ด๋Š” ํฐ ๋ฌธ์ œ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์•ฝ 730๋งŒ ๊ฐœ์˜ ๋ ˆ์ฝ”๋“œ๋กœ ๊ตฌ์„ฑ๋œ ๋ฐ์ดํ„ฐ์…‹์—์„œ ์ปค์„œ ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ์™€ ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ๋ฅผ ๋ชจ๋‘ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์™„์ „ํžˆ ๊ณ„์‚ฐ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

pagination time efficiency graph

์—ฌ๊ธฐ์„œ ์‹ค์ œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์œผ๋กœ ํ™•๋Œ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ 700๋งŒ ๋ฒˆ์งธ ํ–‰์„ ํ‘œ์‹œํ•˜๋Š” ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ด๋ณธ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ฃ .

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์‚ฌ์šฉ์ž๊ฐ€ ๋‹ค์Œ ๋˜๋Š” ์ด์ „ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋˜๊ธฐ๊นŒ์ง€ ์•ฝ 0.18์ดˆ๊ฐ€ ์†Œ์š”๋ฉ๋‹ˆ๋‹ค.
์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๋™์ผํ•œ ๋™์ž‘์ž„์—๋„ 13์ดˆ๊ฐ€ ๊ฑธ๋ฆฌ๋Š” ๊ฒ๋‹ˆ๋‹ค! ์ด๋Š” ๊ฐ ํŽ˜์ด์ง€๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๋Š” ๋ฐ 13์ดˆ๊ฐ€ ๊ฑธ๋ฆฐ๋‹ค๋Š” ๊ฑฐ๊ณ  ์ปดํ“จํŒ… ์„ธ๊ณ„์—์„œ๋Š” ์˜์›ํžˆ ๋กœ๋“œํ•œ๋‹ค๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ฃ !

์‹ค์ œ๋กœ๋Š” ์—ฌ๋Ÿฌ๋ถ„๋“ค์˜ ์‚ฌ์šฉ์ž๊ฐ€ 13์ดˆ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ๋ณด๋‹ค๋Š” ์‚ฌ์ดํŠธ์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ณ  ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ ์ด๋™ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋” ๋†’์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ๋กœ 13์ดˆ๋ฅผ ๊ธฐ๋‹ค๋ ค์„œ ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•  ํ™•๋ฅ ์€ ์–ผ๋งˆ๋‚˜ ๋ ๊นŒ์š”? ๊ฐ€๋Šฅ์€ ํ•˜๊ฒ ์ง€๋งŒ, ์•„๋งˆ ๊ฑฐ์˜ ๊ทธ๋Ÿด ํ™•๋ฅ ์€ ํฌ๋ฐ•ํ•˜๋‹ค๊ณ  ๋ง์”€๋“œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ 700๋งŒ ๋ฒˆ์งธ ๋ ˆ์ฝ”๋“œ ์ด์ „์—๋„ ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ linearํ•œ O(N), ๋” ๊ตฌ์ฒด์ ์œผ๋กœ๋Š” O(offset+limit)์„ ๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž์˜ UX๋Š” ๊ฐ์†Œํ•˜๊ธฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ O(1), ๊ตฌ์ฒด์ ์œผ๋กœ๋Š” O(limit)์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

์œ„ ๊ทธ๋ž˜ํ”„์—์„œ๋„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์ด ํ”ผ๋“œ๋ฅผ ๊ณ„์† ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐˆ์ˆ˜๋ก ํŽ˜์ด์ง€ ๋กœ๋”ฉ์ด ๋Š๋ ค์ง€๋Š” ์ด์œ ์— ๋Œ€ํ•ด ๊ถ๊ธˆํ•œ ์ ์ด ์žˆ์—ˆ๋‹ค๋ฉด, ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์˜ ๋น„ํšจ์œจ์„ฑ์„ ๊ฒฝํ—˜ํ•ด๋ดค๊ธฐ ๋•Œ๋ฌธ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์˜ ๋‹จ์ 

๊ทธ๋ ‡๋‹ค๋ฉด ์ •๋ง ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์‚ฌ์žฅ๋œ ๊ฒƒ์ผ๊นŒ์š”?

์Œ, ๊ผญ ๊ทธ๋ ‡์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ์นœ๊ตฌ๋“ค์„ ์ฒ ์•ผ์— ์ดˆ๋Œ€ํ•˜๊ธฐ ์ „์— ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜์ด ๋” ์ ํ•ฉํ•œ ๊ฒฝ์šฐ๋ฅผ ๋ช‡ ๊ฐ€์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํŽ˜์ด์Šค๋ถ์€ ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ฐ€๋Šฅํ•œ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•œ๋‹ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์–ด๋–ค ์ƒํ™ฉ์—์„œ๋Š” ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฑฐ๋‚˜, ์ปค์„œ ๊ธฐ๋ฐ˜์ด ํ˜„์‹ค์ ์ด์ง€ ์•Š์„ ๋•Œ๋„ ๋ถ„๋ช…ํžˆ ์žˆ์Šต๋‹ˆ๋‹ค.

1. ์ •๋ ฌ ๊ธฐ๋Šฅ์ด ์ œํ•œ๋œ๋‹ค

์—ฌ๋Ÿฌ๋ถ„์ด ์„ฑ๊ณผ ์ด๋ฆ„์œผ๋กœ ์ •๋ ฌํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ € ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค. ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์š”๊ตฌ์‚ฌํ•ญ์ด ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ ์‚ฌ์šฉํ•  ๊ณ ์œ ํ•œ ์ˆœ์ฐจ ์—ด์ด๊ธฐ ๋•Œ๋ฌธ์— ์ปค์„œ ๊ธฐ๋ฐ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปค์„œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ ์ง‘ํ•ฉ์˜ ํŠน์ • ์œ„์น˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ , ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ ๋‹ค์Œ์— ๋ ˆ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์„ธ์š”.

์ฆ‰ ๋Œ€๋ถ€๋ถ„์˜ ์ปค์„œ ๊ตฌํ˜„์€ ํƒ€์ž„์Šคํƒฌํ”„ ์—ด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. ํ™•์‹คํ•˜๊ฒŒ ์ˆœ์ฐจ์ ์ด๊ณ  ์‹œ๊ฐ„์„ ์„ธ๋ถ„ํ™”๋œ ์ˆ˜์ค€์œผ๋กœ ์ถ”์ ํ•˜๋ฉด ํ•ด๋‹น ์—ด์ด ๊ณ ์œ ํ•˜๋‹ค๊ณ  ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๊ฐ€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฆ„์€ ์ˆœ์ฐจ์ ์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ณ ์œ ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ฃผ์œ„์— ๋™๋ช…์ด์ธ๋“ค์„ ๋งŽ์ด ๋ดค์œผ๋‹ˆ๊นŒ์š”. ๊ทธ๋ž˜์„œ ์ปค์„œ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌํ˜•ํ•˜๊ฒŒ ๋˜๋ฉด ๋ฐ์ดํ„ฐ์˜ ์Šคํ‚ต์ด๋‚˜ ์ค‘๋ณต๋œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๋Š” ๋ฌธ์ œ์— ๋ด‰์ฐฉํ•˜๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ์ž ์ •๋ ฌ์„ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด ์‚ฌ์šฉ์ž ์•„์ด๋””๋‚˜ ์ด๋ฉ”์ผ๊ณผ ๊ฐ™์ด ์ˆœ์ฐจ์ ์ด๋ฉฐ ๊ณ ์œ ํ•œ ์—ด์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ด๋ฆ„์ด๋‚˜ ์„ฑ์œผ๋กœ ์ •๋ ฌํ•ด์•ผ ํ•  ๋•Œ๋Š” ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์ด ์ตœ์„ ์˜ ๋ฐฉ๋ฒ•์ด ์•„๋‹ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฆ„๊ณผ ์„ฑ์„ ์ด์–ด์„œ ๊ณ ์œ ํ•œ ์ปฌ๋Ÿผ์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜๋„ ์žˆ๊ณ , ์—ฌ๋Ÿฌ ํŠœํ”Œ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ณ ์œ ํ•œ ์ปฌ๋Ÿผ์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์˜คํ”„์…‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋Š๋ ค์งˆ ์ •๋„๋กœ ์†๋„๊ฐ€ ๊ฐ์†Œํ•ฉ๋‹ˆ๋‹ค. SQL ๋ฌธ์˜ ์—ฐ๊ฒฐ์ด๋‚˜ ํŠœํ”Œ์„ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ด O(N), ๊ตฌ์ฒด์ ์œผ๋กœ๋Š” O(์ „์ฒด ๋ฐ์ดํ„ฐ์…‹)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์‚ฌ์‹ค ์ฒซ ๋ฒˆ์งธ ํŽ˜์ด์ง€๊ฐ€ ๊ฐ€์žฅ ๋Š๋ฆฌ๊ฒŒ ๋กœ๋“œ๋  ๊ฒ๋‹ˆ๋‹ค. ์ด์ƒํ•˜๊ณ  ์ง๊ด€์ ์ด์ง€๋Š” ์•Š์ง€๋งŒ SELECT ๋ฌธ์€ ๋‚˜์•„๊ฐˆ์ˆ˜๋ก ๋” ๋งŽ์€ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ œ์™ธํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ์ด ์ด์Šˆ๋ฅผ ํ•ด๊ฒฐํ•  ๋ช‡ ๊ฐ€์ง€ ํŠธ๋ฆญ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ฐธ๊ณ  : ์ด ํ˜„์ƒ์— ๋Œ€ํ•ด์„œ

2. ์ปค์„œ๋Š” ๊ตฌํ˜„ํ•˜๊ธฐ ๋” ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ๋‹ค

์ปค์„œ๊ฐ€ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•˜๊ธฐ ์–ด๋ ค์šด ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ์˜คํ”„์…‹์€ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ตฌํ˜„ํ•˜๋Š” ๋น ๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฐพ๊ณ  ์žˆ๋‹ค๋ฉด ์˜คํ”„์…‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๋ฉด์š”. ํ•„์š”ํ•˜์ง€ ์•Š์€๋ฐ ์ผ์„ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.

์ง์ ‘ ์ปค์„œ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณธ ๊ฒฐ๊ณผ, 90% ์‚ฌ๋ก€์—์„œ ์ปค์„œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๊ทธ๋ฆฌ ์–ด๋ ต์ง€๋Š” ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์˜คํ”„์…‹๋ณด๋‹ค๋Š” ๊ณ ๋ คํ•ด์•ผ ํ•  ์—ฃ์ง€ ์ผ€์ด์Šค๊ฐ€ ํ›จ์”ฌ ๋” ๋งŽ์•˜์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋งํ•˜์ž๋ฉด, ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ต์ง€๋Š” ์•Š์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ ์˜คํ”„์…‹๋ณด๋‹ค๋Š” ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ปค์„œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๋” ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„, ์—ฌ๋Ÿฌ๋ถ„์˜ ํšŒ์‚ฌ ๋˜๋Š” PM๋“ค์ด ํ•ด์•ผ ํ•˜๋Š” trade-off์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

3. ๋ฌดํ•œ ์Šคํฌ๋กค์€ ์ค‘๋…๋  ์ˆ˜ ์žˆ๋‹ค

์ด๊ฒƒ์€ ์ •ํ™•ํžˆ ๋งํ•˜์ž๋ฉด ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜์—์„œ๋„ ๋ฌดํ•œ ์Šคํฌ๋กค์ด ๊ตฌํ˜„์€ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์˜ ์ด์Šˆ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ปค์„œ์˜ ์‚ฌ์šฉ์ด ์ฆ๊ฐ€ํ•˜๋ฉด์„œ ์•ž์„œ ์–ธ๊ธ‰ํ•œ ๋ฐ์ดํ„ฐ ์ค‘๋ณต ๋ฌธ์ œ ์—†์ด ํšจ์œจ์ ์œผ๋กœ ๋ฌดํ•œ ์Šคํฌ๋กค์˜ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์‹œ๊ฐ„ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ฌดํ•œ ์Šคํฌ๋กค์˜ ๋นˆ๋„๊ฐ€ ์ฆ๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฌดํ•œ ์Šคํฌ๋กค์€ ์‚ฌ์šฉ์ž๊ฐ€ ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ๋ฒˆ์— ๋ณผ ์ˆ˜ ์žˆ๋Š” ํŽธ๋ฆฌํ•œ UI์ด๊ธฐ๋Š” ํ•˜์ง€๋งŒ, ์‚ฌ์šฉ์ž๊ฐ€ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ๋ณด๊ธฐ ์œ„ํ•ด ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋Š” ์˜์‹์ ์ธ ๊ฒฐ์ • ๊ณผ์ •์ด ์‚ฌ๋ผ์ง€๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋” ๋งŽ์€ ๊ฒŒ์‹œ๋ฌผ์„ ๋กœ๋“œํ•˜๊ณ  ์žˆ์Œ์„ ์•Œ์•„์ฑ„์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์–ด ๋”์šฑ ์ค‘๋…์„ฑ์ด ๋†’์€ ๊ฒฝํ—˜์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ปค์„œ์˜ ๊ตฌํ˜„

๋ชจ๋“  ์—ด์„ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•  ๋•Œ ์•ฝ๊ฐ„์˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋”๋ผ๋„ ์‹ค๊ธฐ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ๋Š” ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜๋งŒํผ ์ข‹์€ ๊ฒƒ์ด ์—†์Šต๋‹ˆ๋‹ค.

์™œ ํŽ˜์ด์Šค๋ถ ๊ฐ™์€ ๊ธฐ์—…๋“ค์ด ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์— ๋Œ€ํ•ด ๊ณผ๊ฐํ•œ ๋ฐœ์–ธ์„ ํ•˜๋Š” ์ง€ ์ดํ•ด๊ฐ€ ๋˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์—ฌ๋Ÿฌ๋ถ„์˜ ์›น์‚ฌ์ดํŠธ๊ฐ€ ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ํšจ๊ณผ๋“ค์ด ์žˆ๋Š”์ง€ ์ž๋ฌธํ•ด๋ณผ ๋•Œ ์ž…๋‹ˆ๋‹ค.

์ปค์„œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค๋Š” ํ™•์‹ ์ด ๋“ ๋‹ค๋ฉด, ์›น์‚ฌ์ดํŠธ์—์„œ ์ปค์„œ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์Šคํƒ€ํŠธ์—… ๊ธฐ์‚ฌ๋ฅผ ์ฝ์–ด๋ณด์„ธ์š”!

์ถ•ํ•˜ํ•ฉ๋‹ˆ๋‹ค!! ๐Ÿ˜Ž ๋“œ๋””์–ด ๋๊นŒ์ง€ ๋‹ค ์ฝ์œผ์…จ์–ด์š”. ์ด ์•„ํ‹ฐํด์ด ๋งˆ์Œ์— ๋“œ์…จ๋‹ค๋ฉด ๐Ÿ‘Œ, ์•„๋ž˜ clap ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š” ๐Ÿ‘. ์ €์—๊ฒŒ ํฐ ํž˜์ด ๋  ๊ฒ๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์ด ์•„ํ‹ฐํด์„ ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ต๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] ์—ฌ๋Ÿฌ๋ถ„์ด ์ง€๊ธˆ๋ถ€ํ„ฐ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” JavaScript ES12 ๊ธฐ๋Šฅ Top5

์›๋ฌธ : Top 5 JavaScript ES12 Features You Should Start Using Now

ECMAScript 2021(12๋ฒˆ์งธ ๋ฒ„์ „)์ด ์ด์ œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ๊ณผ ๋ฌธ๋ฒ• ๊ฐœ์„  ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. 2021๋…„ 6์›” 22์ผ ECMA ๊ตญ์ œ๊ธฐ๊ตฌ์— ์˜ํ•ด ๋ช…์„ธ๊ฐ€ ํ™•์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํ–ฅ์ƒ์€ ๊ฐœ๋ฐœ์ž์˜ ์ž‘์—…์„ ์‰ฝ๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์—ฌ JavaScript๋ฅผ ๋”์šฑ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

ECMAScript 2021์—์„œ ์ œ๊ณต๋˜๋Š” Top 5 ๊ธฐ๋Šฅ์„ ์ž์„ธํ•˜๊ฒŒ ์„ค๋ช…๋“œ๋ฆดํ…Œ๋‹ˆ, ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์—์„œ ํ™œ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ๋ถ„์ด ๋” ์ž˜ JavaScript๋ฅผ ์‚ฌ์šฉํ•˜์‹œ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋น„๊ธฐ๋„ˆ์™€ ์ˆ™๋ จ๋œ ๊ฐœ๋ฐœ์ž ๋ชจ๋‘ ์ด ๊ธ€์—์„œ ๋งŽ์€ ๊ฒƒ์„ ์–ป์–ด๊ฐ€์‹ค ์ˆ˜ ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค.

ECMAScript 2021 ์—…๋ฐ์ดํŠธ์—์„œ ์ œ๊ณต๋˜๋Š” Top 5 ๊ธฐ๋Šฅ

  1. ์ˆซ์ž ๊ตฌ๋ถ„์ž (Numeric Separators)
  2. String.prototype.replaceAll
  3. Promise.any()์™€ AggregateError
  4. ๋…ผ๋ฆฌ ํ• ๋‹น ์—ฐ์‚ฐ์ž (Logical Assignment Operators)
  5. Private ํด๋ž˜์Šค ๋ฉ”์†Œ๋“œ์™€ ์ ‘๊ทผ์ž

1. ์ˆซ์ž ๊ตฌ๋ถ„์ž (Numeric Separators)

์ˆซ์ž ๊ตฌ๋ถ„์ž๋Š” ๋ฆฌํ„ฐ๋Ÿด ์ˆซ์ž๋“ค ์‚ฌ์ด์— ์–ธ๋”์Šค์ฝ”์–ด(_)๋ฅผ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ ๋”์šฑ ๊ฐ€๋…์„ฑ์„ ๋†’์—ฌ์ค๋‹ˆ๋‹ค. ์–ธ๋”์Šค์ฝ”์–ด ๊ธฐํ˜ธ๋Š” ๊ฐ ํŒŒ์ผ๋“ค์ด ํŒŒ์‹ฑ๋  ๋•Œ ์ž๋™์œผ๋กœ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค.์ˆซ์ž ๊ตฌ๋ถ„์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ ์‹ถ๋‹ค๋ฉด ์•„๋ž˜ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

// ์ฒœ ๋‹จ์œ„๋กœ ๊ตฌ๋ถ„๋œ ์‹ญ์ง„์ˆ˜ ์ •์ˆ˜ ๋ฆฌํ„ฐ๋Ÿด
let n1 = 1_000_000_000;
console.log(n1); // ์ถœ๋ ฅ : 1000000000

// ์ฒœ ๋‹จ์œ„๋กœ ๊ตฌ๋ถ„๋œ ์‹ญ์ง„์ˆ˜ ๋ฆฌํ„ฐ๋Ÿด
let n2 = 1_000_000_000.150_200
console.log(n2); // ์ถœ๋ ฅ : 1000000000.1502

// ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๊ตฌ๋ถ„๋œ 16์ง„์ˆ˜ ์ •์ˆ˜ ๋ฆฌํ„ฐ๋Ÿด
let n3 = 0x95_65_98_FA_A9
console.log(n3); // ์ถœ๋ ฅ : 641654651561

// ์ฒœ ๋‹จ์œ„๋กœ ๊ตฌ๋ถ„๋œ BigInt ๋ฆฌํ„ฐ๋Ÿด
let n4 = 155_326_458_156_248_168_514n
console.log(n4); // ์ถœ๋ ฅ : 155326458156248168514n

2. String.prototype.replaceAll

String ํ”„๋กœํ† ํƒ€์ž…์˜ replaceAll() ํ•จ์ˆ˜๋Š” ์ •๊ทœ์‹ ์—†์ด ๋ชจ๋“  ์„œ๋ธŒ์ŠคํŠธ๋ง์„ ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋ฌธ์ž์—ด์—์„œ replace()๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค๋ฉด, ์ผ์น˜ํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ์ธ์Šคํ„ด์Šค๋งŒ์„ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ replaceAll()์€ ์ผ์น˜ํ•˜๋Š” ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๋ฅผ ๋Œ€์ฒดํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

// ๋ณ€์ˆ˜ ์„ ์–ธ ๋ฐ ๊ฐ’ ์ €์žฅ
const orgStr = 'JavaScript, often abbreviated as JS, is a programming language that conforms to the ECMAScript specification. JavaScript is high-level, often just-in-time compiled and multi-paradigm.';

// replace()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์Šคํ„ด์Šค ํ•˜๋‚˜ ๋Œ€์ฒด
let newStr = orgStr.replace('JavaScript', 'TypeScript');
console.log(newStr);

// replaceAll()์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค ๋Œ€์ฒด
let newStr2 = orgStr.replaceAll('JavaScript', 'TypeScript');
console.log(newStr2);

3. Promise.any()์™€ AggregateError

Promise.any๋Š” Promise.all()๊ณผ ๋ฐ˜๋Œ€๋˜๋Š” ํ•จ์ˆ˜๋กœ ์—ฌ๋Ÿฌ promise ์ค‘ ํ•˜๋‚˜๊ฐ€ resolve๋˜๋ฉด ํŠธ๋ฆฌ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— Promise.all()์€ ๋ชจ๋“  promise๊ฐ€ resolve ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. any(), all(), allSettled()์˜ ์ฐจ์ด์ ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • any() : ํ•˜๋‚˜์˜ promise๊ฐ€ resolve๋˜๋ฉด ์‹คํ–‰๋˜๊ณ , ๋ชจ๋“  promise๊ฐ€ reject๋˜๋ฉด reject๋ฉ๋‹ˆ๋‹ค.
  • all() : ๋ชจ๋“  promise๊ฐ€ resolve๋˜๋ฉด ์‹คํ–‰๋˜๊ณ , ํ•˜๋‚˜์˜ promise๋ผ๋„ reject๋˜๋ฉด reject๋ฉ๋‹ˆ๋‹ค.
  • allSettled() : ๋ชจ๋“  promise๊ฐ€ resolve๋˜๊ฑฐ๋‚˜ reject๋˜๋ฉด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

Promise.any๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

// Promise ์ƒ์„ฑ
const promise1 = new Promise((resolve, reject) => {
    // 2์ดˆ ํ›„์— ์ฒซ ๋ฒˆ์งธ Promise๊ฐ€ resolve ๋จ
    setTimeout(() => resolve("The first promise has been resolved."), 2000);
});

// Promise ์ƒ์„ฑ
const promise2 = new Promise((resolve, reject) => {
    // 1์ดˆ ํ›„์— ๋‘ ๋ฒˆ์งธ Promise๊ฐ€ resolve
    setTimeout(() => resolve("The second promise has been resolved."), 1000);
});

// Promise ์ƒ์„ฑ
const promise3 = new Promise((resolve, reject) => {
    // 3์ดˆ ํ›„์— ์„ธ ๋ฒˆ์งธ Promise๊ฐ€ resolve
    setTimeout(() => resolve("The third promise has been resolved."), 3000);
});

(async function () {
    const data = await Promise.any([promise1, promise2, promise3]);
    // Print the data returned from the first resolved Promise.
    // ์ฒซ resolved๋œ Promise๋กœ๋ถ€ํ„ฐ ๋ฆฌํ„ด๋ฐ›์€ ๋ฐ์ดํ„ฐ ์ถœ๋ ฅ
    console.log(data);
    // ์ถœ๋ ฅ : The second promise has been resolved.
})();

๋งŒ์•ฝ ๋ชจ๋“  promise๊ฐ€ reject๋˜๋ฉด, AggregateError Exception๊ฐ€ ๋˜์ ธ์ง‘๋‹ˆ๋‹ค. exception์„ ์–ด๋–ป๊ฒŒ ๋‹ค๋ค„์•ผ ํ•˜๋Š”์ง€ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

// Promise ์ƒ์„ฑ
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => reject("The first promise has been rejected."), 1000);
});

// Promise ์ƒ์„ฑ
const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => reject("The second promise has been rejected."), 500);
});

// Promise ์‹คํ–‰
(async function () {
    try {
        const data = await Promise.any([promise1, promise2]);
        console.log(data);
    } catch (error) {
        // ๋ชจ๋“  Promise๊ฐ€ reject๋˜๋ฉด try-catch block์ด aggregate error์„ ์ฒ˜๋ฆฌ
        console.log("Error: ", error);
    }
})();

4. ๋…ผ๋ฆฌ ํ• ๋‹น ์—ฐ์‚ฐ์ž (Logical Assignment Operators)

์„ธ ๊ฐ€์ง€ ๋…ผ๋ฆฌ ํ• ๋‹น ์—ฐ์‚ฐ์ž๋Š” ECMAScript 2021์—์„œ ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ์—ฐ์‚ฐ์ž๋“ค์€ ๋…ผ๋ฆฌ ์—ฐ์‚ฐ์ž์™€ ํ• ๋‹น ํ‘œํ˜„์‹์˜ ์กฐํ•ฉ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • ๋…ผ๋ฆฌ OR ํ• ๋‹น ์—ฐ์‚ฐ์ž ||=
  • ๋…ผ๋ฆฌ AND ํ• ๋‹น ์—ฐ์‚ฐ์ž &&=
  • Nullish ๋ณ‘ํ•ฉ ํ• ๋‹น ์—ฐ์‚ฐ์ž ??=

๋…ผ๋ฆฌ OR ํ• ๋‹น ์—ฐ์‚ฐ์ž (Logical OR assignment operator)

๋…ผ๋ฆฌ OR ํ• ๋‹น ์—ฐ์‚ฐ์ž ||=๋Š” ๋‘ ๊ฐœ์˜ ํ”ผ์—ฐ์‚ฐ์ž๋ฅผ ๋ฐ›์•„ ์™ผ์ชฝ ํ”ผ์—ฐ์‚ฐ์ž๊ฐ€ false์ธ ๊ฒฝ์šฐ ์˜ค๋ฅธ์ชฝ ํ”ผ์—ฐ์‚ฐ์ž๋ฅผ ์™ผ์ชฝ ํ”ผ์—ฐ์‚ฐ์ž์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

//  ||= ๋Š” songsCount๊ฐ€ false (0)์ธ์ง€ ํ™•์ธ
//  false์ธ ๊ฒฝ์šฐ ์˜ค๋ฅธ์ชฝ ๊ฐ’์ด ์™ผ์ชฝ ๋ณ€์ˆ˜์— ํ• ๋‹น๋จ
let myPlaylist = {songsCount: 0, songs:[]};
myPlaylist.songsCount ||= 100;
console.log(myPlaylist);  // ์ถœ๋ ฅ: {songsCount: 100, songs: Array(0)}

๋…ผ๋ฆฌ OR ํ• ๋‹น ์—ฐ์‚ฐ์ž๋Š” ์งง์€ ํ‘œํ˜„์„ ์ œ๊ณตํ•˜๋Š”๋ฐ ์•„๋ž˜ ํ‘œํ˜„๊ณผ ๋™์ผํ•œ ํšจ๊ณผ์ž…๋‹ˆ๋‹ค.

a || (a = b)

๋…ผ๋ฆฌ AND ํ• ๋‹น ์—ฐ์‚ฐ์ž (Logical AND assignment operator)

๋…ผ๋ฆฌ AND ํ• ๋‹น ์—ฐ์‚ฐ์ž &&=๋Š” ์™ผ์ชฝ ํ”ผ์—ฐ์‚ฐ์ž๊ฐ€ true์ธ ๊ฒฝ์šฐ์—๋งŒ ์˜ค๋ฅธ์ชฝ ํ”ผ์—ฐ์‚ฐ์ž๋ฅผ ์™ผ์ชฝ ํ”ผ์—ฐ์‚ฐ์ž์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

//  &&= ๋Š” filesCount๊ฐ€ true์ธ์ง€ ํ™•์ธ
//  true์ธ ๊ฒฝ์šฐ ์˜ค๋ฅธ์ชฝ ๊ฐ’์ด ์™ผ์ชฝ ๋ณ€์ˆ˜์— ํ• ๋‹น๋จ
let myFiles = {filesCount: 100, files:[]};
myFiles.filesCount &&= 5;
console.log(myFiles); // ์ถœ๋ ฅ: {filesCount: 5, files: Array(0)}

๋…ผ๋ฆฌ AND ํ• ๋‹น ์—ฐ์‚ฐ์ž ๋˜ํ•œ ํ•˜๋‚˜์˜ short-circuit์œผ๋กœ ์•„๋ž˜ ํ‘œํ˜„๊ณผ ๋™์ผํ•œ ํšจ๊ณผ์ž…๋‹ˆ๋‹ค.

a && (a = b)

Nullish ๋ณ‘ํ•ฉ ํ• ๋‹น ์—ฐ์‚ฐ์ž (Nullish coalescing assignment operator)

Nullish ๋ณ‘ํ•ฉ ํ• ๋‹น ์—ฐ์‚ฐ์ž ??=๋Š” ์™ผ์ชฝ ํ”ผ์—ฐ์‚ฐ์ž๊ฐ€ null์ด๊ฑฐ๋‚˜ undefined์ธ ๊ฒฝ์šฐ์—๋งŒ ์˜ค๋ฅธ์ชฝ ํ”ผ์—ฐ์‚ฐ์ž๋ฅผ ์™ผ์ชฝ ํ”ผ์—ฐ์‚ฐ์ž์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

// ??=๋Š” lastname์ด null ๋˜๋Š” undefined์ธ์ง€ ํ™•์ธ
// null ๋˜๋Š” undefined๋ผ๋ฉด ์˜ค๋ฅธ์ชฝ ๊ฐ’์ด ์™ผ์ชฝ ๋ณ€์ˆ˜์— ํ• ๋‹น๋จ
let userDetails = {firstname: 'Katina', age: 24}
userDetails.lastname ??= 'Dawson';
console.log(userDetails); // ์ถœ๋ ฅ: {firstname: 'Katina', age: 24, lastname: 'Dawson'}

Nullish ๋ณ‘ํ•ฉ ํ• ๋‹น ์—ฐ์‚ฐ์ž ๋˜ํ•œ ํ•˜๋‚˜์˜ short-circuit์œผ๋กœ ์•„๋ž˜ ํ‘œํ˜„๊ณผ ๋™์ผํ•œ ํ‘œํ˜„์ž…๋‹ˆ๋‹ค.

a ?? (a = b)

5. Private ํด๋ž˜์Šค ๋ฉ”์†Œ๋“œ์™€ ์ ‘๊ทผ์ž

ํด๋ž˜์Šค ๋ฉ”์†Œ๋“œ์™€ ํ”„๋กœํผํ‹ฐ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ publicํ•˜์ง€๋งŒ ํ•ด์‹œ ์ ‘๋‘์‚ฌ(#)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด private ๋ฉ”์†Œ๋“œ์™€ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. privacy ์บก์Šํ™”๋Š” ECMAScript 2021 ์—…๋ฐ์ดํŠธ๋ถ€ํ„ฐ ์ ์šฉ๋œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. privateํ•œ ๋ฉ”์†Œ๋“œ์™€ ํ”„๋กœํผํ‹ฐ๋Š” ํด๋ž˜์Šค ๋‚ด์—์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๊ด€๋ จํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

class User {
    constructor() {}

    // ๋ฉ”์†Œ๋“œ ์ด๋ฆ„ ์•ž์— '#'์„ ๋ถ™์ด๋ฉด private ๋ฉ”์†Œ๋“œ๊ฐ€ ๋จ!
    #generateAPIKey() {
        return "d8cf946093107898cb64963ab34be6b7e22662179a8ea48ca5603f8216748767";
    }

    getAPIKey() {
        return this.#generateAPIKey();
    }
}

const user = new User();
const userAPIKey = user.getAPIKey();
console.log(userAPIKey); // ์ถœ๋ ฅ: d8cf946093107898cb64963ab34be6b7e22662179a8ea48ca5603f8216748767

private ์ ‘๊ทผ์ž๋Š” privateํ•œ Getter์™€ Setter์ž…๋‹ˆ๋‹ค. Getter๋Š” ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ฒŒ ํ•˜๊ณ , Setter๋Š” ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ์— ๊ฐ’์„ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ํ•ด์‹œ ์ ‘๋‘์‚ฌ(#)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ private getter๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

get #newAccountPassword() {}

๋น„์Šทํ•˜๊ฒŒ private setter๋ฅผ ์ •์˜ํ•  ์ˆ˜๋„ ์žˆ์ฃ .

set #generateAccountPassword(newPassword) {}

์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

class Str {
    // ์†์„ฑ ์ด๋ฆ„ ์•ž์— ํ•ด์‹œ ์ ‘๋‘์‚ฌ๋ฅผ ๋ถ™์ด๋ฉด private์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    #uniqueStr;

    constructor() {}
    // private setter๋Š” ์ด๋ฆ„ ์•ž์— '#'๋ฅผ ๋ถ™์ž…๋‹ˆ๋‹ค.
    set #generateUniqueStringByCustomLength(length = 24) {
        const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        let randomStr = "";

        for (let i = 0; i < length; i++) {
            const randomNum = Math.floor(Math.random() * characters.length);
            randomStr += characters[randomNum];
        }

        this.#uniqueStr = randomStr;
    }

    // Public Setter
    set setRandomString(length) {
        this.#generateUniqueStringByCustomLength = length;
    }

    // private getter๋Š” ์ด๋ฆ„ ์•ž์— '#'๋ฅผ ๋ถ™์ž…๋‹ˆ๋‹ค.
    get #fetchUniqueString() {
        return this.#uniqueStr;
    }

    // Public Getter
    get getRandomString() {
        return this.#fetchUniqueString;
    }
}

const str = new Str();
// ํด๋ž˜์Šค ๋‚ด์—์„œ private setter์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ public setter๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
str.setRandomString = 20;


// ํด๋ž˜์Šค ๋‚ด์—์„œ private getter์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ public getter๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
const uniqueStr = str.getRandomString;
console.log(uniqueStr);

๋“œ๋””์–ด ๋์ž…๋‹ˆ๋‹ค! JavaScript ES12์—์„œ ์ œ๊ณต๋˜๋Š” ๊ธฐ๋Šฅ๋“ค์„ ๋ฐฐ์›Œ๋ณด์…จ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์œ„์—์„œ ๋ฐฐ์šด ๊ธฐ๋Šฅ๋“ค์„ ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ํ•˜๊ณ  ์žˆ๋Š” ํ”„๋กœ์ ํŠธ๋‚˜ ์•ž์œผ๋กœ ํ•  ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด๋ณด์„ธ์š”.

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜ ์‹คํ–‰ ์ดํ•ดํ•˜๊ธฐ - ์ฝœ์Šคํƒ, ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋“ฑ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜ ์‹คํ–‰ ์ดํ•ดํ•˜๊ธฐ

์›๋ฌธ : Understanding Javascript Function Executions โ€” Call Stack, Event Loop , Tasks & more

์š”์ฆ˜ ์›น ๊ฐœ๋ฐœ์ž๋‚˜ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋Š” ๋ธŒ๋ผ์šฐ์ € ๋‚ด์—์„œ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•œ ์š”์†Œ๋ฅผ ๋™์ž‘์‹œํ‚ค๊ฑฐ๋‚˜ ์ปดํ“จํ„ฐ ๊ฒŒ์ž„, ๋ฐ์Šคํฌํƒ‘ ์œ„์ ฏ, ํฌ๋กœ์Šคํ”Œ๋žซํผ ๋ชจ๋ฐ”์ผ ์•ฑ ์ œ์ž‘ ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋ฒ„์‚ฌ์ด๋“œ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ(node.js๋ฅผ ๋งŽ์ด ์‚ฌ์šฉ)์— ์ด๋ฅด๊ธฐ๊นŒ์ง€ ์Šคํฌ๋ฆฝํŠธ ์–ธ์–ด๋กœ ๋‹ค์–‘ํ•œ ๊ฒƒ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋‚ด๋ถ€ ๋™์ž‘์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ๊ณผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋” ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์•„์ฃผ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ์•„ํ‹ฐํด์—์„œ ์ด๋Ÿฐ ์ฃผ์ œ๋“ค์— ๋Œ€ํ•ด ๋‹ค๋ฃฐ ๊ฒ๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ƒํƒœ๊ณ„๋Š” ๊ทธ ์–ด๋Š ๋•Œ๋ณด๋‹ค ๋ณต์žกํ•ด์กŒ๊ณ  ์•ž์œผ๋กœ๋„ ๊ณ„์† ๋ณต์žกํ•ด์งˆ ๊ฒ๋‹ˆ๋‹ค. Webpack, Babel, ESLint,Mocha, Karma, Grunt ๋“ฑ ๋ชจ๋˜ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ œ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋„๊ตฌ๋“ค์€ ์—„์ฒญ๋‚ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ณ  ๊ทธ ๋„๊ตฌ๋Š” ์–ด๋–ค ์ผ์„ ํ• ๊นŒ์š”? ์˜ค๋Š˜๋‚  ์›น ๊ฐœ๋ฐœ์ž๋“ค์˜ ๊ณ ๊ตฐ๋ถ„ํˆฌ๋ฅผ ์•„์ฃผ ์ž˜ ์„ค๋ช…ํ•ด์ฃผ๋Š” ๋งŒํ™”๋ฅผ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค.

Javascript Fatigue โ€” What it feels like to learn Javascript

๋ชจ๋“  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ์ž๋“ค์€ ์–ด๋–ค ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•ด ๊นŠ์ด ์•Œ์•„๋ณด๊ธฐ ์ „์— ๋ฃจํŠธ ๋ ˆ๋ฒจ์—์„œ ๋‚ด๋ถ€์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๊ธฐ์ดˆ ์ง€์‹๋“ค์„ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ์ž๋“ค์€ ์•„๋งˆ ํฌ๋กฌ์˜ ๋Ÿฐํƒ€์ž„์ธ V8์ด๋ผ๋Š” ๋‹จ์–ด์— ๋Œ€ํ•ด ๋“ค์–ด๋ณด์…จ์„ ๊ฒ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ ์ •ํ™•ํžˆ V8์ด ๋ฌด์—‡์„ ํ•˜๋Š”์ง€ ์•Œ์ง€ ๋ชปํ•˜๋Š” ๋ถ„๋“ค๋„ ์žˆ๊ฒ ์ฃ . ์ €๋Š” ๊ฐœ๋ฐœ์ž๋กœ์„œ์˜ ์ปค๋ฆฌ์–ด ์ฒซ 1๋…„ ๋™์•ˆ ์ฃผ์–ด์ง„ ์ผ์„ ๋งˆ๋ฌด๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์ฃผ๋กœ ํ–ˆ๊ธฐ์— ์ด๋Ÿฐ ํ™”๋ คํ•œ ์šฉ์–ด๋“ค์— ๋Œ€ํ•ด์„œ๋„ ์ž˜ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ด๋Ÿฐ ์ผ๋“ค์„ ํ•ด๋‚ด๋Š”์ง€์— ๋Œ€ํ•œ ์ €์˜ ํ˜ธ๊ธฐ์‹ฌ์„ ๋งŒ์กฑ์‹œํ‚ค์ง€ ๋ชปํ–ˆ์ฃ . ์ €๋Š” ๊ตฌ๊ธ€์— ๋Œ€ํ•ด ๋” ๊นŠ์ด ํŒŒ๋ณด๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๊ณ  Phili Roberts๊ฐ€ JS ์ปจํผ๋Ÿฐ์Šค์—์„œ ์ง„ํ–‰ํ•œ ์ด๋ฒคํŠธ ๋ฃจํ”„์— ๋Œ€ํ•œ ๋ฉ‹์ง„ ๊ฐ•์—ฐ๊ณผ ๊ฐ™์€ ๋ช‡๋ช‡ ์ข‹์€ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŒ…์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฐฐ์šด ๊ฒƒ๋“ค์„ ์š”์•ฝํ•ด์„œ ๊ณต์œ ํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค. ์•Œ์•„์•ผ ํ•˜๋Š” ๋‚ด์šฉ๋“ค์ด ๋„ˆ๋ฌด ๋งŽ์•„ ์•„ํ‹ฐํด์„ ๋‘ ํŒŒํŠธ๋กœ ๋‚˜๋ˆ„์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํŒŒํŠธ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์šฉ์–ด๋ฅผ ์†Œ๊ฐœํ•  ๊ฒƒ์ด๊ณ  ๋‘ ๋ฒˆ์งธ ํŒŒํŠธ์—์„œ๋Š” ๊ฐ ์šฉ์–ด๋“ค์„ ์—ฐ๊ฒฐํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ์˜ ์‹ฑ๊ธ€ ๋™์‹œ์„ฑ ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ์ฆ‰ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ํƒœ์Šคํฌ, ์ฝ”๋“œ ํ•œ ์กฐ๊ฐ์„ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” (V8 ๋‚ด๋ถ€์— ๊ตฌํ˜„๋œ) ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋™์‹œ์„ฑ ๋ชจ๋ธ์„ ๊ตฌ์„ฑํ•˜๋Š” ํž™๊ณผ ํ ๊ทธ๋ฆฌ๊ณ  ํ•˜๋‚˜์˜ ์ฝœ์Šคํƒ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์šฉ์–ด๋“ค์—๊ฒŒ ๋Œ€ํ•ด ์•Œ์•„๋ด…์‹œ๋‹ค.

Visual Representation of JS Model

1. Call Stack, ์ฝœ ์Šคํƒ

ํ•จ์ˆ˜ ํ˜ธ์ถœ๊ณผ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ˜„์žฌ ํ”„๋กœ๊ทธ๋žจ ์œ„์น˜๋ฅผ ์ €์žฅํ•ด๋‘๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ˜ธ์ถœํ•  ๋•Œ ์Šคํƒ์— ๋ฌด์–ธ๊ฐ€๋ฅผ pushํ•ด๋‘๊ณ  ํ•จ์ˆ˜๋กœ๋ถ€ํ„ฐ ๋ฆฌํ„ด๋ฐ›์„ ๋•Œ ์Šคํƒ์˜ top์—์„œ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ pop ํ•ฉ๋‹ˆ๋‹ค.

JS Stack Visualization (GIF) (Sorry Correct Output = 100)

์œ„์˜ ํŒŒ์ผ์„ ์‹คํ–‰ํ•  ๋•Œ ์‹คํ–‰์ด ์‹œ์ž‘๋˜๋Š” ๋ฉ”์ธ ํ•จ์ˆ˜๊ฐ€ ๋จผ์ € ๋ณด์ž…๋‹ˆ๋‹ค. console.log(bar(6))๋กœ๋ถ€ํ„ฐ ๊ฐ€์„œ ์Šคํƒ์— pushํ•œ ํ›„ ์ธ์ˆ˜์™€ ํ•จ๊ป˜ bar ํ•จ์ˆ˜๋กœ ๋„˜์–ด๊ฐ‘๋‹ˆ๋‹ค. ๋‹ค์‹œ foo ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ์Šคํƒ์— pushํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  foo ํ•จ์ˆ˜๊ฐ€ ๋ฆฌํ„ดํ•˜๋ฉด ์Šคํƒ์—์„œ pop๋˜๊ณ  ๋น„์Šทํ•˜๊ฒŒ bar๊ฐ€ ์ฐจ๋ก€๋Œ€๋กœ pop๋ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ console์ด ๊ฐ’์„ ์ถœ๋ ฅํ•˜๋ฉด์„œ pop๋ฉ๋‹ˆ๋‹ค. ์ด ๋ชจ๋“  ๊ฒƒ๋“ค์€ ํ•œ๋ฒˆ์— ํ•˜๋‚˜์”ฉ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์ฐฝ์—์„œ ๊ธธ๊ณ  ๋นจ๊ฐ„ ์ค„๋“ค๋กœ ์ฑ„์›Œ์ง„ ์—๋Ÿฌ ์Šคํƒ์ด ์ถ”์ ๋œ ๊ฒƒ์„ ์ ์–ด๋„ ํ•œ๋ฒˆ์ฏค์€ ๋ณธ ์ ์ด ์žˆ์œผ์‹ค ๊ฒ๋‹ˆ๋‹ค. ์—๋Ÿฌ ์Šคํƒ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ˜„์žฌ ์ƒํƒœ์™€ ์œ„์—์„œ ์•„๋ž˜์˜ ์ˆœ์„œ๋กœ ์‹คํŒจํ•œ ์œ„์น˜๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. (์•„๋ž˜ ์ด๋ฏธ์ง€ ์ฐธ๊ณ )

๋•Œ๋•Œ๋กœ ์—ฌ์šฐ๋ฆฌ๋Š” ํ•จ์ˆ˜๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋‹ค๊ฐ€ ๋ฌดํ•œ ๋ฃจํ”„์— ๋น ์ง€๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ํฌ๋กฌ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด 16,000 ํ”„๋ ˆ์ž„์˜ ์Šคํƒ ํฌ๊ธฐ์˜ ์ œํ•œ์„ ๋„˜๊ฒŒ ๋˜์–ด ํ”„๋กœ๊ทธ๋žจ์ด ์ฃฝ๊ณ  Max Stack Error Reached ์—๋Ÿฌ๋ฅผ throwํ•ฉ๋‹ˆ๋‹ค.

2. Heap, ํž™

๊ฐ์ฒด๋“ค์€ (๋Œ€๋ถ€๋ถ„ ๋น„๊ตฌ์กฐ์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์ธ) Heap์— ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๋‚˜ ๊ฐ์ฒด๋“ค์˜ ๋ชจ๋“  ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ด ํž™์—์„œ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

3. Queue, ํ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋Ÿฐํƒ€์ž„์€ ์ฒ˜๋ฆฌ๋˜๋Š” ๋ฉ”์„ธ์ง€๋“ค์˜ ๋ชฉ๋ก๊ณผ ๊ด€๋ จ๋˜์–ด ์‹คํ–‰ํ•  ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์„์„ ๋‹ด๋Š” ๋ฉ”์„ธ์ง€ ํ๋ฅผ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์Šคํƒ์˜ ์šฉ๋Ÿ‰์ด ์ถฉ๋ถ„ํ•˜๋ฉด ํ์—์„œ ๋ฉ”์„ธ์ง€๋ฅผ ๊ฐ€์ ธ์™€ ๊ด€๋ จ๋œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์Šคํƒ์ด ๋‹ค์‹œ ๋น„์›Œ์งˆ ๋•Œ๊นŒ์ง€ ๋ฉ”์„ธ์ง€๊ฐ€ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฉ”์„ธ์ง€๋“ค์€ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ์ฃผ์–ด์ง„ (๋งˆ์šฐ์Šค ํด๋ฆญ ์ด๋ฒคํŠธ๋‚˜ HTTP ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๋ฐ›์€ ๊ฒฝ์šฐ์™€ ๊ฐ™์€) ์™ธ๋ถ€ ๋น„๋™๊ธฐ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ํ์— ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์œผ๋‚˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ๋”ฐ๋กœ ์—†๋‹ค๋ฉด ํ์— ๋“ค์–ด๊ฐ€๋Š” ๋ฉ”์„ธ์ง€๋Š” ์—†์Šต๋‹ˆ๋‹ค.

์ด๋ฒคํŠธ ๋ฃจํ”„

๊ธฐ๋ณธ์ ์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ์˜ ์„ฑ๋Šฅ์„ ํ‰๊ฐ€ํ•  ๋•Œ ์Šคํƒ์˜ ํ•จ์ˆ˜๋ฅผ ๋Š๋ฆฌ๊ฒŒ ๋˜๋Š” ๋น ๋ฅด๊ฒŒ ์กฐ์ž˜ํ•ฉ๋‹ˆ๋‹ค. console.log()์™€ ๊ฐ™์€ ํ•จ์ˆ˜๋Š” ๋น ๋ฅด๊ธด ํ•˜์ง€๋งŒ for๋‚˜ while๋ฌธ ์•ˆ์—์„œ ์ˆ˜์ฒœ ๋ฒˆ, ์ˆ˜๋ฐฑ๋งŒ ๋ฒˆ ๋ฐ˜๋ณตํ•˜๊ฒŒ ๋˜๋ฉด ๋Š๋ ค์ง€๊ณ , ์Šคํƒ์„ ๊ทธ๋งŒํผ ๋งŽ์ด ์ฐจ์ง€ํ•˜๊ณ  ๋•Œ๋กœ๋Š” ์Šคํƒ์„ ๋ธ”๋ฝํ•ด๋ฒ„๋ฆด ๊ฒ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒƒ์„ blocking script๋ผ ๋ถ€๋ฅด๋ฉฐ, Webpage Speed Insights์—์„œ ์•„๋งˆ ๋ณด๊ฑฐ๋‚˜ ๋“ค์œผ์…จ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด๋‚˜ ์ด๋ฏธ์ง€ ์š”์ฒญ์€ ๋Š๋ฆด ์ˆ˜ ์žˆ์ง€๋งŒ ๋‹คํ–‰ํžˆ๋„ ์„œ๋ฒ„์— ๋ณด๋‚ด๋Š” ์š”์ฒญ๋“ค์€ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ธ AJAX๋ฅผ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋„คํŠธ์›Œํฌ ์š”์ฒญ๋“ค์ด ๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋งŒ๋“ค์–ด์กŒ๋‹ค๋ฉด ์–ด๋–ค ์ผ์ด ์ƒ๊ธธ๊นŒ์š”? ๋„คํŠธ์›Œํฌ ์š”์ฒญ์€ ๋ณดํ†ต ๋‹ค๋ฅธ ์ปดํ“จํ„ฐ๋‚˜ ์–ด๋”˜๊ฐ€์— ์žˆ๋Š” ๊ธฐ๊ณ„์— ์žˆ๋Š” ์–ด๋–ค ์„œ๋ฒ„์—๊ฒŒ ๋ณด๋‚ด์ง‘๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— ๋‹ค์‹œ ์‘๋‹ต์„ ๋ฐ›์„ ๋•Œ๊นŒ์ง€ ์‹œ๊ฐ„์ด ๊ฝค ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์‚ฌ์ด์— CTA ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๊ฒƒ๋“ค์„ ๋ Œ๋”๋งํ•  ๊ฒŒ ์žˆ๋”๋ผ๋„ ์Šคํƒ์ด ๋ธ”๋ฝ๋˜์–ด ์•„๋ฌด๋Ÿฐ ์ผ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Ruby์™€ ๊ฐ™์€ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ์–ธ์–ด์—์„œ๋Š” ์ด๋Ÿฐ ์ผ๋“ค์ด ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ๊ฐ™์€ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ์–ธ์–ด์—์„œ๋Š” ์Šคํƒ์˜ ํ•จ์ˆ˜๊ฐ€ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ๋•Œ๊นŒ์ง€ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์•„๋ฌด ๊ฒƒ๋„ ํ•  ์ˆ˜ ์—†์–ด ์›นํŽ˜์ด์ง€๋Š” ๋ง๊ฐ€์ ธ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๋“ค์ด ์œ ๋™์ ์ธ UI๋ฅผ ์›ํ•œ๋‹ค๋ฉด ์ด๋Ÿฐ ์ƒํ™ฉ์€ ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์ผ์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ• ๊นŒ์š”?

"JS์—์„œ ๋™์‹œ์„ฑ์€ ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ์„ ์ œ์™ธํ•˜๊ณ  ํ•œ๋ฒˆ์— ํ•˜๋‚˜์”ฉ์„ ์˜๋ฏธํ•œ๋‹ค."

๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰ ์ฝ”๋“œ์˜ ์ผ๋ถ€๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋‚˜์ค‘์— ์‹คํ–‰ํ•  ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ฃผ๋Š” ๊ฒƒ์ด์ฃ . ์šฐ๋ฆฌ๋Š” ๋ชจ๋‘ $.get(),setTimeout(),setInterval(), Promises ๋“ฑ๊ณผ ํ•จ๊ป˜ AJAX ์š”์ฒญ๊ณผ ๊ฐ™์€ ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ์„ ๊ฒฝํ—˜ํ–ˆ์„ ๊ฒ๋‹ˆ๋‹ค. Node๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ์‹คํ–‰์˜ ์ „๋ถ€์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ๋“ค์€ ์ฆ‰์‹œ ์‹คํ–‰๋˜์ง€ ์•Š๊ณ  ๋‚˜์ค‘์— ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ console.log(), ์ˆ˜ํ•™์  ์—ฐ์‚ฐ๊ณผ ๊ฐ™์€ ๋™๊ธฐ ํ•จ์ˆ˜๋“ค์ฒ˜๋Ÿผ ์Šคํƒ์— ๋ฐ”๋กœ push๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ๋„๋Œ€์ฒด ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋“ค์€ ์–ด๋””์— ๊ฐ€์„œ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฑธ๊นŒ์š”?

์œ„ ์ฝ”๋“œ์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ์—์„œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์‹คํ–‰๋˜๋Š” ๊ฒฝ์šฐ

  1. ์š”์ฒญ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ ๊ฒฝ์šฐ, onreadystatechange ์ด๋ฒคํŠธ์— ๋ฏธ๋ž˜์— ์–ธ์  ๊ฐ€ ์‘๋‹ต์ด ๋„์ฐฉํ–ˆ์„ ๋•Œ ์‹คํ–‰ํ•  ์ฝœ๋ฐฑํ•จ์ˆ˜๋กœ ์ต๋ช…ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  2. "Script call done!"์ด ์ฝ˜์†”์— ๋ฐ”๋กœ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
  3. ์‘๋‹ต์ด ๋„์ฐฉํ–ˆ์„ ๋•Œ ์ฝœ๋ฐฑ์ด ์‹คํ–‰๋˜์–ด ๋ณธ๋ฌธ์ด ์ฝ˜์†”์— ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

caller๋ฅผ ์‘๋‹ต์—์„œ ๋ถ„๋ฆฌ๋˜๋ฉด ๋น„๋™๊ธฐ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๊ณ  ํ˜ธ์ถœ์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋Ÿฐํƒ€์ž„์ด ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ DOM ์ด๋ฒคํŠธ๋‚˜ HTTP ์š”์ฒญ, setTimeout๊ณผ ๊ฐ™์ด ๋น„๋™๊ธฐ ์ด๋ฒคํŠธ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด C++๋กœ ๊ตฌํ˜„๋œ ๋ธŒ๋ผ์šฐ์ €์— ์˜ํ•ด ์ƒ์„ฑ๋œ ์Šค๋ ˆ๋“œ์ธ ๋ธŒ๋ผ์šฐ์ € API๊ฐ€ ์‹œ์ž‘ํ•˜๊ณ  API๋ฅผ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ € ์›น API ์Šค๋ ˆ๋“œ๋Š” DOM ์ด๋ฒคํŠธ, HTTP ์š”์ฒญ, setTimeout๊ณผ ๊ฐ™์€ ๋น„๋™๊ธฐ ์ด๋ฒคํŠธ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด C++๋กœ ๊ตฌํ˜„๋œ ๋ธŒ๋ผ์šฐ์ €์— ์˜ํ•ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

WebAPI๋Š” ์Šค์Šค๋กœ ์Šคํƒ์˜ ์‹คํ–‰ ์ฝ”๋“œ๋กœ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๊ฐ€๋Šฅํ–ˆ๋‹ค๋ฉด ์ฝ”๋“œ ์ค‘๊ฐ„์— API๊ฐ€ ๋ฌด์ž‘์œ„๋กœ ๋‚˜ํƒ€๋‚ฌ์„ ๊ฒ๋‹ˆ๋‹ค. ์œ„์—์„œ ๋‹ค๋ฃฌ ๋ฉ”์„ธ์ง€ ์ฝœ๋ฐฑ ํ๋Š” ๊ทธ ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. WebAPI๋Š” ์‹คํ–‰์ด ์™„๋ฃŒ๋˜๋ฉด ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ํ๋กœ pushํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ํ์— ์žˆ๋Š” ์ด ์ฝœ๋ฐฑํ•จ์ˆ˜๋“ค์˜ ์‹คํ–‰์„ ์ฑ…์ž„์ง€๊ณ , ์Šคํƒ์ด ๋นˆ ๊ฒฝ์šฐ์— pushํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ ๋ฃจํ”„์˜ ๊ธฐ๋ณธ์ ์ธ ์ผ์€ ์Šคํƒ๊ณผ ํƒœ์Šคํฌ ํ๋ฅผ ๋ณด๋‹ค๊ฐ€ ์Šคํƒ์ด ๋น„์—ˆ์„ ๋•Œ ํ์˜ ์ฒซ ๋ฒˆ์งธ ํƒœ์Šคํฌ๋ฅผ ์Šคํƒ์— pushํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ ๋ฉ”์„ธ์ง€๋‚˜ ์ฝœ๋ฐฑ์€ ๋‹ค๋ฅธ ๋ฉ”์„ธ์ง€๊ฐ€ ์ฒ˜๋ฆฌ๋˜๊ธฐ ์ „์— ์™„์ „ํžˆ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

while (queue.waitForMessage()) {
  queue.processNextMessage();
}

์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ฉ”์„ธ์ง€๋“ค์€ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ ์‹œ๊ฐ„์— ์ถ”๊ฐ€๋˜๊ณ , ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ด๋ฒคํŠธ์— ์žฅ์ฐฉ๋ฉ๋‹ˆ๋‹ค. ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์—†์œผ๋ฉด ์ด๋ฒคํŠธ๋Š” ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํด๋ฆญ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์žˆ๋Š” ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ ๋ฉ”์„ธ์ง€๊ฐ€ ๋”ํ•ด์ง‘๋‹ˆ๋‹ค. ์ด ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ์€ ์ฝœ์Šคํƒ์˜ ์ดˆ๊ธฐ ํ”„๋ ˆ์ž„ ์—ญํ• ์„ ํ•˜๋ฉฐ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋‹จ์ผ์Šค๋ ˆ๋“œ์ด๋ฏ€๋กœ ๋ชจ๋“  ํ˜ธ์ถœ์ด ๋ฐ˜ํ™˜๋  ๋•Œ๊นŒ์ง€ ์ƒˆ๋กœ์šด ๋ฉ”์„ธ์ง€๋ฅผ ํด๋งํ•˜๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค. ๊ทธ ๋‹ค์Œ์˜ (๋™๊ธฐ) ํ•จ์ˆ˜๊ฐ€ ์Šคํƒ์˜ ์ƒˆ๋กœ์šด ์ฝœํ”„๋ ˆ์ž„์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ํŒŒํŠธ์—์„œ ์œ„ ์ ˆ์ฐจ๋Œ€๋กœ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ์‹œ๊ฐ์ ์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ๋”๋ถˆ์–ด ํ์—์„œ ์šฐ์„ ์ˆœ์œ„๊ณผ ๋†’์€ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์˜ ์œ ํ˜• ๋“ฑ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์˜ ์—ฌ๋Ÿฌ ์œ ํ˜•์„ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ผ๋ถ€ ํ•จ์ˆ˜๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์ œ๋กœ ๋”œ๋ ˆ์ด์™€ ๊ฐ™์€ hacks์— ๋Œ€ํ•ด ๋ง์”€๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] JavaScript์˜ ์ƒˆ๋กœ์šด `.at()` ๋ฉ”์†Œ๋“œ ์‚ฌ์šฉํ•˜๊ธฐ

์›๋ฌธ : Using the new JavaScript .at() method์„ ์ฝ๊ณ  ๋ฒˆ์—ญํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ .at() ๋ฉ”์†Œ๋“œ๋Š” ์ธ๋ฑ์Šค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด ECMA ์ธํ„ฐ๋‚ด์…”๋„ TC39์˜ 8์›” ๋ฆด๋ฆฌ์ฆˆ์—์„œ ์†Œ๊ฐœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์€ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐ ์žˆ์–ด ํ”ํ•˜๊ฒŒ ๋ฐœ์ƒํ•˜๋Š” ์ผ์ด์ง€๋งŒ, .at() ๋ฉ”์†Œ๋“œ๊ฐ€ ๋‚˜ํƒ€๋‚˜๊ธฐ ์ „๊นŒ์ง€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋ฐฐ์—ด์˜ ์ฒ˜์Œ์ด๋‚˜ ๋ ๋˜๋Š” ๋ฌธ์ž์—ด ๋‚ด์—์„œ ์—˜๋ฆฌ๋จผํŠธ๋‚˜ ๋ฌธ์ž๋ฅผ ์„ ํƒํ•˜๋Š” ๋ฉ”์†Œ๋“œ์™€ ๊ธฐ์ˆ ๋งŒ ์กด์žฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๋Œ€๊ด„ํ˜ธ ํ‘œ๊ธฐ์ธ []๋Š” ๋ณดํ†ต ํŠน์ • ์ธ๋ฑ์Šค์˜ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ์‚ฌ์šฉ๋˜๋Š”๋ฐ, ์ด๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฐฐ์—ด์˜ ๋งˆ์ง€๋ง‰ ์•„์ดํ…œ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ํŒŒ์ด์ฌ๊ณผ ๊ฐ™์€ ์–ธ์–ด์—์„œ ๋ณด์ด๋Š” ๊ฒƒ์ฒ˜๋Ÿผ arr[-1]๊ณผ ๊ฐ™์ด ์Œ์ˆ˜์˜ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ ๊ฒฐ๊ณผ ๊ฐœ๋ฐœ์ž๋“ค์€ slice() ๋ฉ”์†Œ๋“œ์™€ length ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด์˜ ๋์— ์žˆ๋Š” ์•„์ดํ…œ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ์—๋„ ์ด ๋ฐฉ๋ฒ• ๋˜ํ•œ ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” .at() ๋ฉ”์†Œ๋“œ์™€ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ณ  ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ๋น„๊ตํ•˜์—ฌ ์–ผ๋งˆ๋‚˜ ๋” ๋‚˜์•„์กŒ๋Š”์ง€ ๋˜ํ•œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ธ๋ฑ์‹ฑ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด ํ”„๋กœํ† ํƒ€์ž…

.at() ๋ฉ”์†Œ๋“œ๋Š” ์ธ๋ฑ์‹ฑ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด์˜ prototype์— ์œ„์น˜ํ•ฉ๋‹ˆ๋‹ค.

์ธ๋ฑ์Šค ํ•ญ๋ชฉ์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ์ด ๊ฐ์ฒด๋“ค์€ Array, String, TypedArray์™€ ๊ฐ™์€ ํด๋ž˜์Šค๋ฅผ ํฌํ•จํ•˜๋Š”๋ฐ, ๋˜ํ•œ ๊ฐ ํด๋ž˜์Šค๋Š” Array.prototype.at(), String.prototype.at(), TypedArray.prototype.at()๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ
์ธ๋ฑ์‹ฑ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด์—์„œ ๋ฐ”๋กœ .at() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฐ์—ด์˜ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ๊ธฐ์กด ๋ฐฉ๋ฒ•

.at() ๋ฉ”์†Œ๋“œ์˜ ์žฅ์ ์„ ๋ณด๊ธฐ ์œ„ํ•ด ๋น„๊ต์˜ ๋ชฉ์ ์œผ๋กœ ๊ธฐ์กด์˜ ๋ฐฉ๋ฒ•๋“ค์— ๋Œ€ํ•ด ๋น ๋ฅด๊ฒŒ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ž…๋ฌธ์ž๋“ค์—๊ฒŒ๋„ ๋‹ค์‹œ๊ธˆ ํ™˜๊ธฐํ•˜๋Š” ์—ญํ• ๋„ ํ•ด์ค„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

arr์ด๋ผ๋Š” ๋ฐฐ์—ด์ด ์žˆ๋‹ค๊ณ  ํ•ด๋ด…์‹œ๋‹ค.

const arr = [1, 2, "three", 4, 5, true, false];

๋Œ€๊ด„ํ˜ธ []์„ ์‚ฌ์šฉํ•˜์—ฌ arr ๋ฐฐ์—ด์—์„œ ํŠน์ • ์ธ๋ฑ์Šค์˜ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด arr[0]์€ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ์ธ 1์„ ๊ฐ€์ ธ์˜ค๊ฒ ์ฃ . ๊ทธ๋Ÿฌ๋‚˜ ๋ฐฐ์—ด์˜ ๊ธธ์ด๋ฅผ ์•Œ ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์ด๋ผ๋ฉด length ํ”„๋กœํผํ‹ฐ๋‚˜ slice() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

length ํ”„๋กœํผํ‹ฐ ์‚ฌ์šฉํ•˜๊ธฐ

length ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

arr[arr.length - N];

์—ฌ๊ธฐ์„œ N์€ ๋ฐฐ์—ด์˜ ๋์—์„œ๋ถ€ํ„ฐ n๋ฒˆ์งธ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ๋ฐฐ์—ด์˜ ๋์—์„œ๋ถ€ํ„ฐ ๋ฐฐ์—ด์˜ ์š”์†Œ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ์—์„œ ์ด ๋ฐฉ๋ฒ•์œผ๋กœ arr ๋ฐฐ์—ด์˜ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์™€๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

const arr = [1, 2, "three", 4, 5, true, false];
const lastItem = arr[arr.length - 1];
console.log(lastItem);  // Expected Output: false

์ด ๋ฐฉ๋ฒ•์€ ์ž˜ ์ž‘๋™ํ•˜์ง€๋งŒ ๊ฐ„๋‹จํ•œ ์ž‘์—…์— ๋น„ํ•ด ๋ฌธ๋ฒ•์ด ๋ถˆํŽธํ•˜๊ณ  ์ฉ ์ข‹์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด๊ฐ’์„ ์‚ฌ์šฉํ•  ๋•Œ ๋ฆฌํ„ด๊ฐ’์„ ๋ณ€์ˆ˜์— ์ €์žฅํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

function appendNumber(arr, N) {
  arr.push(N);
  return arr;
}

const tempArr = appendNumber([1, 2, "three", 4, 5, true, false], 6);
console.log(tempArr[tempArr.length - 1]); // Expected Output: 6

์œ„ ์ฝ”๋“œ์—์„œ appendNumber() ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์€ length ํ”„๋กœํผํ‹ฐ๋ฅผ ์ ์šฉํ•˜๊ธฐ ์ „์— ๋จผ์ € tempArr์— ์ €์žฅ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

slice() ๋ฉ”์†Œ๋“œ ์‚ฌ์šฉํ•˜๊ธฐ

๊ฐœ๋ฐœ์ž๋Š” ๋ฐฐ์—ด์˜ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ์•„๋ž˜์™€ ๊ฐ™์ด slice() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

arr.slice(-1)[0]

์ด ๋ฌธ๋ฒ•์€ ์Œ์ˆ˜ ์ธ๋ฑ์Šค๋ฅผ ํ—ˆ์šฉํ•˜๋Š”๋ฐ ์ถ”ํ›„์— ๋‚˜์˜ค๋Š” .at() ๋ฉ”์†Œ๋“œ์—์„œ๋„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์Œ์ˆ˜ ์ธ๋ฑ์Šค๋Š” ๋ฐฐ์—ด์˜ ๋์—์„œ ๋ถ€ํ„ฐ์˜ ์˜คํ”„์…‹์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด slice(-1)์€ ๋’ค์—์„œ๋ถ€ํ„ฐ ๋งˆ์ง€๋ง‰ ์•„์ดํ…œ์„ ์ œ๊ฑฐํ•˜์—ฌ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. slice(-2)๋Š” ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋งˆ์ง€๋ง‰ 2๊ฐœ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์— ์ดˆ์ ์€ ๋งˆ์ง€๋ง‰ ์š”์†Œ์ด๊ธฐ ๋•Œ๋ฌธ์— [0]์€ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ์„ ํƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
์ด ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ arr ๋ฐฐ์—ด์˜ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const arr = [1, 2, "three", 4, 5, true, false];

console.log(arr.slice(-1)[0]); // Expected Output: false

์œ„์—์„œ ๋ดค๋˜ length ํ”„๋กœํผํ‹ฐ์™€ ๋‹ค๋ฅด๊ฒŒ ์ด ๋ฐฉ๋ฒ•์€ ํ•ด๋‹น ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ์ €์žฅํ•ด์•ผ ํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ์ข€ ๋” ์œ ์—ฐํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

function appendNumber(arr, N) {
  arr.push(N);
  return arr;
}

console.log(appendNumber([1, 2, "three", 4, 5, true, false], 6).slice(-1)[0]); // 6

๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ด ๋ฌธ๋ฒ•์€ ์ด์ƒํ•˜๊ฒŒ ๋ณด์ด๊ณ  ๊ฐœ๋ฐœ์ž์˜ ์˜๋„๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ณด์—ฌ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋ถˆํŽธํ•  ์ˆ˜๋„ ์žˆ๊ณ ์š”.

์™œ arr[-1]๋กœ ๋งˆ์ง€๋ง‰ ์š”์†Œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š”๊ฐ€?

์ด ์งˆ๋ฌธ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ฒ˜์Œ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ํ”ํ•˜๊ฒŒ ์ œ๊ธฐํ•˜๋Š” ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ Python๊ณผ ๊ฐ™์€ ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ–ˆ๋˜ ์‚ฌ๋žŒ๋“ค์ด์ฃ .
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ arr[-1]๊ณผ ๊ฐ™์€ ํ‘œ๊ธฐ๋Š” ์œ ํšจํ•œ ๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ์ž…๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋ฐฐ์—ด์„ ํฌํ•จํ•œ ๋ชจ๋“  ๊ฒƒ์€ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ์–ธ์ œ๋“ ์ง€ ์šฐ๋ฆฌ๋Š” arr[0]๊ณผ ๊ฐ™์€ ๋Œ€๊ด„ํ˜ธ ํ‘œ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ ์ค‘ 0์ด๋ผ๋Š” ํ‚ค๋ฅผ ๊ฐ€์ง€๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐ์ฒด ํ‘œ๊ธฐ ๋ฐฉ๋ฒ•์œผ๋กœ arr ๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•ด๋ณธ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์„ ๊ฒ๋‹ˆ๋‹ค.

const arr = {
  0: 1,
  1: 2,
  3: "three",
  // ...
};

console.log(arr[0]); // Expected Output: 1

์œ„ ์ฝ”๋“œ์—์„œ -1์„ key๋กœ ๊ฐ€์ง€๋Š” ๊ฐ’์€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ arr[-1]์€ undefined๋ฅผ ๋ฐ˜ํ™˜ํ•  ๊ฒ๋‹ˆ๋‹ค.
๋งŒ์•ฝ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ ์ค‘์— -1 key๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด ๊ทธ์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

const arr = {
  "-1": "valid"
};

console.log(arr[-1]); // Expected Output: valid

์ฆ‰, ์ด๋ฏธ ํ•ด๋‹น ๋ฌธ๋ฒ•์€ ์œ ํšจํ•œ ๋ฌธ๋ฒ•์ด๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ arr[-1] ํ‘œ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค.
๋ฐฐ์—ด์˜ ๋์—์„œ๋ถ€ํ„ฐ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ์Œ์ˆ˜์˜ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด .at() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

.at() ๋ฌธ๋ฒ•

.at() ๋ฉ”์†Œ๋“œ๋Š” ๋ฆฌํ„ด๋ฐ›์„ ์š”์†Œ์˜ ์ธ๋ฑ์Šค๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค. ์Œ์ˆ˜ ์ธ๋ฑ์Šค๋ฅผ ๋ฐ›์œผ๋ฉด ๋ฐฐ์—ด์ด๋‚˜ ๋ฌธ์ž์—ด์˜ ๋’ค์—์„œ๋ถ€ํ„ฐ ์ธ๋ฑ์Šค๋ฅผ ์„ธ์–ด ํ•ด๋‹น ์š”์†Œ๋‚˜ ๋ฌธ์ž๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ undefined๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

at(index)

.at() ๋ฉ”์†Œ๋“œ ์‚ฌ์šฉํ•˜๊ธฐ

์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ .at()๋Š” ๋ฐ˜ํ™˜๋ฐ›์„ ์š”์†Œ์˜ ์ธ๋ฑ์Šค๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. ์ด ์„น์…˜์—์„œ๋Š” ์œ ์ฆˆ์ผ€์ด์Šค๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
arr ๋ฐฐ์—ด๋กœ ๋‹ค์‹œ ์˜ฌ๋ผ๊ฐ€ ์–ด๋–ป๊ฒŒ .at() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜๋ฐ›๋Š”์ง€ ๋ด…์‹œ๋‹ค.

const arr = [1, 2, "three", 4, 5, true, false];

console.log(arr.at(0)); // Expected Output: 1
console.log(arr.at(2)); // Expected Output: "three"
console.log(arr.at(-1)); // Expected Output: false
console.log(arr.at(-3)); // Expected Output: 5

.at() ๋ฉ”์†Œ๋“œ์— ์–‘์ˆ˜ ์ธ๋ฑ์Šค๋ฅผ ์ „๋‹ฌํ•˜๋ฉด, ๋ฉ”์†Œ๋“œ๋Š” ํ•ด๋‹น ์ธ๋ฑ์Šค๋ฅผ ๊ฐ€์ง€๋Š” ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์Œ์ˆ˜์˜ ์ธ๋ฑ์Šค์ธ ๊ฒฝ์šฐ์—๋Š” ๋ฐฐ์—ด์˜ ๋์—์„œ๋ถ€ํ„ฐ์˜ ์ธ๋ฑ์Šค์— ํ•ด๋‹นํ•˜๋Š” ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์œ„ ์ฝ”๋“œ์—์„œ at(-1)๋Š” ๋ฐฐ์—ด์˜ ๋์—์„œ๋ถ€ํ„ฐ 1๊ฐœ๋ฅผ ์„ธ์–ด false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ at(-3)์€ ๋์—์„œ๋ถ€ํ„ฐ ์„ธ๋ฒˆ์งธ์— ์žˆ๋Š” 5๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ž์—ด์—์„œ๋„ ๋ฐฐ์—ด๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

const str = "The last alphabet is z";

console.log(str.at(0)); // Expected Output: T
console.log(str.at(-1)); // Expected Output: z

์ด ๋ฉ”์†Œ๋“œ๋Š” ์‚ฌ์šฉํ•˜๊ธฐ์— ์•„์ฃผ ์ข‹์Šต๋‹ˆ๋‹ค. at(-1)์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ž์—ด์—์„œ ๊ฐ€์žฅ ๋์— ์žˆ๋Š” ๋ฌธ์ž๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋™์ผํ•œ ๋™์ž‘์„ length ํ”„๋กœํผํ‹ฐ๋ฅผ ์ด์šฉํ•œ๋‹ค๋ฉด ๋ฌธ๋ฒ•์€ ๋”์šฑ ๋ณต์žกํ•ด์ง‘๋‹ˆ๋‹ค.

console.log(str[str.length - 1]); // Expected Output: z

ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’ ์‚ฌ์šฉํ•˜๊ธฐ

length ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์™€ ๋‹ค๋ฅด๊ฒŒ at() ๋ฉ”์†Œ๋“œ๋Š” ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ์ €์žฅํ•ด์•ผ ํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.
๋‹ค์Œ์€ ๋ฐฐ์—ด์— ๋งˆ์ง€๋ง‰์œผ๋กœ ์‚ฝ์ž…๋œ ์š”์†Œ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

function appendNumber(arr, N) {
  arr.push(N);
  return arr;
}

console.log(appendNumber([1, 2, "three", 4, 5, true, false], 6).at(-1));
// Expected Output: 6

์ฝ”๋“œ์—์„œ .at() ๋ฉ”์†Œ๋“œ๋Š” ๋ฐ˜ํ™˜๋œ ๊ฐ’์— ๋ฐ”๋กœ ์ ์šฉ๋˜์–ด ๋ณ€์ˆ˜์— ๊ฐ’์„ ์ €์žฅํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.
์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค.

const arr = [1, 2, "three", 4, 5, true, false];
console.log(arr.at(0.6)); // Expected Output: 1
console.log(arr.at(-3.6)); // Expected Output: 5

์œ„ ์ฝ”๋“œ์—์„œ ์ฒซ ๋ฒˆ์งธ ์ถœ๋ ฅ์€ 0 ์ธ๋ฑ์Šค์— ํ•ด๋‹นํ•˜๋Š” ์š”์†Œ์ด์ง€๋งŒ ๋‘ ๋ฒˆ์งธ ์ถœ๋ ฅ์€ ๋์—์„œ๋ถ€ํ„ฐ ์„ธ ๋ฒˆ์งธ ์š”์†Œ์ž…๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ๋ฌด์ž‘์œ„๋กœ ๋ฐฐ์—ด์˜ ์š”์†Œ๋ฅผ ์„ ํƒํ•˜๊ณ  ์‹ถ์„ ๋•Œ ๊ฝค ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ๊ฐ€์œ„๋ฐ”์œ„๋ณด ๊ฒŒ์ž„ ํ”„๋กœ์ ํŠธ๋กœ ์„ค๋ช…ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
์ปดํ“จํ„ฐ์—์„œ ๋žœ๋ค์œผ๋กœ ์„ ํƒํ•˜๊ธฐ ์œ„ํ•ด .at() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์–ด๋–ป๊ฒŒ ์ปดํ“จํ„ฐ๊ฐ€ ๋ฌด์ž‘์œ„๋กœ ์„ ํƒํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

const computerOptions = ["rock", "paper", "scissors"];
const randomIndex = Math.random() * computerOptions.length;

console.log(computerOptions.at(randomIndex));

Math.random()์„ ์‚ฌ์šฉํ•˜๋ฉด 0 ์ด์ƒ ๋ฐฐ์—ด ๊ธธ์ด ๋ฏธ๋งŒ ์‚ฌ์ด์˜ ์ˆ˜๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.
.at() ๋ฉ”์†Œ๋“œ๊ฐ€ ์ธ๋ฑ์Šค๋กœ ๋ถ€๋™์†Œ์ˆ˜์  ์ˆ˜๋ฅผ ๋ฐ›๊ฒŒ๋˜๋ฉด ์†Œ์ˆ˜์  ์•ž์˜ ์ˆ˜๋ฅผ ๊ณ ๋ คํ•˜์—ฌ ํ•ด๋‹น ์ธ๋ฑ์Šค์˜ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ™์€ ๋™์ž‘์„ ํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด floor ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€๊นŒ์šด ์ •์ˆ˜๋กœ ๋ณ€ํ™˜ํ•˜์ง€ ์•Š๋Š” ํ•œ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

const computerOptions = ["rock", "paper", "scissors"];
const randomIndex = Math.random() * computerOptions.length;

console.log(computerOptions.at(randomIndex));

๋Œ€๊ด„ํ˜ธ ํ‘œ๊ธฐ๋ฐฉ์‹์€ ํ•ด๋‹น ์ˆ˜๋ฅผ ๊ฐ€์ง€๋Š” ๊ฐ’์ด ์—†์œผ๋ฏ€๋กœ undefined๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

const arr = [1, 2, "three", 4, 5, true, false];
console.log(arr[0.6]); // Expected Output: undefined

.at() ๋ฉ”์†Œ๋“œ๋Š” Math.floor๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋žœ๋ค ์ˆ˜๋ฅผ ๋‚ด๋ฆผํ•˜๋Š” ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ € ์ง€์›

์ด ํŠœํ† ๋ฆฌ์–ผ์„ ์ž‘์„ฑํ•  ์‹œ์ ์„ ๊ธฐ์ค€์œผ๋กœ .at() ๋ฉ”์†Œ๋“œ๋Š” ๊ทนํžˆ ์ผ๋ถ€๋ฅผ ์ œ์™ธํ•œ ๋Œ€๋ถ€๋ถ„์˜ ๋ชจ๋˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ฝค ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
๋ธŒ๋ผ์šฐ์ € ์ง€์›์€ ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

image

๊ฒฐ๋ก 

.at() ๋ฉ”์†Œ๋“œ๋Š” ์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ ๋ดค๋“ฏ์ด ์ธ๋ฑ์Šค๋กœ๋ถ€ํ„ฐ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๋” ํŽธํ•˜๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.
๋˜ํ•œ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๋ฐฉ๋ฒ•๋“ค๊ณผ ๋น„๊ตํ–ˆ์„ ๋•Œ ๋”์šฑ ๊ฐ„๊ฒฐํ•˜๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] Recoil 0.6

์›๋ฌธ : https://recoiljs.org/blog/2022/01/28/0.6.0-release/

Recoil 0.6์ด ๋™์‹œ์„ฑ ๋ Œ๋”๋ง๊ณผ ์ „ํ™˜๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ƒˆ๋กœ์šด API์™€ ์ˆ˜์ •์‚ฌํ•ญ, ์ตœ์ ํ™” ๋“ฑ๊ณผ ํ•จ๊ป˜ React 18์— ๋Œ€ํ•ด ๋” ํ–ฅ์ƒ๋œ ์ง€์›๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

React 18

Recoil 0.6์€ ํ–ฅ์ƒ๋œ ์•ˆ์ „์„ฑ๊ณผ ์„ฑ๋Šฅ์„ ์œ„ํ•ด React 18์˜ ์ตœ์‹  API๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ ๋ฆด๋ฆฌ์ฆˆ๋Š” concurrent rendering๊ณผ <React.StrictMode> ๋ชจ๋‘ ์–‘๋ฆฝ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์‹œ์„ฑ ๋ Œ๋”๋ง์— ๋Œ€ํ•ด ์ž ์žฌ์ ์ธ ์ด์Šˆ๋“ค์„ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์‹๋ณ„ํ•˜๊ธฐ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ํ•ธ๋“ค๋Ÿฌ์™€ ์ฝœ๋ฐฑ์—์„œ Recoil๊ณผ React ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ ์ผ๊ด€๋˜๋Š” ์ƒํƒœ์˜ ๋ทฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฐœ์„ ์‚ฌํ•ญ๋“ค ์ค‘ ์ผ๋ถ€๋Š” React ์ด์ „ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. React 18๋กœ ์‹คํ—˜ํ•˜์‹ ๋‹ค๋ฉด ์ตœ์‹  RC ๋นŒ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ์˜ค๋ฆฌ์ง€๋„ React 18.0.0-rc.0 ํŒจํ‚ค์ง€์—๋Š” ๊ทธ ์ดํ›„ ์ˆ˜์ •๋œ ๋ฒ„๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋™์‹œ์„ฑ ๋ Œ๋”๋ง๊ณผ ์ „ํ™˜

React 18์€ ์ƒํƒœ๊ฐ€ ์ค€๋น„๋˜๊ธฐ ์ „์— ๋ Œ๋”๋งํ•  ํ•ญ๋ชฉ์„ ์ œ์–ดํ•˜๋Š” ๋™์‹œ์— ์ƒˆ๋กœ์šด ์ƒํƒœ๋กœ ์ „ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์ƒˆ๋กœ์šด hook, useTransition()์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Recoil์€ ์ด๋Ÿฌํ•œ ์ ‘๊ทผ๋ฐฉ์‹๊ณผ ํ˜ธํ™˜๊ฐ€๋Šฅํ•˜๋ฉฐ React ์ƒํƒœ์— ๋Œ€ํ•œ ์ผ๊ด€์ ์ธ ๋ทฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, React 18์€ ๋™์‹œ์ ์ธ ์—…๋ฐ์ดํŠธ์—์„œ ๋ฌผ๋Ÿฌ๋‚  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์•„์ง ๊ณต์‹์ ์œผ๋กœ ์™ธ๋ถ€ ์ €์žฅ์†Œ์— ๋Œ€ํ•œ ์ƒํƒœ ๋ณ€๊ฒฝ๊ฐ’๋“ค์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ์ „ํ™˜์€ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฆฌ์•กํŠธ ํŒ€์—์„œ ์ง€์›ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ธฐ๋Šฅ์ด์ง€๋งŒ ๋‹ค์Œ์˜ hook์„ ํ†ตํ•ด ์‹คํ—˜์ ์ธ ์ง€์›์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด API๋Š” ์•„์ง ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ์œ ์ฆˆ์ผ€์ด์Šค๋“ค์ด ์žˆ์œผ๋ฏ€๋กœ ์‹คํ—˜์ ์ž…๋‹ˆ๋‹ค.

  • useRecoilState_TRANSITION_SUPPORT_UNSTABLE()
  • useRecoilValue_TRANSITION_SUPPORT_UNSTABLE()
  • useRecoilValueLoadable_TRANSITION_SUPPORT_UNSTABLE()

์ƒˆ๋กœ์šด ๊ฒฐ๊ณผ๊ฐ’์ด ๋กœ๋”ฉ๋˜๋Š” ๋™์•ˆ ํ˜„์žฌ์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ณด์—ฌ์ฃผ๋Š” ์•„๋ž˜ ์˜ˆ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

function QueryResults() {
  const queryParams = useRecoilValue_TRANSITION_SUPPORT_UNSTABLE(queryParamsAtom);
  const results = useRecoilValue_TRANSITION_SUPPORT_UNSTABLE(myQuerySelector(queryParams));
  return results;
}

function MyApp() {
  const [queryParams, setQueryParams] = useRecoilState_TRANSITION_SUPPORT_UNSTABLE(queryParamsAtom);
  const [inTransition, startTransition] = useTransition();
  return (
    <div>
      {inTransition ? <div>[Loading new results...]</div> : ''}
      Results: <React.Suspense><QueryResults /></React.Suspense>
      <button
        onClick={() => {
          startTransition(() => {
            setQueryParams(...new params...);
          });
        }
      >
        Start New Query
      </button>
    </div>
  );
}

์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ

  • Recoil ์ฝœ๋ฐฑ
    • useRecoilCallback()์€ ์…€๋ ‰ํ„ฐ ์บ์‹œ๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ useRecoilRefresher_UNSTABLE()์™€ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.
    • getCallback()์„ ์‚ฌ์šฉํ•˜๋Š” ์…€๋ ‰ํ„ฐ์˜ ์ฝœ๋ฐฑ์€ useRecoilCallback()์™€ ๋น„์Šทํ•˜๊ฒŒ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ , ์ƒˆ๋กœ๊ณ ์นจํ•˜๊ณ  ํŠธ๋žœ์žญ์…˜์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ ์ด๋ฅผ ์ฝ๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ์ €์žฅ์†Œ ID - StoreID๋Š” useRecoilStoreID()๋‚˜ atom effects์˜ storeID ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • RecoilLoadable.of() and RecoilLoadable.all() ํŒฉํ† ๋ฆฌํ•จ์ˆ˜๋“ค์€ ๋ฆฌํ„ฐ๋Ÿด ๊ฐ’์ด๋‚˜ async Promises ๋˜๋Š” Loadable์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค๏ฟฝ. ์ด๋Š” Promise.resolve()์™€ Promise.all()์— ํ•„์ ํ•ฉ๋‹ˆ๋‹ค.
  • ์Šค๋ƒ…์ƒท์— .isRetained() ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ .retain()์„ ํ†ตํ•ด ์Šค๋ƒ…์ƒท์ด ๋ฆด๋ฆฌ์ฆˆ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] ๋‹น์‹ ์ด ์•Œ์•„์•ผ ํ•˜๋Š” 6๊ฐ€์ง€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํƒ€์ž…์‹œ์Šคํ…œ ํŠธ๋ฆญ๋“ค

์›๋ฌธ : 6 TypeScript Typing System Tricks You Should Know์„ ์ฝ๊ณ  ๋ฒˆ์—ญํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ํƒ€์ž…์— ๋Œ€ํ•œ ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ ํƒ€์ž„์— ํƒ€์ž… ์ฒดํฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ ๊ฐ•๋ ฅํ•œ ํƒ€์ž… ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ๋™์‹œ์— ์ •์  ํƒ€์ž…์€ ์„ ํƒ ์‚ฌํ•ญ์ด๋ฏ€๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ํ˜ธํ™˜์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ €๋Š” 3๋…„ ์ด์ƒ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ์ผ์„ ํ•ด์™”์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๊ฐ„ ๋™์•ˆ ๋งŽ์€ ๊ฒƒ๋“ค์„ ๋ฐฐ์› ์ง€๋งŒ ๋งค์ผ ์ผ์„ ํ•˜๋ฉด์„œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด๋‚˜ ํŠธ๋ฆญ์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์—ฌ์ „ํžˆ ๋†€๋ผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํƒ€์ž… ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋ฐฐ์šด ์—ฌ๋Ÿฌ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋“ค์„ ์†Œ๊ฐœํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Be Specific : ๊ตฌ์ฒดํ™”ํ•˜๋ผ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ, ํƒ€์ž…์€ ๋ฐ์ดํ„ฐ์˜ ํ˜•ํƒœ๋‚˜ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ํƒ€์ž…์— ๋Œ€ํ•œ ์ •๋ณด๋กœ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์—ฌ๋Ÿฌ๋ถ„์—๊ฒŒ ์ปดํŒŒ์ผ ์‹œ์ ์— ๊ฐ์ง€ํ•œ ์—๋Ÿฌ์— ๋Œ€ํ•ด ๋น ๋ฅด๊ฒŒ ์ฃผ์˜๋ฅผ ์ค„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋Ÿฐํƒ€์ž„์— ์—๋Ÿฌ๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ๋Œ€์‹ ์—์š”.

ํƒ€์ž…์„ ์ •์˜ํ•  ๋•Œ, ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ฒด์ ์œผ๋กœ ํ•˜๊ณ  ์‹ถ์„ ๊ฒ๋‹ˆ๋‹ค. ๊ฐ„๊ฒฐํ•œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋” ์ผ์„ ์ž˜ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ์ž˜ ์ •์˜๋œ ํƒ€์ž…์€ ์Šค์Šค๋กœ ์„ค๋ช…ํ•˜๋Š” ๋ฌธ์„œ๋กœ์„œ์˜ ์—ญํ• ์„ ํ•˜๊ณ  ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ๋†’์—ฌ์ค๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ๊ทœ์น™์€ ๋” ๊ฐ„๊ฒฐํ•  ์ˆ˜๋ก ๋” ์ข‹๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ํž˜์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๊ตฌ์กฐ์  ํƒ€์ž…, ๋งคํ•‘๋œ ํƒ€์ž…, ์ปจํŠธ๋กค ํ”Œ๋กœ์šฐ ๊ธฐ๋ฐ˜์˜ ๋ถ„์„์ด ์žˆ๋Š” ์กฐ๊ฑด ํƒ€์ž…, ํƒ€์ž… ์ถ”๋ก (type inference), ํƒ€์ž… ๋‹จ์–ธ(type assertion)์„ ์ œ๊ณตํ•œ๋‹ค๋Š” ์‚ฌ์‹ค๋กœ๋ถ€ํ„ฐ ์˜ต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด PayGrade๋ผ๋Š” ํƒ€์ž…์ด ์žˆ๋‹ค๊ณ  ํ•ฉ์‹œ๋‹ค.

type PayGrade: number;

1๋ถ€ํ„ฐ 5๊นŒ์ง€์˜ ์ˆซ์ž์— ๋Œ€ํ•œ ํƒ€์ž…์ด๋ผ๊ณ  ์ข€ ๋” ๊ตฌ์ฒด์ ์œผ๋กœ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

type PayGrade: 1 | 2 | 3| 4 | 5;

์—ฌ๋Ÿฌ๋ถ„์ด ํƒ€์ž…์„ ๋” ์˜๋ฏธ์žˆ๊ฒŒ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const payGrade = {
  low : 1,
  average : 2,
  good : 3,
  better : 4,
  best : 5} as const;
type PayGrade = typeof payGrade[keyof typeof payGrade]

์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ์— ๊ฐ•๋ ฅํ•œ ํƒ€์ž…์„ ๋”ํ•ด์ฃผ๋ฉด ์ฝ”๋“œ๋Š” ๋”์šฑ ๊ฐ•ํ•ด์ง‘๋‹ˆ๋‹ค.

Enable Strict Mode : Strict ๋ชจ๋“œ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ผ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ strict ๋ชจ๋“œ๋Š” ํƒ€์ž… ์ฒดํฌ์˜ ๊ทœ์น™์„ ๋”์šฑ ์—„๊ฒฉํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•˜๋ฉด strict ๋ชจ๋“œ๋Š” ํ™œ์„ฑํ™” ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” tsconfig.json์—์„œ ์„ค์ •์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

{  "compilerOptions": 
    {    
        "strict": true,  
    }
}

strict ๋ชจ๋“œ๋Š” ์‚ฌ์‹ค ์ผ๊ณฑ๊ฐ€์ง€ ์˜ต์…˜์˜ ์ถ•์•ฝ ํ‘œํ˜„์ด๊ณ , ์„ธ๋ฐ€ํ•œ ์ปจํŠธ๋กค์„ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๊ฐ ์˜ต์…˜์„ ๋ถ„๋ฆฌํ•ด์„œ on/off๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์—ฌ๋Ÿฌ๋ถ„์ด ํ˜„์žฌ ์กด์žฌํ•˜๋Š” ํ”„๋กœ์ ํŠธ๋กœ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ๊ณ  ๋ชจ๋“  ์˜ต์…˜์„ ํ™œ์„ฑํ™”ํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด, ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ๊ทœ์น™์ด ๋‹ค๋ฅธ ๊ฒƒ๋ณด๋‹ค ๋”์šฑ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

  • noImplicitAny : any ํƒ€์ž…์€ ์—๋Ÿฌ ๋ฐฉ์ถœ
  • strictNullChecks : ๋ช…์‹œ์ ์œผ๋กœ ํ—ˆ์šฉ๋œ ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ฉด ๋ณ€์ˆ˜์— null์ด๋‚˜ undefined๋ฅผ ํ• ๋‹นํ•  ์ˆ˜ ์—†์Œ

๋‚˜๋จธ์ง€ ๊ทœ์น™์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • noImplicitThis : any ํƒ€์ž…์˜ this๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์—†์Œ
  • alwaysStrict : ๋ชจ๋“  ์ปดํŒŒ์ผ๋œ JS ํŒŒ์ผ ์ƒ๋‹จ์— "use strict"๋ฅผ ์„ค์ •
  • strictBindCallApply : bind, call, apply ๋ฉ”์†Œ๋“œ์— strict ์ฒดํฌ
  • strictFunctionTypes : ํ•จ์ˆ˜ ํƒ€์ž… ์ฒดํฌ๋ฅผ ๊ธฐ๋ณธ๊ฐ’์ธ _bivariant_๊ฐ€ ์•„๋‹Œ _contravariant_๋กœ ์„ค์ •
  • strictPropertyInitialization : ์ƒ์„ฑ์ž์—์„œ ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ์— ๊ธฐ๋ณธ๊ฐ’์ด๋‚˜ ์ดˆ๊ธฐํ™”๋˜๋„๋ก ๊ฐ•์ œ

Apply Type Parameter Constraint to Generices : ์ œ๋„ค๋ฆญ์— ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์˜ ์ œ์•ฝ์กฐ๊ฑด์„ ๊ฐ•์ œํ•˜๋ผ

์ œ๋„ค๋ฆญ์€ ํƒ€์ž…์ด ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ œ๋„ค๋ฆญ ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์—ฌ๋Ÿฌ๋ถ„์€ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ œ์•ฝ์กฐ๊ฑด์„ ์„ ์–ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค๋ฅธ ํƒ€์ž…์ด๋‚˜ ์ธํ„ฐํŽ˜์ด์Šค์— ์˜ํ•ด ์ œ์•ฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ๋Š” extends ํ‚ค์›Œ๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ Animal ํƒ€์ž…์˜ ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ œ์•ฝํ•˜๋Š”์ง€ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

type Animal = {
  owner: string;
}
function feedPets<T extends Animal>(pets: T[]): void { }

ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ๋“ค์–ด์™”๋‹ค๋ฉด ์ปดํŒŒ์ผ ์‹œ์ ์—์„œ ์—๋Ÿฌ๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐœ์ƒํ•  ๊ฒ๋‹ˆ๋‹ค.

![])(https://miro.medium.com/max/700/1*UJ2sg0TMILHr4a9BYDup4w.png)

Use Type Inference Instead of Explicit Declaration : ๋ช…์‹œ์ ์ธ ์„ ์–ธ๋ณด๋‹ค ํƒ€์ž… ์ถ”๋ก ์„ ์‚ฌ์šฉํ•˜๋ผ

์ฝ”๋“œ๋ฅผ ๋‹จ์ˆœํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ํƒ€์ž… ์ถ”๋ก ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๋ณ€์ˆ˜๋‚˜ ๋ฆฌํ„ด ํƒ€์ž…์„ ํฌํ•จํ•œ ๊ฐ„๋‹จํ•œ ํƒ€์ž… ํ‘œํ˜„์„ ํ†ตํ•ด ํƒ€์ž…์„ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŽ์€ ๊ฒฝ์šฐ์— ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธํ•  ์ด์œ ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ๊ฐ„๋‹จํ•˜๋Š” ๊ฒŒ ๋” ์ข‹์Šต๋‹ˆ๋‹ค.

const x: string = 'John'; // string is redundant here

๊ทธ๋Ÿฌ๋‚˜ ์˜ˆ์™ธ๋Š” ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ํ‘œํ˜„์˜ ๊ฒฝ์šฐ ๋ช…์‹œ์ ์ธ ํƒ€์ž… ์„ ์–ธ์ด ๊ฐ€๋…์„ฑ์— ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์˜ˆ์™ธ๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ ˆ๋Œ€ ์ถ”๋ก ํ•  ์ˆ˜ ์—†๋Š” ํ•จ์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ํƒ€์ž… ์ถ”๋ก ์ด ์—†๋‹ค๋ฉด ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” any ํƒ€์ž…์ด ์‚ฌ์šฉ๋  ๊ฒ๋‹ˆ๋‹ค.

ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด ํƒ€์ž…์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์— ์˜ํ•ด ์ถ”๋ก ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•จ์ˆ˜๊ฐ€ ๋ณต์žกํ•œ ๋ฆฌํ„ด ํƒ€์ž…์„ ๊ฐ€์ง„๋‹ค๋ฉด, ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ๋ช…์‹œ์ ์œผ๋กœ ํƒ€์ž…์„ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ์Šต๋‹ˆ๋‹ค.

Use any As Little as Possible : ๊ฐ€๋Šฅํ•œ any๋ฅผ ์ ๊ฒŒ ์‚ฌ์šฉํ•˜๋ผ

๋Œ€๋ถ€๋ถ„์€ any๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. any๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ฝ”๋“œ๋ฅผ ๊ณ„์† ์“ฐ๊ฒŒ ํ•˜๋Š” ๋น ๋ฅธ ๋ฐฉ๋ฒ•์ด๊ธฐ๋„ ํ•˜์ง€๋งŒ ์ด๋Š” ์ปดํŒŒ์ผ ์‹œ์ ์— ๋ฐœ์ƒํ•  ์—๋Ÿฌ ๋˜๋Š” ์ž ์žฌ์ ์ธ ์—๋Ÿฌ๋ฅผ ์ˆจ๊ธฐ๊ณ  ์žˆ์„ ๋ฟ์ž…๋‹ˆ๋‹ค. ์ฆ‰, any ํƒ€์ž…์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ๊ฐ€์žฅ ํฐ ์ด์ ์ธ ๊ฐ•๋ ฅํ•œ ํƒ€์ดํ•‘์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด์ฃ .

๋Œ€์‹ ์— unknown์„ ์‚ฌ์šฉํ•˜์„ธ์š”. unknown ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ํƒ€์ž…์„ ์ •ํ•˜๊ฑฐ๋‚˜ ์ขํžˆ์ง€๋Š” ์•Š๊ณ ์„œ๋Š” ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

const data: unknown = value;

Immutability With readonly :

immutability๋Š” ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋ฅผ ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ํ•˜๊ณ  ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ๋กœ๋ถ€ํ„ฐ ์˜ค๋Š” ๋ณต์žก์„ฑ์„ ์ค„์—ฌ์ค๋‹ˆ๋‹ค. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” immutability๋ฅผ ์ง€ํ‚ค๋„๋ก readonly ๋ณ€๊ฒฝ์ž์™€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž…์ธ Readonly๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

readonly ๋ณ€๊ฒฝ์ž๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋‚˜ ํด๋ž˜์Šค์˜ ํ”„๋กœํผํ‹ฐ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ณ  ์žฌํ• ๋‹น์„ ๋ง‰์Šต๋‹ˆ๋‹ค.

class Fish {
   constructor(public readonly name: string) {}
}

Readonly<T>๋Š” ์ œ๋„ค๋ฆญ ํƒ€์ž… T์˜ ์ปดํŒŒ์ผ ์‹œ์ ์˜ ํ”„๋กœํผํ‹ฐ์— readonly ๋ณ€๊ฒฝ์ž๋ฅผ ์ ์šฉํ•˜๊ฒŒ ํ•˜๋Š” ํƒ€์ž…์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” T๋กœ ๊ตฌ์„ฑ๋œ ํ”„๋กœํผํ‹ฐ์—๋Š” ์žฌํ• ๋‹น์„ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž…์ด ๊ณต์œ ๋  ๋•Œ Readonly ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž…์œผ๋กœ immutable ํƒ€์ž…์„ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์€ ์•„์ฃผ ์ข‹์Šต๋‹ˆ๋‹ค.

readonly ๋ณ€๊ฒฝ์ž์™€ Readonly ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž… ๋‘˜ ๋‹ค ๋Ÿฐํƒ€์ž„์ด ์•„๋‹Œ ์ปดํŒŒ์ผ ์‹œ์ ์—๋งŒ ํšจ๊ณผ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ฃผ๋ชฉํ•˜์„ธ์š”.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ readonly๋‚˜ ์ƒ์ˆ˜์— ๋Œ€ํ•ด ๋” ์ฝ๊ณ  ์‹ถ์œผ์‹œ๋ฉด ๋‹ค๋ฅธ ์•„ํ‹ฐํด์„ ์ฝ์–ด์ฃผ์„ธ์š”.

How to Share Constants in Typescript Project

์š”์•ฝ

์ด ์•„ํ‹ฐํด์—์„œ๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํƒ€์ž…์— ๊ด€ํ•œ ๋ชจ๋ฒ”์ ์ธ ๋ฐฉ๋ฒ•๋“ค์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํƒ€์ž…์„ ๊ตฌ์ฒด์ ์œผ๋กœ ์„ ์–ธํ•˜๊ณ  ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ํƒ€์ž… ์‹œ์Šคํ…œ์„ ์ž˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์šฐ๋ฆฌ์˜ ์ฝ”๋“œ๋ฅผ ๊ฐ€๋…์„ฑ์žˆ๊ฒŒ, ์œ ์ง€๊ฐ€ ์šฉ์ดํ•˜๊ฒŒ, ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

์ด ์•„ํ‹ฐํด์ด ๋งˆ์Œ์— ๋“œ์…จ๋‹ค๋ฉด ์ œ๊ฐ€ ์ž‘์„ฑํ•œ ๋‹ค๋ฅธ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์•„ํ‹ฐํด์„ ์ฝ์–ด๋ณด์„ธ์š”.

[๋ฒˆ์—ญ] ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ํƒ€์ž… ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์†Œ๊ฐœ

์›๋ฌธ : https://www.zhenghao.io/posts/type-programming

ํƒ€์ž… ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํƒ€์ž… ์ž‘์„ฑํ•˜๋Š” ๋ฒ•์„ ๋ฐฐ์šฐ๊ณ  ์—ฌ๋Ÿฌ๋ถ„์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์‹ค๋ ฅ์„ ํ™œ์šฉํ•˜์—ฌ ๋” ๋นจ๋ฆฌ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งˆ์Šคํ„ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํƒ€์ž…์€ ๊ทธ ์ž์ฒด๋กœ ๋ณต์žกํ•œ ์–ธ์–ด๋‹ค

์ €๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‹จ์ง€ ํƒ€์ž… ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ฟŒ๋ ค์ ธ ์žˆ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ƒ๊ฐํ•˜๊ณค ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋งˆ์Œ๊ฐ€์ง์œผ๋กœ๋Š” ์ข…์ข… ์ •ํ™•ํ•œ ํƒ€์ž…์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒŒ ๊ฝค ๊นŒ๋‹ค๋กญ๊ณ  ์–ด๋ ต๋‹ค๋Š” ๊ฑธ ์•Œ๊ฒŒ ๋˜์—ˆ๊ณ , ํƒ€์ž…๋“ค์€ ์ œ๊ฐ€ ๋งŒ๋“ค๊ณ ์ž ํ•˜๋Š” ์‹ค์ œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐ ๋ฐฉํ•ด๊ฐ€ ๋˜์—ˆ์ฃ . ๊ทธ๋ž˜์„œ ์ข…์ข… ์ €๋Š” any๋ผ๋Š” ์ตœํ›„์˜ ํ•ด๊ฒฐ์ฑ…์— ๋„๋‹ฌํ•˜๊ณค ํ–ˆ๊ณ  ๊ฒฐ๊ตญ ํƒ€์ž…์˜ ์•ˆ์ „์„ฑ๊นŒ์ง€ ์žƒ์–ด๋ฒ„๋ ธ์Šต๋‹ˆ๋‹ค.

๊ฒŒ๋‹ค๊ฐ€ ์—ฌ๋Ÿฌ๋ถ„์ด ํ•˜๋Š” ๊ฒƒ์— ๋”ฐ๋ผ ํƒ€์ž…์€ ์•„์ฃผ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ๋™์•ˆ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ์ฝ”๋“œ๋ฅผ ์“ฐ๊ณ  ๋‚˜์„œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์‹ค์ œ๋กœ ๋‘ ๊ฐœ์˜ ์–ธ์–ด๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ, ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ํƒ€์ž… ์–ธ์–ด๋ผ๊ณ  ๋ง์ž…๋‹ˆ๋‹ค.

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์–ธ์–ด์˜ ๊ฒฝ์šฐ ์„ธ๊ณ„๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ’์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํƒ€์ž… ์–ธ์–ด์˜ ๊ฒฝ์šฐ๋Š” ์„ธ๊ณ„๋Š” ํƒ€์ž…์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์šฐ๋ฆฌ๋Š” ๋Š์ž„์—†์ด ๋‘ ์„ธ๊ณ„ ์‚ฌ์ด์—์„œ ์™”๋‹ค๊ฐ”๋‹ค ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž… ์„ธ๊ณ„์—์„œ๋Š” ํƒ€์ž…์„ ๋งŒ๋“ค๊ณ , ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์„ธ๊ณ„๋กœ ๊ฐ€์„œ ํƒ€์ž… ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ํƒ€์ž…์„ "์†Œํ™˜"ํ•ฉ๋‹ˆ๋‹ค. (์ปดํŒŒ์ผ๋Ÿฌ์— ์˜ํ•ด์„œ ์•”๋ฌต์ ์œผ๋กœ ์ถ”๋ก ๋˜๊ณค ํ•ฉ๋‹ˆ๋‹ค.) ๋‹ค๋ฅธ ๋ฐฉํ–ฅ์œผ๋กœ๋„ ๋ฌผ๋ก  ๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ณ€์ˆ˜/ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•ด typeof ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ทธ์— ๋Œ€ํ•œ ํƒ€์ž…์„ ๊ฐ€์ ธ์˜ค๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. (๋Ÿฐํƒ€์ž„ ๊ฐ’์˜ ํƒ€์ž…์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ œ๊ณต๋˜๋Š” typeof ์—ฐ์‚ฐ์ž๋ฅผ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค.)

image

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์–ธ์–ด๋Š” ๋งค์šฐ ํ‘œํ˜„์ ์ธ ํŠน์„ฑ์ด ์žˆ๊ณ  ์ด๋Š” ํƒ€์ž… ์–ธ์–ด๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ํƒ€์ž… ์–ธ์–ด๊ฐ€ ํ‘œํ˜„๋ ฅ์ด ๋›ฐ์–ด๋‚˜์„œ ํŠœ๋ง ์™„์ „ํ•จ์ด ์ฆ๋ช…๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ํŠœ๋ง ์™„์ „์„ฑ์ด ์ข‹์€์ง€ ๋‚˜์œ์ง€์— ๋Œ€ํ•œ ๊ฐ€์น˜ ํŒ๋‹จ์€ ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ฉฐ, ๊ทธ๊ฒƒ์ด ์„ค๊ณ„์— ์˜ํ•œ ๊ฑด์ง€ ์šฐ์—ฐ์— ์˜ํ•œ ๊ฑด์ง€ ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. (์‚ฌ์‹ค ์ข…์ข… ํŠœ๋ง ์™„์ „์„ฑ์€ ์šฐ์—ฐํžˆ ๋‹ฌ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.) ์ œ๊ฐ€ ๋งํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฐ”๋Š” ํƒ€์ž… ์–ธ์–ด ์ž์ฒด๋Š” ๋ณด์ด๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์œ„ํ—˜ํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์•„์ฃผ ๊ฐ•๋ ฅํ•˜๊ณ  ์œ ๋Šฅํ•˜๋ฉฐ ์ปดํŒŒ์ผ ์‹œ์ ์—์„œ ์ž„์˜์˜ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

์ œ๊ฐ€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ํƒ€์ž… ์–ธ์–ด๋ฅผ ์™„์ „ํ•œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋กœ์„œ ์ƒ๊ฐํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์„ ๋•Œ ์ด ์–ธ์–ด๊ฐ€ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์˜ ๋ช‡ ๊ฐ€์ง€ ํŠน์„ฑ์„ ๊ฐ–๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค.

  • ๋ฐ˜๋ณต ๋Œ€์‹  ์žฌ๊ท€๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์ 
    • TypeScript 4.5 ๋ฒ„์ „์—์„œ tail call์— (์–ด๋Š ์ •๋„) ์ตœ์ ํ™”๋œ ์žฌ๊ท€๊ฐ€ ์žˆ์Œ
  • ํƒ€์ž…์€ ๋ถˆ๊ฐ€๋ณ€์ ์ด๋ผ๋Š” ์ 

์ด ๊ธ€์—์„œ๋Š” ๋” ๋นจ๋ฆฌ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งˆ์Šคํ„ฐํ•˜๊ณ ์ž ๊ฐ–๊ณ  ์žˆ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ง€์‹์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ํƒ€์ž… ์–ธ์–ด๋ฅผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ๋น„๊ตํ•˜์—ฌ ๋ฐฐ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ๊ธ€์€ ๋…์ž๋“ค์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์— ์–ด๋Š ์ •๋„ ์ต์ˆ™ํ•˜๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ฐฐ์šฐ๊ณ ์ž ํ•˜์‹ ๋‹ค๋ฉด The TypeScript Handbook์„ ๋จผ์ € ์ฝ์–ด๋ณด์„ธ์š”. ์ด ๊ธ€๋“ค๊ณผ ๊ฒฝ์Ÿํ•˜๋Š” ๋ชฉ์ ์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋ณ€์ˆ˜ ์„ ์–ธ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์„ธ๊ณ„๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ’๋“ค๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๋Š” var, const, let๊ณผ ๊ฐ™์€ ํ‚ค์›Œ๋“œ๋กœ ๊ฐ’๋“ค์„ ์ฐธ์กฐํ•˜๊ธฐ ์œ„ํ•ด ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.

const obj = {name: 'foo'}

ํƒ€์ž… ์–ธ์–ด์—์„œ๋Š”, ์„ธ๊ณ„๋Š” ํƒ€์ž…์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์ฃ . ๊ทธ๋ฆฌ๊ณ  type๊ณผ interface ํ‚ค์›Œ๋“œ๋กœ ํƒ€์ž… ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.

type Obj = {name: string}

"ํƒ€์ž… ๋ณ€์ˆ˜"์— ๋Œ€ํ•œ ๋” ์ •ํ™•ํ•œ ์ด๋ฆ„์€ type synonyms ํ˜น์€ type alias(ํƒ€์ž… ๋ณ„์นญ)์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ณ€์ˆ˜๊ฐ€ ๊ฐ’์„ ์ฐธ์กฐํ•˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•œ ๋น„์œ ๋กœ์„œ "ํƒ€์ž… ๋ณ€์ˆ˜"๋ผ๋Š” ๋‹จ์–ด๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์™„๋ฒฝํ•œ ๋น„์œ ๊ฐ€ ์•„๋‹์ง€๋ผ๋„ ํƒ€์ž… ๋ณ€์ˆ˜๋Š” ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํƒ€์ž… ๋ณ„์นญ์€ ์ด๋ฏธ ์žˆ๋Š” ํƒ€์ž…์— ๋Œ€ํ•œ ์ƒˆ๋กœ์šด ์ด๋ฆ„์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ํƒ€์ž… ์–ธ์–ด์˜ ๊ฐœ๋…์„ ๋” ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•˜๊ณ ์ž ํ•˜๋Š” ๋ชฉ์ ์œผ๋กœ ์ด ๋น„์œ ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํƒ€์ž…๊ณผ ๊ฐ’์€ ์„œ๋กœ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํƒ€์ž…์˜ ํ•ต์‹ฌ์€ ๊ฐ€๋Šฅํ•œ ๊ฐ’๋“ค์˜ ์ง‘ํ•ฉ๊ณผ ๊ฐ’๋“ค์— ๋Œ€ํ•ด ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ณ  ์œ ํšจํ•œ ์ž‘์—…๋“ค์„ ๋‚˜ํƒ€๋‚ธ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋•Œ๋•Œ๋กœ ์ง‘ํ•ฉ์€ ์œ ํ•œํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด type Name = 'foo' | 'bar' ์™€ ๊ฐ™์€ ๊ฒฝ์šฐ์—์„œ ๋ง์ด์ฃ . ๊ทธ๋Ÿฌ๋‚˜ ๋Œ€๋ถ€๋ถ„ ์ง‘ํ•ฉ์€ ๋ฌดํ•œํ•ฉ๋‹ˆ๋‹ค. type Age = number์™€ ๊ฐ™์ด ๋ง์ž…๋‹ˆ๋‹ค. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์“ธ ๋•Œ ์šฐ๋ฆฌ๋Š” ํƒ€์ž…๊ณผ ๊ฐ’์„ ๊ฒฐํ•ฉํ•˜๊ณ  ๋Ÿฐํƒ€์ž„ ์‹œ์ ์˜ ๊ฐ’๊ณผ ์ปดํŒŒ์ผ ์‹œ์ ์˜ ํƒ€์ž…์ด ๊ฐ™๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•˜๊ณ ์ž ๋‘ ๊ฐœ๊ฐ€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๊ฒŒ๋” ํ•ฉ๋‹ˆ๋‹ค.

๋กœ์ปฌ ๋ณ€์ˆ˜ ์„ ์–ธ

ํƒ€์ž… ์–ธ์–ด์—์„œ ํƒ€์ž… ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํƒ€์ž… ๋ณ€์ˆ˜๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ „์—ญ ์Šค์ฝ”ํ”„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ๋กœ์ปฌ ํƒ€์ž… ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” ํƒ€์ž… ์–ธ์–ด์—์„œ infer ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

type A = 'foo'; // global scope
type B = A extends infer C ? (
    C extends 'foo' ? true : false// **์ด ํ‘œํ˜„์‹์—์„œ๋งŒ** C๋Š” A๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
) : never

์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ์Šค์ฝ”ํ”„๋ฅผ ์ œํ•œํ•˜๋Š” ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ์ž์—๊ฒŒ๋Š” ์ข€ ์ƒ์†Œํ•ด๋ณด์ผ์ง€๋ผ๋„, ์ด๋Ÿฐ ๋ฐฉ์‹์˜ ๋ฟŒ๋ฆฌ๋Š” ๋ช‡๋ช‡ ์ˆœ์ˆ˜ํ•œ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Haskell ์–ธ์–ด์—์„œ๋Š” ํŠน์ • ์Šค์ฝ”ํ”„๋ฅผ ํ• ๋‹นํ•˜๊ธฐ ์œ„ํ•ด in๊ณผ ํ•จ๊ป˜ let ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. let {assignments} in {expression}์™€ ๊ฐ™์ด ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด์ฃ .

let two = 2; three = 3 in two * three 
//                         โ†‘       โ†‘
// two and three are only in scope for the expression `two * three` 

infer๋Š” ์ค‘๊ฐ„ ํƒ€์ž…๋“ค์„ ์บ์‹ฑํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.
๊ด€๋ จ๋œ ์˜ˆ์‹œ๋ฅผ ๋ณด์—ฌ๋“œ๋ฆด๊ฒŒ์š”.

type ConvertFooToBar<G> = G extends 'foo' ? 'bar' : never
type ConvertBarToBaz<G> = G extends 'bar' ? 'baz' : never

type ConvertFooToBaz<T> = ConvertFooToBar<T> extends infer Bar ? 
        Bar extends 'bar' ? ConvertBarToBaz<Bar> : never 
    : never

type Baz = ConvertFooToBaz<'foo'>

infer ์—†์ด ๋กœ์ปฌ ํƒ€์ž… ๋ณ€์ˆ˜ Bar๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด ๋‘ ๋ฒˆ ๊ณ„์‚ฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

type ConvertFooToBar<G> = G extends 'foo' ? 'bar' : never
type ConvertBarToBaz<G> = G extends 'bar' ? 'baz' : never

type ConvertFooToBaz<T> = ConvertFooToBar<T> extends 'bar' ? 
    ConvertBarToBaz<ConvertFooToBar<T> > : never // call `ConvertFooToBar` twice

type Baz = ConvertFooToBaz<'foo'>

๋™๋“ฑ์„ฑ ๋น„๊ต์™€ ์กฐ๊ฑด ๋ถ„๊ธฐ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ if ๋ฌธ๊ณผ ํ•จ๊ป˜ ===์™€ ==๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์‚ผํ•ญ ์—ฐ์‚ฐ์ž ?๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ™์€์ง€๋ฅผ ๋น„๊ตํ•˜๊ณ  ์กฐ๊ฑด ๋ถ„๊ธฐ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ฐ˜๋ฉด์—, ํƒ€์ž… ์–ธ์–ด์—์„œ๋Š” "๋™๋“ฑ์„ฑ ๋น„๊ต"๋ฅผ ์œ„ํ•ด extends ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ๋น„์Šทํ•˜๊ฒŒ ์กฐ๊ฑด ๋ถ„๊ธฐ๋ฅผ ์œ„ํ•ด ์‚ผํ•ญ ์—ฐ์‚ฐ์ž ?๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

TypeC = TypeA extends TypeB ? TrueExpression : FalseExpression

๋งŒ์•ฝ TypeA๊ฐ€ TypeB์— ํ• ๋‹น ๊ฐ€๋Šฅํ•˜๊ฑฐ๋‚˜ ๋Œ€์ฒด๋  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์ฒซ ๋ฒˆ์งธ ๋ถ„๊ธฐ์— ๋“ค์–ด๊ฐ€๊ณ  TrueExpression์— ๋Œ€ํ•œ ํƒ€์ž…์„ ์–ป์„ ์ˆ˜ ์žˆ๊ณ  ๊ทธ ํƒ€์ž…์„ TypeC์— ํ• ๋‹นํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด FalseExpression๋ฅผ ์–ป์–ด TypeC์— ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํ• ๋‹น์‹œํ‚ค๊ฒ ์ฃ .

ํ• ๋‹น ๊ฐ€๋Šฅํ•˜๋‹ค, ๋Œ€์ฒด ๊ฐ€๋Šฅํ•˜๋‹ค(assignability, substitutability)์˜ ๊ฐœ๋…์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ต‰์žฅํžˆ ํ•ต์‹ฌ์ ์ธ ๊ฐœ๋… ์ค‘ ํ•˜๋‚˜์ด๊ธฐ์— ์ด์— ๊ด€๋ จํ•œ ํฌ์ŠคํŒ…์„ ์ž‘์„ฑํ•˜๊ธฐ๋„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ ์ž์„ธํžˆ ๋‹ค๋ฃจ์—ˆ์Šต๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ตฌ์ฒด์ ์ธ ์˜ˆ์‹œ๋ฅผ ๋ณผ๊นŒ์š”?

const username = 'foo'
let matched

if(username === 'foo') {
    matched = true
} else {
    matched = false
}

์ด๋ฅผ ํƒ€์ž… ์–ธ์–ด๋กœ ๋ฐ”๊พธ์–ด ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

type Username = 'foo'
type Matched = Username extends 'foo' ? true : false // true

extends ํ‚ค์›Œ๋“œ๋Š” ๋‹ค์–‘ํ•˜๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ๋„ˆ๋ฆญ ํ˜•์‹์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ œ์•ฝ ์กฐ๊ฑด์œผ๋กœ์„œ ์ ์šฉ์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ์ฃ .

function getUserName<T extends {name: string}>(user: T) {
	return user.name
}

์ œ๋„ˆ๋ฆญ ์ œ์•ฝ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ, <T extends {name: string}> ํ•จ์ˆ˜๊ฐ€ ๋ฐ›๋Š” ์ธ์ž๋Š” ํ•ญ์ƒ string ํƒ€์ž…์˜ name ํ”„๋กœํผํ‹ฐ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒ๋‹ˆ๋‹ค.

๊ฐ์ฒด ํƒ€์ž…์— ์ธ๋ฑ์‹ฑํ•˜์—ฌ ํ”„๋กœํผํ‹ฐ์˜ ํƒ€์ž… ๊ฐ€์ ธ์˜ค๊ธฐ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด obj['prop']์™€ ๊ฐ™์ด ๋Œ€๊ด„ํ˜ธ๋ฅผ ์ด์šฉํ•˜๊ฑฐ๋‚˜ obj.prop์ฒ˜๋Ÿผ dot์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
ํƒ€์ž… ์–ธ์–ด์—์„œ๋„ ๋Œ€๊ด„ํ˜ธ๋กœ ํ”„๋กœํผํ‹ฐ ํƒ€์ž…์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

type User = {name: string, age: number}
type Name = User['name']

์ด ๋ฐฉ์‹์€ ๊ฐ์ฒด ํƒ€์ž… ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํŠœํ”Œ์ด๋‚˜ ๋ฐฐ์—ด๊ณผ ๊ฐ™์€ ํƒ€์ž…์—์„œ๋„ ์ ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

type Names = string[]
type Name = Names[number]

type Tuple = [string, number]
type Age = Tuple[1]

ํ•จ์ˆ˜

ํ•จ์ˆ˜๋Š” ์–ด๋– ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋“  ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์€ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ "๊ตฌ์„ฑ ์š”์†Œ"์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋Š” ํŠน์ •ํ•œ input์„ ๋ฐ›์•„ output์„ ๋ฆฌํ„ดํ•ด์ค๋‹ˆ๋‹ค.
ํƒ€์ž… ์–ธ์–ด์—์„œ๋Š” ์ œ๋„ˆ๋ฆญ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ๋„ˆ๋ฆญ์€ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ๊ฐ’์„ ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”ํ•˜๋Š” ํƒ€์ž…์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ œ๋„ˆ๋ฆญ์€ ๊ฐœ๋…์ ์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํ•จ์ˆ˜์™€ ๋น„์Šทํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ผ๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

function fn(a, b = 'world') { return [a, b] }
const result = fn('hello') // ["hello", "world"]

ํƒ€์ž… ์–ธ์–ด์—์„œ๋Š” ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

type Fn  <A extends string, B extends string = 'world'>   =  [A, B]
//   โ†‘    โ†‘           โ†‘                          โ†‘              โ†‘
// name parameter parameter type          default value   function body/return statement

type Result = Fn<'hello'> // ["hello", "world"]

์™„๋ฒฝํ•œ ๋น„์œ ๋Š” ์•„๋‹์ง€๋ผ๋„ ...

์ œ๋„ˆ๋ฆญ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํ•จ์ˆ˜์™€ ์ •ํ™•ํžˆ ๋™์ผํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜์™€ ๋‹ค๋ฅด๊ฒŒ ์ œ๋„ˆ๋ฆญ์€ ํƒ€์ž… ์–ธ์–ด์˜ ์ผ๊ธ‰ ๊ฐ์ฒด๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
์ฆ‰, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ํ•จ์ˆ˜๋ฅผ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ œ๋„ˆ๋ฆญ์„ ๋‹ค๋ฅธ ์ œ๋„ˆ๋ฆญ์— ์ „๋‹ฌํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์˜๋ฏธ๊ฐ€ ๋˜๊ฒ ์ฃ .

map๊ณผ filter

ํƒ€์ž… ์–ธ์–ด์—์„œ ํƒ€์ž…์€ ๋ถˆ๋ณ€ํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž…์˜ ์–ด๋Š ๋ถ€๋ถ„์„ ์ˆ˜์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๊ธฐ์กด์˜ ํƒ€์ž…์„ ์ƒˆ๋กœ์šด ํƒ€์ž…์œผ๋กœ ๋ณ€ํ˜•์‹œ์ผœ์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค.
ํƒ€์ž… ์–ธ์–ด์—์„œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ(์˜ˆ๋ฅผ ๋“ค์–ด ๊ฐ์ฒด)์— ๊ฑธ์ณ ๋ฐ˜๋ณตํ•˜๊ณ  ๋ณ€ํ˜•ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด๊ฒŒ ์ ์šฉํ•˜๋Š” ์„ธ๋ถ€ ์‚ฌํ•ญ๋“ค์€ Mapped Types์— ์˜ํ•ด ์ถ”์ƒํ™”๋ฉ๋‹ˆ๋‹ค.
์ด๋ฅผ ์‚ฌ์šฉํ•ด์„œ map๊ณผ filter์™€ ๊ฐ™์€ ๋ฐฐ์—ด ๋ฉ”์†Œ๋“œ์™€ ๊ฐœ๋…์ ์œผ๋กœ ๋น„์Šทํ•œ ๋™์ž‘๋“ค์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋„˜๋ฒ„ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ฐ”๊พธ๋ ค๋จผ ์•„๋ž˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

const user = {
    name: 'foo',
    age: 28
}

function stringifyProp(object) {
    return Object.fromEntries(Object.entries(object)
		.map(([key, value]) => [key, String(value)]))
}

const userWithStringProps = stringifyProp(user) // {name:'foo', age: '28'}

ํƒ€์ž… ์–ธ์–ด์—์„œ ๋งคํ•‘์€ [K in keyof T]์™€ ๊ฐ™์€ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. keyof ์—ฐ์‚ฐ์ž๋Š” ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„๋“ค์„ string ์œ ๋‹ˆ์˜จ ํƒ€์ž…์œผ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

type User = {
    name: string,
    age: number
}

type StringifyProp<T> = {
    [K in keyof T]: string
}

type UserWithStringProps = StringifyProp<User> // { name: string; age: string; }

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ํŠน์ • ๊ธฐ์ค€์— ๋”ฐ๋ผ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด์ด ์•„๋‹Œ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ๋ณผ๊นŒ์š”?

const user = {
    name: 'foo',
    age: 28
}

function filterNonStringProp(object) {
    return Object.fromEntries(Object.entries(object)
        .filter(([key, value]) => typeof value === 'string' && [key, value]))
}

const filteredUser = filterNonStringProp(user) // {name: 'foo'}

ํƒ€์ž… ์–ธ์–ด์—์„œ๋Š” as ์—ฐ์‚ฐ์ž์™€ never ํƒ€์ž…์œผ๋กœ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

type User = {
    name: string,
    age: number
}

type FilterStringProp<T> = {
    [K in keyof T as T[K] extends string ? K : never]: string
}

type FilteredUser = FilterStringProp<User> // { name: string }

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—๋Š” ํƒ€์ž…์„ ๋ณ€ํ˜•์‹œ์ผœ์ฃผ๋Š” ๋‚ด์žฅ๋œ ์œ ํ‹ธ๋ฆฌํ‹ฐ "ํ•จ์ˆ˜"(์ œ๋„ˆ๋ฆญ)์ด ๋‹ค์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ์ด๋ฅผ ์ง์ ‘ ๋งŒ๋“ค ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.

ํŒจํ„ด ๋งค์นญ

ํƒ€์ž… ์–ธ์–ด์—์„œ ํŒจํ„ด ๋งค์นญ์„ ํ•˜๊ณ ์ž infer ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด JS ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š” ๋ฌธ์ž์—ด์˜ ํŠน์ • ๋ถ€๋ถ„์„ ์ถ”์ถœํ•˜๊ธฐ ์œ„ํ•ด ์ •๊ทœ์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

const str = 'foo-bar'.replace(/foo-*/, '')
console.log(str) // 'bar'

์ด ์ฝ”๋“œ๋ฅผ ํƒ€์ž… ์–ธ์–ด๋กœ ๋ฐ”๊พธ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

type Str = 'foo-bar'
type Bar = Str extends `foo-${infer rest}` ? rest : never // 'bar'

๋ฐ˜๋ณต ๋Œ€์‹  ์žฌ๊ท€

๋‹ค๋ฅธ ๋งŽ์€ ์ˆœ์ˆ˜ํ•œ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๊ฐ€ ๊ทธ๋ ‡๋“ฏ์ด, ํƒ€์ž… ์–ธ์–ด ๋˜ํ•œ ๋ฐ์ดํ„ฐ์˜ ๋ชฉ๋ก์„ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉฐ ๋ฐ˜๋ณตํ•˜๋Š” ๊ตฌ๋ฌธ ๊ตฌ์กฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์žฌ๊ท€ ๋ฐฉ์‹์ด ๋ฃจํ”„ ๋ฐฉ์‹์„ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ๋™์ผํ•œ ์•„์ดํ…œ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ์“ธ ์ˆ˜ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค.

function fillArray(item, n) {
    const res = [];
    for (let i = 0; i < n; i++) {
        res[i] = item;
    }
    return res;
}

์ด๋ฅผ ์žฌ๊ท€๋กœ ๋ฐ”๊พธ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

function fillArray(item, n, array = []) {
    return array.length === n ? array : fillArray(item, n, [item, ...array])
}

์ด ์ฝ”๋“œ๋ฅผ ํƒ€์ž… ์–ธ์–ด์—์„œ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ์จ์•ผ ํ• ๊นŒ์š”? ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ๊ธฐ ์œ„ํ•œ ๋…ผ๋ฆฌ์ ์ธ ๋‹จ๊ณ„๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • FilArray๋ผ๋Š” ์ œ๋„ˆ๋ฆญ ํƒ€์ž…์„ ์ƒ์„ฑํ•œ๋‹ค. (ํ•จ์ˆ˜์ฒ˜๋Ÿผ ํƒ€์ž… ์–ธ์–ด์—์„œ๋Š” ์ œ๋„ˆ๋ฆญ์ด ์žˆ๋‹ค๊ณ  ๋งํ–ˆ์ฃ ?)
FillArray<Item, N extends number, Array extends Item[] = []>
  • "ํ•จ์ˆ˜ ๋ฐ”๋””" ๋‚ด๋ถ€์—์„œ extends ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ Array์˜ length ํ”„๋กœํผํ‹ฐ๊ฐ€ N์ด ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
    • N์— ๋„๋‹ฌํ–ˆ๋‹ค๋ฉด, Array๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.
    • N์— ๋„๋‹ฌํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด, Array์— Item์„ ๋”ํ•˜๊ณ  ๋‹ค์‹œ ๋ฐ˜๋ณตํ•œ๋‹ค.

์ด ๋‹จ๊ณ„๋“ค์„ ํƒ€์ž… ์–ธ์–ด๋กœ ํ‘œํ˜„ํ•œ๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

type FillArray<Item, N extends number, Array extends Item[] = []> 
    = Array['length'] extends N 
        ? Array : FillArray<Item, N, [...Array, Item]>;

type Foos = FillArray<'foo', 3> // ["foo", "foo", "foo"]    

์žฌ๊ท€์˜ ํ•œ๊ณ„

TS 4.5 ์ „์— ์ตœ๋Œ€ ์žฌ๊ท€ ๊นŠ์ด๋Š” 45๊นŒ์ง€ ์˜€์Šต๋‹ˆ๋‹ค. 4.5 ๋ฒ„์ „์—์„œ ๊ผฌ๋ฆฌ ํ˜ธ์ถœ์ด ์ตœ์ ํ™”๋จ์— ๋”ฐ๋ผ 999๊นŒ์ง€ ์ฆ๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ์—์„œ ํƒ€์ž… ใ…‡ใ…‡๋ฅผ ์ง€์–‘ํ•˜์„ธ์š”

๋•Œ๋•Œ๋กœ ํƒ€์ž… ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์šฐ์Šค๊ฐฏ์†Œ๋ฆฌ๋กœ "type gymnastics"๋ผ๊ณ  ๋ถˆ๋ฆฌ๊ธฐ๋„ ํ•˜๋Š”๋ฐ ์ด๋Š” ์ผ๋ฐ˜์ ์ธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํ•„์š”ํ•œ ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋ณต์žกํ•˜๊ณ  ํ™”๋ คํ•˜๋ฉฐ ์ •๊ตํ•  ๋•Œ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์ž๋ฉด,

์ด๋Ÿฐ ๊ฒฝ์šฐ๋“ค์€ ํ›จ์”ฌ ๋” ํ•™์ˆ ์ ์ธ ์˜ˆ์‹œ์ด๋ฏ€๋กœ ์‹ค์ œ ํ”„๋กœ๋•์…˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ๋Š” ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • ๋‚œํ•ดํ•œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๊ธฐ๋Šฅ์œผ๋กœ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์›€
  • ๊ธธ๊ณ  ์•”ํ˜ธํ™”๋œ ์ปดํŒŒ์ผ๋Ÿฌ ์—๋Ÿฌ๋ฉ”์‹œ์ง€ ๋•Œ๋ฌธ์— ๋””๋ฒ„๊น…์ด ์–ด๋ ค์›€
  • ์ปดํŒŒ์ผ์ด ๋Š๋ฆผ

์™€ ๊ฐ™์€ ์ด์œ ๋“ค์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ฝ”์–ด ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์Šคํ‚ฌ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ๋ฆฌํŠธ์ฝ”๋“œ ๋ฌธ์ œ๋ฅผ ํ‘ธ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ๋ถ„์˜ ํƒ€์ž… ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์Šคํ‚ฌ์„ ์œ„ํ•ด type-challenges์„ ํ’€์–ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆ๋ฌด๋ฆฌ

์ •๋ง ๋งŽ์€ ๊ฒƒ๋“ค์„ ์ด ๊ธ€์—์„œ ๋‹ค๋ฃจ์—ˆ๋„ค์š”. ์ด ๊ธ€์˜ ํ•ต์‹ฌ์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ฐ€๋ฅด์น˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์–ด์ฉŒ๋ฉด ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ฐฐ์šฐ๊ณ  ๋‚˜์„œ ๊ฐ„๊ณผํ–ˆ์„ ์ˆ˜๋„ ์žˆ๋Š” "์ˆจ๊ฒจ์ง„" ํƒ€์ž… ์–ธ์–ด๋ฅผ ๋‹ค์‹œ ์†Œ๊ฐœํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํƒ€์ž… ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ํ™œ๋ฐœํ•˜๊ฒŒ ๋…ผ์˜๊ฐ€ ์ด๋ฃจ์–ด์ง€๊ณ  ์žˆ์ง€ ์•Š์€๋ฐ, ๊ทธ๊ฒƒ์ด ์ž˜๋ชป๋๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง„ ์•Š์Šต๋‹ˆ๋‹ค. ๊ถ๊ทน์ ์œผ๋กœ ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ๋ชฉ์ ์„ ์œ„ํ•œ ์ˆ˜๋‹จ์ผ๋ฟ, ๊ฒฐ๊ตญ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์‹ ๋ขฐ์„ฑ ์žˆ๋Š” ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“œ๋Š” ๊ฒŒ ์ค‘์š”ํ•˜๋‹ˆ๊นŒ์š”. ๊ทธ๋ž˜์„œ ์‚ฌ๋žŒ๋“ค์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋‚˜ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋“ค์ฒ˜๋Ÿผ "์ ์ ˆํ•˜๊ฒŒ" ํƒ€์ž… ์–ธ์–ด๋ฅผ ๊ณต๋ถ€ํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์„ ๋“ค์ด์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ถฉ๋ถ„ํžˆ ์ดํ•ด๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์•ž์œผ๋กœ ์ฝ์„ ๊ฒƒ๋“ค

[๋ฒˆ์—ญ] `useMemo`์™€ `useCallback`์„ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ

<์›๋ฌธ : When to useMemo and useCallback>

์„ฑ๋Šฅ์ตœ์ ํ™”๋Š” ์–ธ์ œ๋‚˜ ๋น„์šฉ์ด ๋“ค์ง€๋งŒ ํ•ญ์ƒ ์ข‹์€ ๊ฑด ์•„๋‹™๋‹ˆ๋‹ค. useMemo์™€ useCallback์˜ ๋น„์šฉ๊ณผ ์žฅ์ ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•ด๋ด…์‹œ๋‹ค.

์—ฌ๊ธฐ์— ์‚ฌํƒ• ๋””์ŠคํŽœ์„œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ–ˆ๋Š”์ง€ ๋ด…์‹œ๋‹ค.

function CandyDispenser() {
  const initialCandies = ['snickers', 'skittles', 'twix', 'milky way']
  const [candies, setCandies] = React.useState(initialCandies)
  const dispense = candy => {
    setCandies(allCandies => allCandies.filter(c => c !== candy))
  }
  return (
    <div>
      <h1>Candy Dispenser</h1>
      <div>
        <div>Available Candy</div>
        {candies.length === 0 ? (
          <button onClick={() => setCandies(initialCandies)}>refill</button>
        ) : (
          <ul>
            {candies.map(candy => (
              <li key={candy}>
                <button onClick={() => dispense(candy)}>grab</button> {candy}
              </li>
            ))}
          </ul>
        )}
      </div>
    </div>
  )
}

๊ทธ๋Ÿผ ์ด์ œ ์—ฌ๋Ÿฌ๋ถ„๋“ค์—๊ฒŒ ์งˆ๋ฌธ์„ ํ•  ๊ฒ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ ๋‚˜์•„๊ฐ€๊ธฐ ์ „์— ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์ œ ์งˆ๋ฌธ์— ๋Œ€ํ•ด ์ž˜ ์ƒ๊ฐํ•ด๋ณด๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•  ๊ฑด๋ฐ ์–ด๋–ค ๊ฒƒ์ด ๋” ๋‚˜์€ ์„ฑ๋Šฅ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ๋ ค์ฃผ์„ธ์š”.

์ œ๊ฐ€ ๋ฐ”๊ฟ€ ๊ฒƒ์€ dispense ํ•จ์ˆ˜๋Š” React.useCallback์œผ๋กœ ๊ฐ์‹ธ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

const dispense = React.useCallback(candy => {
  setCandies(allCandies => allCandies.filter(c => c !== candy))
}, [])

์›๋ž˜ ์ฝ”๋“œ๋Š” ์ด๋ ‡์Šต๋‹ˆ๋‹ค.

const dispense = candy => {
  setCandies(allCandies => allCandies.filter(c => c !== candy))
}

์ด ์ƒํ™ฉ์—์„œ ์›๋ž˜ ์ฝ”๋“œ์™€ ๋ณ€๊ฒฝ๋œ ์ฝ”๋“œ ์ค‘ ์–ด๋–ค ๊ฒƒ์ด ์„ฑ๋Šฅ์— ๋” ์ข‹์„๊นŒ์š”? ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ์•Œ๋ ค์ฃผ์„ธ์š”.

์—ญ : ์›๋ฌธ์—๋Š” ๋…์ž๊ฐ€ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ„ํŠผ์ด ์žˆ์ง€๋งŒ ์ƒ๋žตํ•ฉ๋‹ˆ๋‹ค.

์ •๋‹ต์€ '์›๋ณธ ์ฝ”๋“œ' ์ž…๋‹ˆ๋‹ค.

์™œ useCallback์„ ์“ฐ๋Š”๊ฒŒ ๋” ์•ˆ์ข‹์€๊ฐ€์š”?

์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ณ  "์ธ๋ผ์ธ ํ•จ์ˆ˜๋Š” ์„ฑ๋Šฅ์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค"๊ณ  ํ•˜๊ธฐ ๋•Œ๋ฌธ์— React.useCallback์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋งŽ์ด ๋“ค์œผ์…จ์„ ๊ฒ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์™œ useCallback์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๊ฒŒ ์™œ ๋” ์ข‹์€ ์ฝ”๋“œ์ผ๊นŒ์š”?

์•„๊นŒ ๋ดค๋˜ ์˜ˆ์‹œ์—์„œ ํ•œ ๋ฐœ์ง ๋ฌผ๋Ÿฌ๋‚˜ React ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ๋„ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ์˜ ๋ชจ๋“  ๋ผ์ธ์€ ๋น„์šฉ์ด ๋“ ๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•˜์„ธ์š”. ์ด์ œ useCallback ์˜ˆ์‹œ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๊ณ ์ž ์ข€ ๋” ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. (์‹ค์ œ ๋ณ€ํ™”๋Š” ์—†์ง€๋งŒ ์•ฝ๊ฐ„์˜ ์ด๋™๋งŒ ํ•ฉ๋‹ˆ๋‹ค)

const dispense = candy => {
  setCandies(allCandies => allCandies.filter(c => c !== candy))
}
const dispenseCallback = React.useCallback(dispense, [])

์›๋ณธ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ๋ณด์—ฌ๋“œ๋ฆฌ์ฃ .

const dispense = candy => {
  setCandies(allCandies => allCandies.filter(c => c !== candy))
}

๋‘ ์ฝ”๋“œ์— ๋Œ€ํ•ด ๋ญ”๊ฐ€ ์•Œ์•„์ฐจ๋ฆฌ์…จ๋‚˜์š”? ์ฐจ์ด์ ์„ ์‚ดํŽด๋ด…์‹œ๋‹ค.

const dispense = candy => {
    setCandies(allCandies => allCandies.filter(c => c !== candy))
  }
+ const dispenseCallback = React.useCallback(dispense, [])

๋งž์Šต๋‹ˆ๋‹ค. useCallback ๋ฒ„์ „์ด ์ข€ ๋” ๋งŽ์€ ์ผ์„ ํ•œ๋‹ค๋Š” ๊ฒƒ ๋นผ๊ณ  ๋‘ ์ฝ”๋“œ๋Š” ์ •ํ™•ํžˆ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ฐฐ์—ด์„ ์ •์˜ํ•˜๊ณ  ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ค์ •ํ•˜๊ณ  ๋…ผ๋ฆฌ์ ์ธ ํ‘œํ˜„์„ ํ†ตํ•ด ์‹คํ–‰๋˜๋Š” React.useCallback์„ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋‘ ๊ฐ€์ง€ ๊ฒฝ์šฐ ๋ชจ๋‘ JavaScript๋Š” ๋ Œ๋”๋ง ๋•Œ๋งˆ๋‹ค ํ•จ์ˆ˜ ์ •์˜์— ๋Œ€ํ•œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•ด์•ผ ํ•˜๊ณ  ์–ด๋–ป๊ฒŒ useCallback์ด ๊ตฌํ˜„๋˜๋Š”์ง€์— ๋”ฐ๋ผ ํ•จ์ˆ˜ ์ •์˜์— ๋Œ€ํ•ด ๋” ๋งŽ์€ ํ• ๋‹น์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์ด ๊ฒฝ์šฐ์— ํ•ด๋‹นํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์ œ ๋ง์˜ ์š”์ ์€ ์—ฌ์ „ํ•ฉ๋‹ˆ๋‹ค) ์ œ๊ฐ€ ํŠธ์œ„ํ„ฐ ํˆฌํ‘œ๋ฅผ ํ†ตํ•ด ์ „๋‹ฌํ•˜๊ณ ์ž ํ–ˆ๋˜ ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ •๋‹ต์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ์ œ๊ฐ€ ๋ง์„ ์„œํˆด๊ฒŒ ํ•ด์„œ ํ‹€๋ฆฐ ๋‹ต์„ ์„ ํƒํ•˜์…จ๋‹ค๋ฉด ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ์˜ ๋‘ ๋ฒˆ์งธ ๋ Œ๋”๋ง ๋•Œ ์›๋ž˜ ์žˆ๋˜ dispense ํ•จ์ˆ˜๋Š” ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰ํ„ฐ๊ฐ€ ์ˆ˜์ง‘ํ•˜๊ณ (๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„๋„ ํ’€๋ฆฌ์ฃ ) ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ useCallback๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ์›๋ž˜ ์žˆ๋˜ dispense ํ•จ์ˆ˜๋Š” ์ˆ˜์ง‘๋˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑ๋˜๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ ์ธก๋ฉด์—์„œ๋„ ์ข‹์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ๋ง์”€๋“œ๋ฆฌ๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ด€๋ จํ•ด์„œ useCallback์˜ dependency๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ React๊ฐ€ ์ด์ „ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ฐธ์กฐ๋กœ ๊ทธ ๊ฐ’๋“ค์„ ๊ณ„์† ๊ฐ€์ง€๊ณ  ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค. ๋ฉ”๋ชจ์ด์ œ์ด์…˜์€ ์ด์ „์— ์ฃผ์–ด์กŒ๋˜ dependency ๊ฐ’๋“ค์ด ๋™์ผํ•œ ๊ฒฝ์šฐ ์ด์ „ ๊ฐ’๋“ค์„ ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ดํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.ํŠนํžˆ ๋ˆˆ์น˜๊ฐ€ ๋น ๋ฅธ ๋ถ„๋“ค์ด๋ผ๋ฉด React๊ฐ€ dependency ๊ฐ’๋“ค์˜ ๋™์ผ์„ฑ ์ฒดํฌ๋ฅผ ์œ„ํ•ด ํ•ด๋‹น ๊ฐ’๋“ค์˜ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•„์ฐจ๋ฆฌ์…จ์„ ๊ฒ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด useMemo๋Š” ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ๊ฐ€์š”?

useMemo๋Š” ํ•จ์ˆ˜ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์–ด๋–ค ํƒ€์ž…์˜ ๊ฐ’์ด๋“  ๋ฉ”๋ชจ์ด์ œ์ด์…˜์„ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ ์™ธ์— useCallback๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ›์œผ๋ฉด ํ•จ์ˆ˜๋Š” ๊ฐ’์ด ๋ฐ˜ํ™˜๋˜์–ด์•ผ ํ•  ๋•Œ๋งŒ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. (๋ณดํ†ต ๋ Œ๋” ์‹œ dependency ๋ฐฐ์—ด ๋‚ด ๊ฐ’๋“ค์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ํ•œ๋ฒˆ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.)

๊ทธ๋ž˜์„œ ๋ Œ๋”๋ง ๋•Œ๋งˆ๋‹ค initialCandies ๋ฐฐ์—ด์„ ๋‹ค์‹œ ๋งŒ๋“ค๊ธฐ ์‹ซ๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ๋ฐ”๊พธ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

- const initialCandies = ['snickers', 'skittles', 'twix', 'milky way']
+ const initialCandies = React.useMemo(
+  () => ['snickers', 'skittles', 'twix', 'milky way'],
+  [],
+ )

๊ทธ๋Ÿฌ๋ฉด ๊ทธ ๋ฌธ์ œ๋Š” ํ”ผํ•  ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ, ์ €์žฅ๋œ ๊ฐ’๋“ค์ด ๋„ˆ๋ฌด ์ž‘์•„์„œ ์ฝ”๋“œ๋ฅผ ๋ณต์žกํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ๋งŒํผ์˜ ๊ฐ€์น˜๊ฐ€ ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์ด๋ ‡๊ฒŒ useMemo๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ ํ”„๋กœํผํ‹ฐ ํ• ๋‹น ๋“ฑ์„ ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ์˜ˆ์‹œ์—์„œ๋Š” ์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

+ const initialCandies = ['snickers', 'skittles', 'twix', 'milky way']
  function CandyDispenser() {
-   const initialCandies = ['snickers', 'skittles', 'twix', 'milky way']
    const [candies, setCandies] = React.useState(initialCandies)

๊ทธ๋Ÿฌ๋‚˜ ๊ฐ’๋“ค์ด props๋กœ ๋„˜์–ด์˜ค๊ฑฐ๋‚˜ ํ•จ์ˆ˜ ๋ฐ”๋””์—์„œ ์ดˆ๊ธฐํ™”๋˜๋Š” ๋‹ค๋ฅธ ๊ฐ’๋“ค์ด ํ•„์š”ํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์—†์„ ๊ฒ๋‹ˆ๋‹ค.

์ œ๊ฐ€ ๋งํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฐ”๋Š” ๊ฒฐ๊ตญ ์ฝ”๋“œ๋ฅผ ์ตœ์ ํ™”ํ•  ๋•Œ ์–ป๋Š” ๋ฒ ๋„คํ•์ด ๋งค์šฐ ๋ฏธ๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ป๊ฒŒ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์„์ง€๋ฅผ ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์š”์ ์ด ๋ญ”๊ฐ€์š”?

๊ฒฐ๊ตญ ์ด ๊ธ€์˜ ์š”์ ์„ ๋ง์”€๋“œ๋ฆฌ์ž๋ฉด, ์„ฑ๋Šฅ ์ตœ์ ํ™”๋Š” ๊ณต์งœ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์„ฑ๋Šฅ ์ตœ์ ํ™”๋Š” ์–ธ์ œ๋‚˜ ๋น„์šฉ์„ ๋™๋ฐ˜ํ•˜์ง€๋งŒ ํ•ญ์ƒ ๋น„์šฉ๋งŒํผ์˜ ๋ฒ ๋„คํ•์„ ๊ฐ€์ ธ๋‹ค์ฃผ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‹ˆ ์ฑ…์ž„๊ฐ์„ ๊ฐ–๊ณ  ์ตœ์ ํ™”ํ•˜์„ธ์š”.

๊ทธ๋Ÿผ ์–ธ์ œ useMemo์™€ useCallback์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋‚˜์š”?

๋‘ hook์ด React์— ๋‚ด์žฅ๋˜์–ด ์žˆ๋Š” ๋ถ„๋ช…ํ•œ ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์ฐธ์กฐ ๋™์ผ์„ฑ (Referential equality)
  2. ๋น„์šฉ์ด ๋งŽ์ด ๋“œ๋Š” ์—ฐ์‚ฐ (Computationally expensive calculations)

์ฐธ์กฐ ๋™์ผ์„ฑ (Referential equality)

์—ฌ๋Ÿฌ๋ถ„์ด JavaScript๋‚˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ดˆ๋ณด๋ผ ํ• ์ง€๋ผ๋„, ์™œ ์ด๋Ÿฐ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๋Š”์ง€ ๊ธˆ๋ฐฉ ์•Œ ๊ฒ๋‹ˆ๋‹ค.

true === true // true
false === false // true
1 === 1 // true
'a' === 'a' // true

{} === {} // false
[] === [] // false
() => {} === () => {} // false

const z = {}
z === z // true

// NOTE: React actually uses Object.is, but it's very similar to ===

์ด ์ฝ”๋“œ์— ๋Œ€ํ•ด ๊นŠ๊ฒŒ ์–˜๊ธฐํ•˜์ง€๋Š” ์•Š๊ฒŒ์ง€๋งŒ, ์—ฌ๋Ÿฌ๋ถ„์ด React ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ๊ฐ์ฒด๋ฅผ ์„ ์–ธํ•  ๋•Œ ๊ฐ™์€ ๊ฐ์ฒด๊ฐ€ ์ •์˜๋œ ๋งˆ์ง€๋ง‰ ์‹œ๊ฐ„๊ณผ ์ฐธ์กฐ๊ฐ€ ๋™์ผํ•˜์ง€ ์•Š์„ ๊ฒ๋‹ˆ๋‹ค. (๋™์ผํ•œ ํ”„๋กœํผํ‹ฐ๊ณผ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ํ•ด๋„ ๋ง์ด์ฃ .)

React์—์„œ ์ฐธ์กฐ ๋™์ผ์„ฑ์ด ์ค‘์š”ํ•œ ๋‘ ๊ฐ€์ง€ ์ƒํ™ฉ์ด ์žˆ๋Š”๋ฐ ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ด…์‹œ๋‹ค.

Dependencies Lists

๋‹ค์Œ ์˜ˆ์‹œ๋ฅผ ๋ด…์‹œ๋‹ค.

๊ฒฝ๊ณ  : ๋ถ€์ž์—ฐ์Šค๋Ÿฌ์šด ์ฝ”๋“œ๊ฐ€ ๋ณด์ด๋”๋ผ๋„ ์ปจ์…‰์— ์ง‘์ค‘ํ•ด์ฃผ์„ธ์š”!

function Foo({bar, baz}) {
  const options = {bar, baz}
  React.useEffect(() => {
    buzz(options)
  }, [options]) // we want this to re-run if bar or baz change
  return <div>foobar</div>
}

function Blub() {
  return <Foo bar="bar value" baz={3} />
}

์ด ์ฝ”๋“œ๊ฐ€ ๋ฌธ์ œ์ธ ์ด์œ ๋Š” useEffect๊ฐ€ ๋ Œ๋”๋ง ์‹œ์ ๋งˆ๋‹ค options์— ๋Œ€ํ•œ ์ฐธ์กฐ ๋™์ผ์„ฑ ํ™•์ธ์„ ํ•ด์•ผ ํ•˜๊ณ  JavaScript์˜ ๋™์ž‘ ๋ฐฉ์‹์— ์˜ํ•ด options๋Š” ๋ชจ๋“  ์‹œ์ ์—์„œ ์ƒˆ๋กœ์šด ์ฐธ์กฐ๋ฅผ ๊ฐ–๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๊ฒฐ๊ตญ React๋Š” ํ•ญ์ƒ options๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๊ณ  ํ‰๊ฐ€ํ•  ๊ฒ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด useEffect์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋Š” bar์™€ baz๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋งค ๋ Œ๋”๋ง ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

// option 1
function Foo({bar, baz}) {
  React.useEffect(() => {
    const options = {bar, baz}
    buzz(options)
  }, [bar, baz]) // we want this to re-run if bar or baz change
  return <div>foobar</div>
}

์ด ๋ฐฉ๋ฒ•์€ ์•„์ฃผ ์ข‹์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ œ๊ฐ€ ํ•ด๊ฒฐํ•œ ๋ฐฉ๋ฒ•์ด์ฃ .

๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋Š” ํ•œ ๊ฐ€์ง€ ์ƒํ™ฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค. bar๋‚˜ baz๊ฐ€ ์›์‹œ๊ฐ’์ด ์•„๋‹Œ ๊ฐ์ฒด/๋ฐฐ์—ด/ํ•จ์ˆ˜ ๋“ฑ์ผ ๋•Œ์ž…๋‹ˆ๋‹ค.

function Blub() {
  const bar = () => {}
  const baz = [1, 2, 3]
  return <Foo bar={bar} baz={baz} />
}

์ด๋Ÿฐ ๊ฒฝ์šฐ๊ฐ€ useCallback๊ณผ useMemo์˜ ์กด์žฌ ์ด์œ ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๋•Œ์ž…๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ์ˆ˜์ •ํ• ๊นŒ์š”?

function Foo({bar, baz}) {
  React.useEffect(() => {
    const options = {bar, baz}
    buzz(options)
  }, [bar, baz])
  return <div>foobar</div>
}

function Blub() {
  const bar = React.useCallback(() => {}, [])
  const baz = React.useMemo(() => [1, 2, 3], [])
  return <Foo bar={bar} baz={baz} />
}

์ฐธ๊ณ ๋กœ useEffect, useLayoutEffect, useCallback, useMemo์— ์‚ฌ์šฉ๋˜๋Š” dependencies ๋ฐฐ์—ด์— ๋™์ผํ•˜๊ฒŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

React.memo

๊ฒฝ๊ณ  : ๋” ๋ถ€์ž์—ฐ์Šค๋Ÿฌ์šด ์ฝ”๋“œ๊ฐ€ ๋ณด์ผ์ง€๋ผ๋„ ์ปจ์…‰์„ ์œ„ํ•œ ๊ฒƒ์ด๋‹ˆ ์ดํ•ด ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ด ์ฝ”๋“œ๋ฅผ ๋ณผ๊นŒ์š”?

function CountButton({onClick, count}) {
  return <button onClick={onClick}>{count}</button>
}

function DualCounter() {
  const [count1, setCount1] = React.useState(0)
  const increment1 = () => setCount1(c => c + 1)
  
  const [count2, setCount2] = React.useState(0)
  const increment2 = () => setCount2(c => c + 1)
  
  return (
    <>
      <CountButton count={count1} onClick={increment1} />
      <CountButton count={count2} onClick={increment2} />
    </>
  )
}

์—ฌ๋Ÿฌ๋ถ„์ด ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๋•Œ๋งˆ๋‹ค DualCounter์˜ ์ƒํƒœ๊ฐ’์€ ๋ณ€๊ฒฝ๋˜์–ด ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜์—ฌ CountButton ์ปดํฌ๋„ŒํŠธ๋“ค๋„ ๋ฆฌ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ๋กœ๋Š” ํด๋ฆญ๋œ ๋ฒ„ํŠผ๋งŒ ๋‹ค์‹œ ๋ Œ๋”๋ง์ด ๋˜์–ด์•ผ ํ•˜์ง€ ์•Š์„๊นŒ์š”? ์ฒซ ๋ฒˆ์งธ ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ, ๋‘ ๋ฒˆ์งธ ๋ฒ„ํŠผ์ด ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜๋Š”๋ฐ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฐ ์ƒํ™ฉ์„ "๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”"๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๋ถˆํ•„์š”ํ•œ ๋ Œ๋”๋ง์„ ์ตœ์ ํ™”ํ•˜๋Š”๋ฐ ๋„ˆ๋ฌด ๋งŽ์€ ์‹œ๊ฐ„์„ ์“ฐ์ง€ ๋งˆ์„ธ์š”. React๋Š” ๊ต‰์žฅํžˆ ๋น ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ์ค‘์š”ํ•œ ์ผ๋“ค์ด ๋งŽ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ Paypal ์ œํ’ˆ์„ ์ž‘์—…ํ•˜๋Š” 3๋…„๋™์•ˆ ๋ง ๊ทธ๋Œ€๋กœ 3๋…„๋™์•ˆ, ๊ทธ๋ฆฌ๊ณ  React๋กœ ์ž‘์—…ํ•œ ๊ธฐ๊ฐ„๋™์•ˆ ํ•  ํ•„์š”๊ฐ€ ์—†์—ˆ๋‹ต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•œ ๊ทธ๋ž˜ํ”„, ์ฐจํŠธ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋“ฑ ๋ Œ๋”๋ง์— ๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹คํ–‰ํžˆ React์˜ ์‹ค์šฉ์ฃผ์˜์ ์ธ ํŠน์„ฑ ๋•๋ถ„์— ๋น„์ƒ๊ตฌ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

const CountButton = React.memo(function CountButton({onClick, count}) {
  return <button onClick={onClick}>{count}</button>
})

์ด์ œ React๋Š” props๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ CountButton๋งŒ์„ ๋ฆฌ๋ Œ๋”๋ง ํ•  ๊ฒ๋‹ˆ๋‹ค! ๊ทธ๋Ÿฌ๋‚˜ ์•„์ง ํ•  ์ผ์ด ๋‚จ์•˜์Šต๋‹ˆ๋‹ค. ์•„๊นŒ ์–˜๊ธฐํ–ˆ๋˜ ์ฐธ์กฐ ๋™์ผ์„ฑ์„ ๊ธฐ์–ตํ•˜์‹œ๋‚˜์š”? DualCounter ์ปดํฌ๋„ŒํŠธ์—์„œ increment1๊ณผ increment2 ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ–ˆ๋Š”๋ฐ, DualCounter๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค ์ด ํ•จ์ˆ˜๋“ค์€ ์ƒˆ๋กœ ์ƒ์„ฑ๋˜์–ด CountButton๋“ค์„ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๊ฒŒ ๋  ๊ฒ๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๊ฒฝ์šฐ๊ฐ€ useCallback๊ณผ useMemo๊ฐ€ ๋„์›€์ด ๋˜๋Š” ๋˜ ๋‹ค๋ฅธ ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค.

const CountButton = React.memo(function CountButton({onClick, count}) {
  return <button onClick={onClick}>{count}</button>
})

function DualCounter() {
  const [count1, setCount1] = React.useState(0)
  const increment1 = React.useCallback(() => setCount1(c => c + 1), [])
  
  const [count2, setCount2] = React.useState(0)
  const increment2 = React.useCallback(() => setCount2(c => c + 1), [])
  
  return (
    <>
      <CountButton count={count1} onClick={increment1} />
      <CountButton count={count2} onClick={increment2} />
    </>
  )
}

์ด์ œ ์šฐ๋ฆฌ๋Š” CountButton ์ปดํฌ๋„ŒํŠธ์˜ "๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง"์„ ํ”ผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ ์ €๋Š” React.memo(๋‚˜ ๋น„์Šทํ•œ PureComponent, ShouldComponentUpdate)๋ฅผ ๊ธฐ์ค€์—†์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ถŒ๊ณ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์ ํ™”๋ฅผ ํ–ˆ์„ ๋•Œ์˜ ๋น„์šฉ๊ณผ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์ด์ ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์œ„์—์„œ ์‚ดํŽด๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ ์ตœ์ ํ™”๋ฅผ ํ–ˆ์„ ๋•Œ ์–ป๋Š” ์ด์ ์ด ์—†์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋น„์šฉ์ด ๋งŽ์ด ๋“œ๋Š” ์—ฐ์‚ฐ

React์—์„œ useMemo๊ฐ€ ๋‚ด์žฅ๋œ ๋˜ ๋‹ค๋ฅธ ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.(useCallback์€ ํ•ด๋‹น๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.) useMemo์˜ ์žฅ์ ์€ ์•„๋ž˜์ฒ˜๋Ÿผ ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒ๋‹ˆ๋‹ค.

const a = {b: props.b}

์ด ๊ฐ’์„ lazyํ•˜๊ฒŒ ํ•ด๋ณผ๊นŒ์š”.

const a = React.useMemo(() => ({b: props.b}), [props.b])

์ด๊ฒƒ์€ ์œ„์˜ ์ผ€์ด์Šค์ฒ˜๋Ÿผ ์œ ์šฉํ•œ ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ์—ฌ๋Ÿฌ๋ถ„์ด ๋™๊ธฐ์ ์œผ๋กœ ๋ณต์žกํ•œ ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์„ธ์š”.

function RenderPrimes({iterations, multiplier}) {
  const primes = calculatePrimes(iterations, multiplier)
  return <div>Primes! {primes}</div>
}

iterations๋‚˜ multiplier๋ฅผ ์ƒ๊ฐํ•ด๋ณด๋ฉด ์—ฐ์‚ฐ ์†๋„๊ฐ€ ๊ฝค ๋Š๋ฆด ๊ฑฐ๋ผ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ํ•  ๊ฒƒ์€ ๋”ฑํžˆ ์—†๊ณ , ํ•˜๋“œ์›จ์–ด๋ฅผ ์ž๋™์ ์œผ๋กœ ๋น ๋ฅด๊ฒŒ ๋งŒ๋“ค ์ˆœ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ™์€ ๊ฐ’์„ ๋‘ ๋ฒˆ ๊ณ„์‚ฐํ•˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜๋Š” ์žˆ์Šต๋‹ˆ๋‹ค.

function RenderPrimes({iterations, multiplier}) {
  const primes = React.useMemo(() => calculatePrimes(iterations, multiplier), [
    iterations,
    multiplier,
  ])
  return <div>Primes! {primes}</div>
}

์ด ๋ฐฉ๋ฒ•์ด ํšจ๊ณผ์ ์ธ ์ด์œ ๋Š” ๋ชจ๋“  ๋ Œ๋”๋ง ๋•Œ๋งˆ๋‹ค ์†Œ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ–ˆ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ React๋Š” ํ•„์š”ํ•œ ๊ฐ’์ด ์žˆ์„ ๋•Œ๋งŒ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๋Š” ๊ฒ๋‹ˆ๋‹ค. React๋Š” ์ด์ „์˜ ๊ฐ’๋“ค์„ ์ €์žฅํ•˜๊ณ  ๊ฐ™์€ ์ž…๋ ฅ๊ฐ’์ด ๋“ค์–ด์˜ค๋ฉด ์ด์ „ ๊ฐ’๋“ค์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋ฉ”๋ชจ์ด์ œ์ด์…˜์ด ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

๋ชจ๋“  ์ถ”์ƒํ™”(์™€ ์„ฑ๋Šฅ ์ตœ์ ํ™”)๋Š” ๋น„์šฉ์ด ๋“ ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ง์”€๋“œ๋ฆฌ๋ฉด์„œ ๊ธ€์„ ๋งˆ๋ฌด๋ฆฌํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. AHA ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์›์น™์„ ์ ์šฉํ•˜๊ณ  ์ถ”์ƒํ™”/์ตœ์ ํ™”๊ฐ€ ์ •๋ง ํ•„์š”ํ•  ๋•Œ๋งŒ ์ ์šฉ์‹œํ‚จ๋‹ค๋ฉด ์ด์ ์ด ์—†์ด ๋น„์šฉ๋งŒ ๋“œ๋Š” ์ƒํ™ฉ์—์„œ ๋ฒ—์–ด๋‚  ์ˆ˜ ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค.

ํŠนํžˆ useCallback๊ณผ useMemo๋Š” ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋ฅผ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋น„์šฉ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ๋˜ํ•œ dependencies ๋ฐฐ์—ด์— ์‹ค์ˆ˜๋ฅผ ํ•œ๋‹ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์€ ๋‚ด์žฅ๋œ hooks์„ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰ํ„ฐ๊ฐ€ ๊ฐ’์„ ์ˆ˜์ง‘ํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜์—ฌ ์„ฑ๋Šฅ์„ ๋‚˜์˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ป๊ณ ์ž ํ•˜๋Š” ์ด์ต์ด ์žˆ์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋น„์šฉ์€ ๊ดœ์ฐฎ์ง€๋งŒ, ๋จผ์ € ํ™•์ธํ•ด๋ณด๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๊ด€๋ จ๋˜์–ด ์ฝ์–ด๋ณผ๋งŒํ•œ ๊ฒƒ๋“ค์ž…๋‹ˆ๋‹ค.

์ถ”์‹ . ์—ฌ๋Ÿฌ๋ถ„์ด hook์œผ๋กœ ์˜ฎ๊ธฐ๋Š” ๊ฒƒ๊ณผ ํด๋ž˜์Šค๋กœ ์„ ์–ธํ•˜๋˜ ๊ฒƒ๋“ค์„ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋กœ ์ •์˜ํ•ด์•ผ ํ•˜๋Š” ๊ฑฐ์— ๊ฑฑ์ •ํ•˜๊ณ  ์žˆ๋Š” ๋ถ„ ์ค‘์— ํ•œ ๋ช…์ด๋ผ๋ฉด ๋ฉ”์†Œ๋“œ๋ฅผ render ๋‹จ๊ณ„์—์„œ ์ •์˜ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๊ณ ๋ คํ•ด๋ณด์‹œ๊ธธ ๊ถŒํ•ฉ๋‹ˆ๋‹ค.

class FavoriteNumbers extends React.Component {
  render() {
    return (
      <ul>
        {this.props.favoriteNumbers.map(number => (
          // TADA! This is a function defined in the render method!
          // Hooks did not introduce this concept.
          // We've been doing this all along.
          <li key={number}>{number}</li>
        ))}
      </ul>
    )
  }
}

[๋ฒˆ์—ญ] Nest.js - ๊ตฌ์กฐ์  ํŒจํ„ด (์ปจํŠธ๋กค๋Ÿฌ, ํ”„๋กœ๋ฐ”์ด๋”, ๋ชจ๋“ˆ)

์›๋ฌธ : https://medium.com/geekculture/nest-js-architectural-pattern-controllers-providers-and-modules-406d9b192a3a

๊ฐœ์š”

NestJS๋Š” ํšจ์œจ์ ์ด๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•œ Node.js ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ์ตœ์‹ ์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์™„๋ฒฝํžˆ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๋ณธ์งˆ์ ์œผ๋กœ NestJS๋Š” ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋น ๋ฅด๊ณ  ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์™€ ๊ตฌํ˜„ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ˜ ๋…ธ๋“œ ์œ„์˜ ๊ณ„์ธต์ž…๋‹ˆ๋‹ค. NestJS๋Š” ์—ฌ๋Ÿฌ๋ถ„์ด ํ•„์š”ํ•œ ๊ฒƒ์„ ๋ชจ๋‘ ๋งŒ์กฑ์‹œ์ผœ์ฃผ์–ด ์•„์ฃผ ํŽธ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜๊ธฐ๊ฐ€ ์ข‹๊ณ  ๊ธฐ๋ณธ์ ์œผ๋กœ Express ๊ธฐ๋ฐ˜์—์„œ ๋™์ž‘ํ•˜์ง€๋งŒ ์„ ํƒ์ ์œผ๋กœ Fastify๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Node.js๊ฐ€ ์žˆ๋Š”๋ฐ NestJS๋ฅผ ์จ์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ผ๊นŒ์š”?

  • Nest๋Š” Node ์œ„์—์„œ ์ถ”์ƒํ™” ๊ณ„์ธต์„ ์ œ๊ณตํ•˜๋Š”๋ฐ ์ด๋Š” Node์˜ ๊ธฐ๋Šฅ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์„ฑ๋Šฅ๊ณผ ํšจ์œจ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ์Šˆํผ์ฐจ์ € API๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฐœ๋ฐœ์ž๋“ค์€ ๊ธฐ๋Šฅ์„ ์‚ฌ๋ž‘ํ•˜๊ณ  ์—ฌ๋Ÿฌ๋ถ„์ด ๋” ๋งŽ์€ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด ๊ทธ๊ฒƒ์€ ๋ฌด์‹œํ•˜์ง€ ๋ชปํ•  ์žฅ์ ์ž…๋‹ˆ๋‹ค. ๋ฐ”๋กœ Nest๊ฐ€ ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ๊ฐœ๋ฐœ ๊ณผ์ •์„ ๋น ๋ฅด๊ฒŒ ํ•ด์ฃผ๋Š” ์—ฌ๋Ÿฌ ์„œ๋“œํŒŒํ‹ฐ ๋ชจ๋“ˆ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฐฑ์—”๋“œ ํŒจ๋Ÿฌ๋‹ค์ž„์œผ๋กœ๋ถ€ํ„ฐ ์™„์ „ํžˆ ๋ฒ—์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋™์ผํ•œ ์ข…๋ฅ˜์˜ ์ฝ”๋“œ๋ฅผ ์“ฐ๊ณ  ์žˆ์Œ์—๋„ ๊ฒฌ๊ณ ์„ฑ์ด ์ถ”๊ฐ€๋œ ์ธต์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • Nest๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํ•จ๊ป˜ ์ž‘์—…ํ•  ๋•Œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ORM์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์”๋‹ˆ๋‹ค. ์ฆ‰, ์‰ฝ๊ฒŒ ํ™œ์šฉ ๊ฐ€๋Šฅํ•œ Active Record ๋ฐ Data Mapper ํŒจํ„ด๊ณผ ๊ฐ™์€ ์ข‹์€ TypeORM ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Active Record ํŒจํ„ด์€ ๋‹จ์ˆœํ•จ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๋ฐ ๋„์›€์ด ๋˜๊ณ  Data Mapper ํŒจํ„ด์€ ์œ ์ง€๋ณด์ˆ˜ ํ•˜๊ธฐ ์ข‹์€ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.
  • ๋˜ํ•œ Nest์˜ ์•„ํ‚คํ…์ฒ˜๋Š” ์•ต๊ทค๋Ÿฌ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ๋ถ€ํ„ฐ ๋งŽ์€ ์˜๊ฐ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค. ํ•„์š”ํ•  ๋•Œ ์‰ฝ๊ฒŒ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๊ณ  ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์–ธ์ œ๋‚˜ ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Nest๊ฐ€ ๊ผญ ํ•„์š”ํ•œ ๊ตฌ์กฐ๋ฅผ ์ œ๊ณตํ•œ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

3ํ‹ฐ์–ด ์•„ํ‚คํ…์ฒ˜ NestJS์˜ ๊ฒฝํ–ฅ

ํŠผํŠผํ•œ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์–˜๊ธฐํ•  ๋•Œ, ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์žฅ ์ค‘์š”ํ•˜๊ฒŒ ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์—ฌ๋Ÿฌ ๋ถ€๋ถ„์„ ๋ถ„๋ฆฌํ•˜์—ฌ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ตฌ์กฐ์ ์ธ ํŒจํ„ด์„ ๋”ฐ๋ฅด๋Š” ๊ฒƒ์€ ์ž‘์„ฑํ•˜๊ณ  ์žˆ๋Š” ์ŠคํŒŒ๊ฒŒํ‹ฐ ์ฝ”๋“œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜ ํ”Œ๋กœ์šฐ ๋‹ค์ด์–ด๊ทธ๋žจ์„ ๊ณ ๋ คํ•ด๋ณผ ๋•Œ ์ปจํŠธ๋กค๋Ÿฌ์™€ ์„œ๋น„์Šค ๋ ˆ์ด์–ด๊ฐ€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜์—ฌ ๋…ผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ๋‘˜์€ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ปจํŠธ๋กค๋Ÿฌ๋“ค์€ ๋ณธ์งˆ์ ์œผ๋กœ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฃจํŠธ(route)๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๋ช‡ ๊ฐ€์ง€ ๋‹ค๋ฅธ ๋ฃจํŠธ๋ฅผ ๊ฐ€์ง€๊ณ  ๋ผ์šฐํŒ… ๋ฉ”์ปค๋‹ˆ์ฆ˜์— ๋”ฐ๋ผ ์–ด๋–ค ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์–ด๋–ค ์š”์ฒญ์— ๋Œ€ํ•ด ์‘๋‹ตํ• ์ง€ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ชจ๋“  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ปจํŠธ๋กค๋Ÿฌ ๋‚ด๋ถ€์— ๋„ฃ๋Š”๋‹ค๋ฉด ์–ด๋–จ๊นŒ์š”? ์•„๋งˆ๋„ ์•„์ง ์œ ์ €๊ฐ€ ๋“ฑ๋ก๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ƒˆ ์œ ์ €๋ฅผ ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜ ์ปจํŠธ๋กค๋Ÿฌ ๋‚ด์—์„œ๋งŒ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ƒํ™ฉ์€ ๋ง์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ํฌํ‚ค๊ฐ€ ์ž‘๋‹ค๋ฉด ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ปค์ง์— ๋”ฐ๋ผ ๋” ๋งŽ์€ ์ปจํŠธ๋กค๋Ÿฌ์™€ ๋ฃจํŠธ๊ฐ€ ํ•„์š”ํ•ด์ง€๋ฉฐ ๋” ๋งŽ์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋œ๋‹ค๋ฉด ์ƒํ™ฉ์€ ํ†ต์ œ ๋ถˆ๊ฐ€๋Šฅํ•ด์ง€๋ฉฐ ์œ ์ง€๋ณด์ˆ˜ํ•  ์ˆ˜ ์—†๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

image

  1. ์ปจํŠธ๋กค๋Ÿฌ(controllers) : ์ปจํŠธ๋กค๋Ÿฌ์˜ ์œ ์ผํ•œ ๋ชฉ์ ์€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•œ ์š”์ฒญ์„ ๋ฐ›๊ณ  route ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  2. ์„œ๋น„์Šค ๊ณ„์ธต(service layer) : ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ชจ๋“  CRUD ๋™์ž‘๋“ค์ด๋‚˜ ์–ด๋–ป๊ฒŒ ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์ €์žฅ๋˜๋ฉฐ ๊ฐฑ์‹ ๋˜๋Š”์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต(data access layer) : ์˜๊ตฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋กœ์ง์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ex. ๋ชฝ๊ตฌ์Šค์™€ ๊ฐ™์€ ODM

NestJS ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

CLI๋ฅผ ์‚ฌ์šฉํ•ด์„œ NestJS ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๋ฉด, ๋ช‡ ๊ฐ€์ง€ ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ํŒŒ์ผ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์ž‘์—…ํ•˜๋Š” ์ฝ”์–ด ํŒŒ์ผ๋“ค์ž…๋‹ˆ๋‹ค. ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

src
| โ€” app.controller.spec.ts
| โ€” app.controller.ts
| โ€” app.module.ts
| โ€” app.service.ts
| โ€” main.ts
  • app.controller.ts : ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ route๋ฅผ ํฌํ•จํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ ํŒŒ์ผ
  • app.controller.spec.ts : ์ปจํŠธ๋กค๋Ÿฌ์— ๋Œ€ํ•œ ์œ ๋‹› ํ…Œ์ŠคํŠธ ํŒŒ์ผ
  • app.module.ts : ์ปจํŠธ๋กค๋Ÿฌ์™€ ํ”„๋กœ๋ฐ”์ด๋”์˜ ๋ฌถ์Œ
  • app.service.ts : ํŠน์ • ๋™์ž‘์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๋Š” ํŒŒ์ผ
  • main.ts : ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์—”ํŠธ๋ฆฌ ํŒŒ์ผ๋กœ ๋ชจ๋“ˆ ๋ฒˆ๋“ค์„ ๊ฐ€์ ธ์™€์„œ NestFactory๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์•ฑ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑ

์—ฌ๋Ÿฌ๋ถ„์ด ๋”ฐ๋ผ์•ผ ํ•˜๋Š” ํŠน์ • ๊ตฌ์กฐ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฑธ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ตฌ์กฐ๋Š” ๊นจ๋—ํ•˜๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๋ฉฐ ์œ ์ง€๋ณด์ˆ˜ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ ์‚ดํŽด๋ณด๊ธฐ

์„œ๋น„์Šค ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ์ปจํŠธ๋กค๋Ÿฌ ํŒŒ์ผ ๋‚ด์—์„œ ์ž„ํฌํŠธํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” CatsService๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ export ํ•ด๋ด…์‹œ๋‹ค.

import { Injectable } from '@nestjs/common';

@Injectable()
export class CatsService {
  getAllCats(): string {
    return 'Get all cats!';
  }

  getOneCat(): string {
    return 'Get one cat!';
  }
}

CatsService ํด๋ž˜์Šค๋ฅผ ์ต์ŠคํฌํŠธํ•˜๊ณ  ์„ธ ๊ฐ€์ง€์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ @Injectable() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ฒจ๋ถ€ํ•˜๊ณ  ์ฃผ์ž… ๊ฐ€๋Šฅํ•œ ํด๋ž˜์Šค๋ฅผ ์ข…์†์„ฑ์œผ๋กœ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ํด๋ž˜์Šค๋ฅผ ๋””ํŽœ๋˜์‹œ๋กœ ์ฃผ์ž…ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ณ ์–‘์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { Controller, Get } from '@nestjs/common';
import { CatsService } from '../services/cats.service';

@Controller('cats')
export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Get('allcats')
  getCats(): string {
    return this.catsService.getAllCats();
  }

  @Get('onecat')
  getOneCat(): string {
    return this.catsService.getOneCat();
  }
}

์ปจํŠธ๋กค๋Ÿฌ ํŒŒ์ผ์—์„œ CatsService๋ฅผ ์ž„ํฌํŠธํ•˜๊ณ  ์ƒ์„ฑ์ž ๋‚ด์—์„œ ์„œ๋น„์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. CatsService ๋””ํŽœ๋˜์‹œ๋Š” ํด๋ž˜์Šค ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ฃผ์ž…๋ฉ๋‹ˆ๋‹ค. (dependency injection) CatsService ๋‚ด์—์„œ ์ •์˜ํ•œ ์—ฌ๋Ÿฌ ๋ฉ”์†Œ๋“œ๋ฅผ ๋…ธ์ถœ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ณ ์–‘์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ต๋‹ˆ๋‹ค.

์˜์กด์„ฑ์€ ํด๋ž˜์Šค๊ฐ€ ํ•จ์ˆ˜๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์„œ๋น„์Šค ๋˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์˜์กด์„ฑ ์ฃผ์ž…(DI)์€ ํด๋ž˜์Šค๊ฐ€ ์™ธ๋ถ€ ์†Œ์Šค๋กœ๋ถ€ํ„ฐ ์ข…์†์„ฑ์„ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹  ์š”์ฒญํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

@get() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์ธ์ž๋ฅผ ๋ฐ›์•„ ์ถ”๊ฐ€๋œ ๊ธฐ๋Šฅ๊ณผ ๋™์ผํ•œ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ @get() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํŠน์ • route๋ฅผ ์š”์ฒญํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” pathname์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด /cats/allCats ์— ๋Œ€ํ•œ ์š”์ฒญ์€ getCats๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ชจ๋“  ๊ณ ์–‘์ด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

[์ •๋ฆฌ] React Conf 2021

"Great User Experience"

First Block ๐Ÿ‘€

Keynote

  • ์ผ๋ฐ˜ ๊ฐœ๋ฐœ์ž ์™ธ์—๋„ ๋””์ž์ด๋„ˆ๋“ค์—๊ฒŒ React๊ฐ€ ์˜ํ–ฅ์„ ๋ผ์นœ๋‹ค (framer)
  • rooted in design principle, not programming
  • React made components a mainstream part of UI dev => designers and developers speak "the same language"

Suspense

  • Read data over the network as easily as props or state
  • React 16-17์—์„œ์˜ Suspense๋Š” client์—์„œ React.lazy๋ฅผ ์ด์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๋™์ ์œผ๋กœ ๋กœ๋”ฉํ•˜๋Š” ๊ฒฝ์šฐ์— ์žฅ์ ์ด ์žˆ์—ˆ์Œ
    • SSR์—์„œ๋Š” ๋ถˆ๊ฐ€๋Šฅ
  • React ์ฝ”๋“œ๋Š” top-down์œผ๋กœ ์ฝ๊ธฐ ์ข‹์€๋ฐ ๋น„๋™๊ธฐ ์ฝ”๋“œ๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ์ˆœ๊ฐ„ ๋ถˆ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.
  • Reading the data + Specifying the loading state
if (isLoading) return <Spinner />;
return (...);

// declarative way !
<Suspense fallback={<Spinner />}>
  <List pageId={pageId} />
</Suspese>

"design centric idea"

  • 16~17 : (c) Code Splitting with React.lazy
  • 18 : (c) Data fetching via compatible libs, like Relay (s) Streaming server rendering
  • Next steps : General support for data fetching, Server components
    • ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด Relay๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š์Œ, Suspense์™€ Relay๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ๋ฐ˜๋ณตํ•˜๋Š” ๊ฒƒ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŒ๋“œ๋Š” ์‚ฌ๋žŒ๋„ ํž˜๋“  ์ผ!

Concurrent Redering : "A behind-the-scenes capability in React that powers features like Suspense"

"what์— ์ง‘์ค‘ํ•˜๋ผ, React๋Š” how์— ์ง‘์ค‘ํ•œ๋‹ค . . "

  • concurrent mode๊ฐ€ ์•„๋‹Œ concurrent features!

React without memo

Xuan Huang

React Forget

  • auto memoizing compiler
  • Research project in React Labs
  • familiar React, still React
  • ๋ฉ”๋ชจ์ด์ œ์ด์…˜์€ UX๋ฅผ ํ–ฅ์ƒ์‹œํ‚ค์ง€๋งŒ DX์—๋Š” ์ข‹์ง€ ์•Š๋‹ค.
  • ์ฆ‰, React Forget์€ DX๋ฅผ ์ข‹์ง€ ์•Š๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฉ”๋ชจ์ด์ œ์ด์…˜์„ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ํ”„๋กœ์ ํŠธ (์•„์ง ๊ณต๊ฐœX)

example code

function TodoList({ visibility, themeColor }) {
  const [todos, setTodos] = useState(initialTodos);
  const handleChange = todo => setTodos(todos => getUpdated(todos, todo));
  const filtered = getFiltered(todos, visibility);

  return (
    <div>
      <ul>
        {filtered.map(todo => (
          <Todo key={todo.id} todo={todo} onChange={handleChange} />
        ))}
      </ul>
      <AddTodo setTodos={setTodos} themeColor={themeColor} />
    </div>
  );
}
function TodoList({ visibility, themeColor }) {
  const [todos, setTodos] = useState(initialTodos)
  let hasVisibilityChanged, hasThemeColorChanged, hasTodosChanged, memoCache

  if (hasVisibilityChanged || hasThemeColorChanged || hasTodosChanged) {
    const handleChange = memoCache[0] || (memoCache[0] = (todo) => setTodos((todos) => getUpdated(todos, todo)))

    let filtered, jsx_todos
    if (hasVisibilityChanged || hasTodosChanged) {
      filtered = memoCache[1] = getFiltered(todos, visibility)
      jsx_todos = memoCache[2] = (
        <ul>
          {filtered.map((todo) => (
            <Todo key={todo.id} todo={todo} onChange={handleChange} />
          ))}
        </ul>
      )
    } else {
      filtered = memoCache[1]
      jsx_todos = memoCache[2]
    }
  }

  const jsx_addTodo = hasThemeColorChanged ? (memoCache[3] = <AddTodo setTodos={setTodos} themeColor={themeColor} />) : memoCache[3]

  return (
    <div>
      {jsx_todos}
      {jsx_addTodo}
    </div>
  )
}

Final Block

React 18 for External Store Libraries

Daishi Kato

  • internal states : props context useState useReducer
  • ์ด ์™ธ์—๋Š” ๋ชจ๋‘ external stores
  • tearing : ์ •๋ณด์˜ ๋ถˆ์ผ์น˜๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ž˜๋ชป๋œ ์Šคํฌ๋ฆฐ์„ ๋ณด์—ฌ์ฃผ๋Š” ๋ฌธ์ œ
  • useSyncExternalStore : React 18์—์„œ ๋„์ž…

useSyncExternalStore

  • subscribe: get callback, return unsubscribe func
  • getSnapshot : return immutable value
  • ์™ธ๋ถ€ ์Šคํ† ์–ด๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ํ˜•ํƒœ

Accessible Japanese Form Components with React

Tafu Nakazaki (SmartHR)

  • ์ผ๋ณธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” administrative docs๋Š” ๋ณต์žกํ•˜๊ณ  ์ดํ•ดํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค (name, age, address, etc ...) ๐Ÿคฏ
  • HR & management๋Š” ๋ณต์žกํ•˜๊ณ  ๋‹ค์–‘ํ•จ
    • ํŠนํžˆ ๋ฌธ์„œ๋ฅผ ์ฝ๋Š” ๊ฒƒ์ด ์–ด๋ ค์šด ๊ฒฝ์šฐ๋„ ์žˆ์Œ ==> web based docs ! (์ ‘๊ทผ์„ฑ์ด ์ฆ๊ฐ€)
    • Web Content Accessibility Guidelines (WCAG)
  • React๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ declarative UI ๊ตฌํ˜„

[๋ฒˆ์—ญ] GraphQL ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ง€์นจ์„œ : Offset vs. Cursor vs. Relay ์Šคํƒ€์ผ ํŽ˜์ด์ง€๋„ค์ด์…˜

์›๋ฌธ GraphQL Pagination Primer: Offset vs. Cursor vs. Relay-Style Pagination

์ด ํฌ์ŠคํŒ…์€ ์ œ๊ฐ€ ์ €์ˆ ํ•œ Advanced GraphQL with Apollo & React์˜ Relay ์Šคํƒ€์ผ ํŽ˜์ด์ง€๋„ค์ด์…˜์— ๋Œ€ํ•œ ์ฑ•ํ„ฐ์—์„œ ๋ฐœ์ทŒํ–ˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์ด GraphQL API๋ฅผ ๊ฐœ๋ฐœํ•  ๋•Œ ๋ฐ์ดํ„ฐ ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š” ๋ฐ ๋ชจ๋“  ๊ฒฐ๊ณผ๋ฅผ ํ•œ ๋ฒˆ์— ๊ฒ€์ƒ‰ํ•˜๊ธฐ์—๋Š” ๋„ˆ๋ฌด ๋งŽ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ GraphQL ์ฟผ๋ฆฌ ๋‚ด์—์„œ ์ค‘์ฒฉ๋œ ๋ฆฌ์ŠคํŠธ ํ•„๋“œ๋“ค์—๋„ ํ•ด๋‹นํ•˜๋Š” ์–˜๊ธฐ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์ด ํ•„์š”ํ•œ ๊ฒƒ์ด์ฃ .

์šฐ๋ฆฌ๊ฐ€ ๋งค์ผ ์‚ฌ์šฉํ•˜๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๋„ˆ๋ฌด ํ”ํ•œ ๊ธฐ๋Šฅ์ด์ง€๋งŒ, ์ž˜ ๊ตฌํ˜„ํ•˜๊ธฐ์—๋Š” ๊นŒ๋‹ค๋กœ์šด ๊ธฐ๋Šฅ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ ์ˆ  ๋” ๋– ์„œ GraphQL ์ฟผ๋ฆฌ๊ฐ€ ์–ด๋–ค ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ• ์ง€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ ์„ ํƒ์ง€๋“ค์ด ์กด์žฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ „์— ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ตฌํ˜„ํ•œ ์ ์ด ์žˆ๋‹ค๋ฉด ์•„๋งˆ offset ๊ธฐ๋ฐ˜์ด๋‚˜ cursor ๊ธฐ๋ฐ˜ ๋ฐฉ์‹์— ๋” ์นœ์ˆ™ํ•˜์‹ค ๊ฒ๋‹ˆ๋‹ค. GraphQL API๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์šฐ๋ฆฌ์—๊ฒŒ๋Š” Relay-style ํŽ˜์ด์ง€๋„ค์ด์…˜์ด๋ผ๋Š” ํ•˜๋‚˜์˜ ์˜ต์…˜์ด ๋” ์žˆ์Šต๋‹ˆ๋‹ค.

Relay-style ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ํŽ˜์ด์ง• GraphQL ์ฟผ๋ฆฌ์—์„œ๋Š” ๊ฝค ์ธ๊ธฐ์žˆ๋Š” ์„ ํƒ์ง€์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ GraphQL ์Šคํ‚ค๋งˆ๊ฐ€ Relay ๋ช…์„ธ๋ฅผ ์ค€์ˆ˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋ช‡ ๊ฐ€์ง€ ๊ณ ๋ คํ•  ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํฌ์ŠคํŒ…์—์„œ๋Š” ๊ฐ ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋ฐฉ์‹์— ๋”ฐ๋ฅธ ์žฅ์ ๊ณผ ๋‹จ์ ์„ ์‚ดํŽด๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ ํ›„์— ์—ฌ๋Ÿฌ๋ถ„์—๊ฒŒ ๋” ์ ํ•ฉํ•œ ๋ฐฉ์‹์„ ์„ ํƒํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์˜คํ”„์…‹ ๊ธฐ๋ฐ˜

์—ญ์‚ฌ์ ์œผ๋กœ ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ๋ถ€ํ„ฐ ๊ฒฐ๊ณผ๊ฐ’๋“ค์„ ํŽ˜์ด์ง•ํ•˜๋Š” ์ธ๊ธฐ์žˆ๋Š” ์„ ํƒ์ง€์˜€์Šต๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ํŽ˜์ด์ง•์„ ํ•˜๋ฉด, ํด๋ผ์ด์–ธํŠธ๋Š” ํŽ˜์ด์ง€ ๋‹น ๋ฐ›๊ณ ์ž ํ•˜๋Š” ํ•ญ๋ชฉ์˜ ๊ฐ’์— ๋Œ€ํ•œ ์ •๋ณด(limit์ด๋ผ ๋ถˆ๋ฆผ)์™€ ๋›ฐ์–ด ๋„˜์„ ํ•ญ๋ชฉ๋“ค์˜ ๊ฐœ์ˆ˜์— ๋Œ€ํ•œ ์ •๋ณด(offset์ด๋ผ ๋ถˆ๋ฆผ)๋ฅผ ์„œ๋ฒ„์— ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์„œ๋ฒ„๋Š” ์ด ๊ธฐ์ค€์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ํŠน์ • ๋ฐ์ดํ„ฐ ์…‹์„ ์ฟผ๋ฆฌํ•ด์˜ต๋‹ˆ๋‹ค. (ํ•„์š”ํ•˜๋‹ค๋ฉด ๊ธฐ๋ณธ limit, offset์„ ์„ค์ •ํ•ด๋‘ก๋‹ˆ๋‹ค.)

์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์‹œ๊ฐ์ ์œผ๋กœ ๋ณด๊ธฐ ์œ„ํ•ด, 5๊ฐœ ํ•ญ๋ชฉ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฐ์ดํ„ฐ ์…‹์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์„ธ์š”. ๊ทธ๋ฆฌ๊ณ  ๊ฐ ํŽ˜์ด์ง€ ๋‹น 2๊ฐœ์”ฉ, ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ๋˜์–ด ์žˆ๋Š” ํ•ญ๋ชฉ๋“ค์˜ ๋‘ ๋ฒˆ์งธ ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ฌ ๊ฒ๋‹ˆ๋‹ค.

์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ „์ฒด ํŽ˜์ด์ง€ ์ˆ˜๋ฅผ ์•Œ๊ณ  ์žˆ์„ ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์–‘๋ฐฉํ–ฅ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์ž˜ ์ง€์›ํ•˜์ฃ . ์–‘๋ฐฉํ–ฅ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ํŽ˜์ด์ง€ ์•ž์œผ๋กœ, ๋’ค๋กœ ์ด๋™ํ•˜๊ฑฐ๋‚˜ ํŠน์ • ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋ธ”๋กœ๊ทธ์™€ ๊ฐ™์€ ๊ณณ์—์„œ ๋งŽ์ด ๋ณด์ด๋Š” ๋ฐฉ์‹์ด์ฃ .

๊ทธ๋Ÿฌ๋‚˜ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฌ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋„ˆ๋ฌด ๋งŽ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์— ์ด ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ์„ฑ๋Šฅ ์ €ํ•˜ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๊ฐ€ ๋นˆ๋ฒˆํ•˜๊ฒŒ ์ถ”๊ฐ€๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์‹ค์‹œ๊ฐ„์œผ๋กœ ํŽ˜์ด์ง€ window๊ฐ€ ์ž˜๋ชป ๋งค์นญ๋˜์–ด ๋ฐ์ดํ„ฐ๊ฐ€ ์ค‘๋ณต๋˜์–ด ๋ณด์ด๊ฑฐ๋‚˜ ์œ ์‹ค๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์œ„ํ—˜์„ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ์…‹์—์„œ ์ฒซ ๋ฒˆ์งธ ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ƒํ™ฉ์„ ๊ฐ€์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ํ•ด๋‹น ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋Š” ๋™์•ˆ ๋‹ค์Œ ํŽ˜์ด์ง€์— ๋„˜์–ด๊ฐ€๊ธฐ ์ „์— 6๋ฒˆ์งธ ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ‘์ž๊ธฐ ํŽ˜์ด์ง€ ์œˆ๋„์šฐ๊ฐ€ ํ•œ ์ž๋ฆฌ์”ฉ ๋ฐ€๋ฆฌ๊ฒŒ ๋˜์–ด 4๋ฒˆ์งธ ๋ฐ์ดํ„ฐ๊ฐ€ ์ฒซ ๋ฒˆ์งธ ํŽ˜์ด์ง€์˜ ๋งˆ์ง€๋ง‰์ด์ž ๋‘ ๋ฒˆ์งธ ํŽ˜์ด์ง€์˜ ์ฒ˜์Œ์— ๋ณด์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ปค์„œ ๊ธฐ๋ฐ˜

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๋ฐ์ดํ„ฐ์…‹์—์„œ ๊ฒฐ๊ณผ๋ฌผ๋“ค์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ์ปค์„œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ปค์„œ๋Š” ๋ฐ์ดํ„ฐ์…‹์—์„œ ํŠน์ • ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ์ž…๋‹ˆ๋‹ค. ๊ณ ์œ ํ•˜๊ณ  ์ˆœ์ฐจ์ ์ธ ๊ฐ’๋“ค์— ํ•œํ•ด์„œ ๋ฐฑ์—”๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ํ•ฉํ•œ ์–ด๋–ค ๊ฐ’์ด๋“  ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ดํ›„ ํŽ˜์ด์ง€๋ฅผ ํƒ์ƒ‰ํ•  ๋•Œ ์„œ๋ฒ„๋Š” ์ปค์„œ ๊ฐ’์œผ๋กœ ํ‘œ์‹œ๋œ ํ•ญ๋ชฉ ๋’ค์— ์žˆ๋Š” ๊ฒฐ๊ณผ๊ฐ’๋“ค์„ ๋ฐ˜ํ™˜ํ•ด์ค๋‹ˆ๋‹ค.

5๊ฐœ์˜ ๋ฐ์ดํ„ฐ์…‹์—์„œ ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ปค์„œ ํŠน์„ฑ ์ž์ฒด๊ฐ€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ค‘์š”ํ•œ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋Š” ์ดํ›„ ๋‹ค์Œ ๊ฐ’๋“ค์— ๋Œ€ํ•ด ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์ปค์„œ ๊ฐ’์„ ์„œ๋ฒ„๋กœ ๋‹ค์‹œ ๋ณด๋‚ด๊ธฐ๋งŒ ํ•˜๋ฉด ์„œ๋ฒ„๊ฐ€ ์–ด๋Š ์‹œ์ ๋ถ€ํ„ฐ ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ๋ฐฉ์‹์—์„œ ๋ฐœ์ƒํ–ˆ๋˜ ํŽ˜์ด์ง€ ์œˆ๋„์šฐ์˜ ๋ถ€์ •ํ™•์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋น ๋ฅด๊ฒŒ ๊ฐฑ์‹ ๋˜๋Š” ๋ฐ์ดํ„ฐ์…‹์— ์•„์ฃผ ์ ํ•ฉํ•œ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  6๋ฒˆ์งธ ์•„์ดํ…œ์ด ์ถ”๊ฐ€๋˜์—ˆ์–ด๋„ ์ปค์„œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์— ํ˜ผ๋ž€์˜ ์—ฌ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ด ๋ฐฉ์‹์€ ๋‹จ์ ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปค์„œ ๊ธฐ๋ฐ˜์˜ ์ ‘๊ทผ์€ ํŠน์ • ํŽ˜์ด์ง€ ๋„˜๋ฒ„๋กœ ์ ํ”„ํ•˜๊ฑฐ๋‚˜ ์ „์ฒด ํŽ˜์ด์ง€ ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋น ๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜๊ณ  ์ปจํ…์ธ ๋ฅผ ๋ธŒ๋ผ์šฐ์ง•ํ•˜๋Š” ๋ฌดํ•œ ์Šคํฌ๋กค์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•  ๋•Œ๋Š” ํŽ˜์ด์ง€ ๋„˜๋ฒ„๋‚˜ ์ „์ฒด ํŽ˜์ด์ง€ ์ˆ˜๊ฐ€ ์—†๋Š” ๊ฒƒ์ด ์ „ํ˜€ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Relay ์Šคํƒ€์ผ

Relay-style ํŽ˜์ด์ง€๋„ค์ด์…˜์€ GraphQL API์—์„œ ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์— ์•ฝ๊ฐ„์˜ ํ–ฅ์ด ์ฒจ๊ฐ€๋œ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. Relay ์ž์ฒด๋Š” GraphQL API์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์บ์‹ฑํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” JavaScript ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ํŽ˜์ด์Šค๋ถ์— ์˜ํ•ด ๋งŒ๋“ค์–ด์กŒ๊ณ  ํŽ˜์ด์Šค๋ถ ์ˆ˜์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์€ ์•ฑ์„ ์—ผ๋‘์— ๋‘๊ณ  ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Relay๋Š” Apollo Client์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ์˜ต์…˜๋“ค๋ณด๋‹ค๋Š” ์ข€ ๋” ์ง„์ž… ์žฅ๋ฒฝ์ด ๋†’์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ GraphQL์„ ์‹œ์ž‘ํ•  ๋•Œ Relay ์ž์ฒด๊ฐ€ ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒŒ ์ฒซ ๋ฒˆ์งธ ํŒจํ‚ค์ง€๋Š” ์•„๋‹ˆ์ฃ . ๊ทธ๋Ÿฌ๋‚˜ Relay๋Š” GraphQL API์—์„œ ์–ด๋–ป๊ฒŒ ํŽ˜์ด์ง•๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ์œ ์šฉํ•œ ๋กœ๋“œ๋งต์„ ์ œ๊ณตํ•˜๋Š”๋ฐ, ์ด๋ฅผ "์ปค์„œ ์ปค๋„ฅ์…˜ ๊ทœ๊ฒฉ(GraphQL Cursor Connections Specification)"์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์€ ์ด ๋งํฌ์—์„œ Relay์˜ ์ „์ฒด ๊ทœ๊ฒฉ์„ ์ฝ์–ด๋ณด์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋น„๋ก ์—ฌ๋Ÿฌ๋ถ„์˜ ํด๋ผ์ด์–ธํŠธ ์•ฑ์—์„œ Relay๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•˜์ง€๋Š” ์•Š์•„๋„, ์—ฌ๋Ÿฌ๋ถ„์€ GraphQL API์—์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ตฌํ˜„ํ•  ๋•Œ ์—ฌ์ „ํžˆ ์ด ๊ทœ๊ฒฉ์„ ๋”ฐ๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ Relay๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋‚˜์ค‘์— ์—ฌ๋Ÿฌ๋ถ„์˜ API์— ์š”์ฒญ์„ ๋ณด๋‚ด๋ ค๋Š” ๊ฒฝ์šฐ ์ด ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ๋•Œ ์—ฌ๋Ÿฌ๋ถ„์˜ API๋ฅผ ์ข€ ๋” ๋ฏธ๋ž˜์ง€ํ–ฅ์ ์œผ๋กœ ๋งŒ๋“ค์–ด์ค„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Relay-style ํŽ˜์ด์ง€๋„ค์ด์…˜์—์„œ ๊ธฐ์–ตํ•ด์•ผ ํ•  ์ค‘์š”ํ•œ ์ ์€ ๋‹จ๋ฐฉํ–ฅ์„ฑ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ์•ฑ์—์„œ "์ด์ „ ํŽ˜์ด์ง€" ๋ฒ„ํŠผ๊ณผ "๋‹ค์Œ ํŽ˜์ด์ง€" ๋ฒ„ํŠผ์œผ๋กœ ์ปจํ…์ธ  ์ด๋™์„ ๊ตฌํ˜„ํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด Relay ๋ฐฉ์‹์€ ์•„๋งˆ ์—ฌ๋Ÿฌ๋ถ„์—๊ฒŒ ์ ํ•ฉํ•œ ๋ฐฉ์‹์ด ์•„๋‹ ๊ฒ๋‹ˆ๋‹ค. (๊ตฌ๊ธ€๋ง์„ ํ•˜๋ฉด ์–‘๋ฐฉํ–ฅ ํŽ˜์ด์ง•์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๊ธฐ๋Š” ํ•ฉ๋‹ˆ๋‹ค.) ๊ทธ๋Ÿฌ๋‚˜ ์ถ”๊ฐ€์ ์ธ ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ค„ ๋•Œ ๋ฌดํ•œ ์Šคํฌ๋กค์˜ UI๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด, ์ด ๋ฐฉ์‹์€ ์•„์ฃผ ์ž˜ ๋งž์„ ๊ฒ๋‹ˆ๋‹ค.

์ด์ „์— ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, Relay๋Š” ํŽ˜์ด์ง•๋œ ์ฟผ๋ฆฌ ๋ฐ์ดํ„ฐ์˜ ์•„์›ƒํ’‹ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ธ์ˆ˜๋ฅผ ํ†ตํ•ด ์š”์ฒญ์ด ์ด๋ฃจ์–ด์ง€๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•ด ๋งค์šฐ ํ™•๊ณ ํ•ฉ๋‹ˆ๋‹ค. Relay ๋ฐฉ์‹์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์œผ๋กœ ๊ตฌํ˜„๋œ ๊ฐ€์ƒ ์ฟผ๋ฆฌ์˜ ์˜ˆ๋ฅผ ๋ด…์‹œ๋‹ค. following ํ•„๋“œ๋Š” User ๊ฐ์ฒด์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

query {
  user(username: "bob") {
    fullName
    following(first: 20, after: "someProfileId") {
      edges {
        cursor
        node {
          fullName
          username
        }
      }
      pageInfo {
        hasPreviousPage
        hasNextPage
      }
    }
  }
}

์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ์ด ์ฟผ๋ฆฌ์˜ ๋ช‡ ๊ฐ€์ง€ ์žฌ๋ฐŒ๋Š” ํŠน์ง•์— ๋Œ€ํ•ด ์•Œ์•„์ฐจ๋ฆฌ์…จ์„ ๊ฒ๋‹ˆ๋‹ค. ๋จผ์ €, ์ฟผ๋ฆฌ์— edge ํƒ€์ž…์„ ๋ฆฌ์ŠคํŠธ๋กœ ๊ฐ–๊ณ  ์žˆ๋Š”edges๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด edge ํƒ€์ž…์€ node์™€ cursor๋กœ ๋ถˆ๋ฆฌ๋Š” ์ตœ์†Œ 2๊ฐœ์˜ ํ•„๋“œ๋กœ ์ด๋ฃจ์–ด์ง„ ๊ฐ์ฒด ํƒ€์ž…์ž…๋‹ˆ๋‹ค.

node ํ•„๋“œ๋Š” ๊ฐ์ฒด ์ž์ฒด์ด๊ณ  ๋ฆฌ์ŠคํŠธ๋ฅผ ์ œ์™ธํ•œ GraphQL ์–ด๋–ค ํƒ€์ž…์ด๋“  ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์šฐ๋ฆฌ์˜ ๊ฒฝ์šฐ์—๋Š” User ํƒ€์ž…์ด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.) cursor ํ•„๋“œ๋Š” ๊ฐ edge๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ ํ•˜๊ณ  ์ˆœ์ฐจ์ ์ธ ๊ฐ’์— ํ•ด๋‹นํ•˜๋Š” ๋ฌธ์ž์—ด์ž…๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ pageInfo๋Š” hasPreviousPage์™€ hasNextPage ํ•„๋“œ๋ฅผ ๋ฌด์กฐ๊ฑด ๊ฐ€์ง€๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ๋‘ ํ•„๋“œ ๋ชจ๋‘ null์ด ๋  ์ˆ˜ ์—†๋Š” boolean ๊ฐ’์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ์ฟผ๋ฆฌ์˜ first, after ์ธ์ˆ˜์— ๋Œ€ํ•ด ์ฃผ๋ชฉํ•ด์•ผ ํ•˜๋Š”๋ฐ ์ด ๊ฐ’๋“ค์€ ์ •๋ฐฉํ–ฅ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์œ„ํ•œ ์ธ์ˆ˜ ๊ฐ’๋“ค์ž…๋‹ˆ๋‹ค. ์ •๋ฐฉํ–ฅ์ด ์•„๋‹ˆ๋ผ ์—ญ๋ฐฉํ–ฅ์œผ๋กœ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด last, before ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•  ๊ฒ๋‹ˆ๋‹ค.

์ฐธ๊ณ ! ์—ญ๋ฐฉํ–ฅ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ๊ณผ๋Š” ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ์…‹์˜ ๋์—์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ ์ฒ˜์Œ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ์€ ๋†’์€ ๊ฐ’๋ถ€ํ„ฐ ๋‚ฎ์€ ๊ฐ’์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ด๊ณ ์š”. ๋ฐ์ดํ„ฐ์…‹์€ ๋ณดํ†ต ๋จผ์ € ์ •๋ ฌ์ด ๋˜๊ณ , ์ •๋ ฌ๋œ ๊ฐ’๋“ค์˜ ํŽ˜์ด์ง€๋ฅผ ๊ฒ€์ƒ‰ํ•  ๋•Œ ์ •๋ฐฉํ–ฅ ๋˜๋Š” ์—ญ๋ฐฉํ–ฅ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์ ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์œ„ ์ฟผ๋ฆฌ ์˜ˆ์‹œ์—์„œ ๋ช…ํ™•ํ•˜์ง€ ์•Š์€ ์ ์€ ์ƒ์œ„ ์ˆ˜์ค€์˜ "connection type"์ด ๊ฐ์ฒด ์œ ํ˜•์œผ๋กœ ๊ตฌํ˜„๋˜๊ณ (์ ‘๋‘์‚ฌ๋กœ Connection์ด ๋ถ™๋Š”) following ํ•„๋“œ๊ฐ€ User ๊ฐ์ฒด ํƒ€์ž…์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฆฌ์ŠคํŠธ ๋Œ€์‹  ํ•˜๋‚˜์˜ ์ปค๋„ฅ์…˜ ๊ฐ์ฒด๋กœ ๋ฐ˜ํ™˜๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋‚˜ ๋ฌธ๋ฒ•์— ๋Œ€ํ•œ ์ด ๊ฐœ๋…์  ๋ชจ๋ธ์ด ์ฒ˜์Œ์—๋Š” ๋ถ€๋‹ด์Šค๋Ÿฌ์šธ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๋‹ค๋ฃจ๋Š” ๋ฐ ๊น”๋”ํ•˜๊ณ  ํ‘œ์ค€ํ™”๋œ ๋ฐฉ์‹์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์š”์•ฝ

์ด ํฌ์ŠคํŠธ์—์„œ๋Š” ์˜คํ”„์…‹, ์ปค์„œ, Relay ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์˜ 3๊ฐ€์ง€ ๋ฐฉ์‹์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์˜คํ”„์…‹ ๊ธฐ๋ฐ˜์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ (๋ณดํ†ต์€) ๋น ๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜๊ณ  ์–‘๋ฐฉํ–ฅ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์ง€์›ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ „์ฒด ํŽ˜์ด์ง€ ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•  ๋•Œ๋„ ์ข‹์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์„ฑ๋Šฅ ์ด์Šˆ๊ฐ€ ์žˆ๊ณ  ๋น ๋ฅด๊ฒŒ ๋ฐ์ดํ„ฐ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์ž˜ ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์•„์ฃผ ๋น ๋ฅด๊ฒŒ ๋ฐ์ดํ„ฐ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๊ณ  ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹จ๋ฐฉํ–ฅ์„ ์ง€์›ํ•  ๋•Œ ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์˜ ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Relay ๋ฐฉ์‹์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ GraphQL API๋กœ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ตฌํ˜„ํ•  ๋•Œ ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์— ์•ฝ๊ฐ„์˜ ์กฐ๋ฏธ๋ฃŒ๋ฅผ ์ฒจ๊ฐ€ํ•œ ๋˜ ํ•˜๋‚˜์˜ ์„ ํƒ์ง€์ž…๋‹ˆ๋‹ค.

์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ์ด ํฌ์ŠคํŠธ๊ฐ€ ๋งˆ์Œ์— ๋“œ์…จ๋‹ค๋ฉด Advanced GraphQL with Apollo & React์˜ ์ „์ฒด ์ฑ•ํ„ฐ๋ฅผ ๋ฌด๋ฃŒ๋กœ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์œผ์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํด๋ž˜์Šค๋Š” ํ•ด๋กญ๋‹ค

์›๋ฌธ : https://calvin.hashnode.dev/javascript-classes-are-harmful

๊ฝค ๋Œ€๋‹ดํ•œ ํ‘œํ˜„์ด์ง€๋งŒ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ข€ ๋‹ค๋ค„๋ณธ ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ๋‹ค๋“ค ๋Š๋ผ๋Š” ๊ฐ์ •์ผ ๊ฒ๋‹ˆ๋‹ค.
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์ œ๋Œ€๋กœ ๋ฐฐ์šฐ์ง€ ์•Š์œผ๋ฉด ๋‚˜์œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ์ ์€ ๋ฐ˜๋Œ€๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ˆ™๋‹ฌํ•˜์ง€ ์•Š๊ณ ๋„ ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ๋˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ด๋Ÿฐ ์ ์ด ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๋‘ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ํŒจ๋Ÿฌ๋‹ค์ž„์œผ๋กœ ๋น ์ง€๊ธฐ ์ „๊นŒ์ง€ ์˜ค๋žซ๋™์•ˆ ์ง€์†๋˜์–ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.

  • ํ”„๋กœํ† ํƒ€์ž… ์ƒ์†
  • ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฐฝ์กฐ์ž๊ฐ€ ์ด๋Ÿฌํ•œ ๊ธฐ๋‘ฅ๋“ค์„ ๋งŒ๋“  ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋‘ ํŒจ๋Ÿฌ๋‹ค์ž„์„ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋ณด์—ฌ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

์ƒ์„ฑ์ž๋Š” ํ•ญ์ƒ ํ‹€๋ฆฌ๋‹ค

// constructor function
function Person () {
    this.name = 'John',
    this.age = 23
}

// create an object
const person = new Person();

์—ฌ๋Ÿฌ๋ถ„์ด ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ ํ•จ์ˆ˜๋ฅผ ์ƒ์†ํ•  ๋•Œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๊ฐ€์ง€๋Š” ๋Šฅ๋ ฅ์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆœ ์—†์Šต๋‹ˆ๋‹ค.

  • ์ƒ์„ฑ์ž ํ•จ์ˆ˜์—์„œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์„ ๋ฌด๋„ˆ๋œจ๋ฆฌ๋Š”๋ฐ ์ด๋Š” ๋” ์ด์ƒ ์ƒˆ๋กœ์šด ๊ฐ์ฒด์— this๊ฐ€ ๋ฐ”์ธ๋”ฉ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค.
  • this๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ง„์งœ ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ณด๋‹ค ๋œ ์œ ์—ฐํ•ฉ๋‹ˆ๋‹ค.
  • strict ๋ชจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ new๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ๊นŒ๋จน๋Š”๋‹ค๋ฉด, this์— ํ• ๋‹นํ•œ ๋ชจ๋“  ๊ฒƒ๋“ค์ด ์ „์—ญ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ ์ด ์•„์ฃผ ์น˜๋ช…์ ์ด์ฃ .

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์–ด๋– ํ•œ ํ•จ์ˆ˜๋“  ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜

const dog = {
    name: 'Naya',
    sex: 'female',
    age: 2,
    breed: 'Rottweiler mix'
};

**Object.create()**๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜

const person = {
  isHuman: false,
  printIntroduction: function() {
    console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
  }
};

const me = Object.create(person);

me.name = 'Matthew'; // "name" is a property set on "me", but not on "person"
me.isHuman = true; // inherited properties can be overwritten

me.printIntroduction();
// expected output: "My name is Matthew. Am I human? true"

๋™์  ๊ฐ์ฒด ํ™•์žฅ(dynamic object extension) ์„ ์‚ฌ์šฉํ•˜๋ฉด ์šฐ๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ๋“ค์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  const dynamic1 = "Marks";
  const dynamic2 = "Age";
  const user = {
      Name : "GeeksForGeeks",
      [dynamic1] : "57",
      [dynamic2] : "42"
    };

ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ž€?

function createJelly() {
  return {
    type: 'jelly',
    colour: 'red'
    scoops: 3
  };
}

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ž€ new๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๊ณ , ์ „์—ญ ๊ณต๊ฐ„์„ ์˜ค์—ผ์‹œํ‚ฌ ์œ„ํ—˜์„ฑ์ด ์—†๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

ํด๋ž˜์Šค ์ƒ์†

ํด๋ž˜์Šค ์ƒ์†์€ ์ผ๋ฐ˜์ ์œผ๋กœ ํ•˜๋‚˜์˜ ์กฐ์ƒ์œผ๋กœ๋ถ€ํ„ฐ ์ƒ์†๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋‚˜์ค‘์— ๊ณค๋ž€ํ•œ ์ƒํ™ฉ์— ๋†“์—ฌ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ฐœ๋ฐœ์ž๋“ค์€ ๋ณดํ†ต ๋ชจ๋“  OO ๋””์ž์ธ์ด ๊ฒฐ๊ตญ ์ž˜๋ชป๋๋‹ค๋Š” ๊ฑธ ์•Œ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

Elliot์— ์˜ํ•˜๋ฉด ์ž์‹๊ณผ ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๊ธด๋ฐ€ํ•จ์€ ๋ชจ๋“ˆ์‹ ์ฝ”๋“œ์™€ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ์˜ ์ •๋ฐ˜๋Œ€์— ๋†“์ด๊ฒŒ ๋œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์—‡์œผ๋กœ๋ถ€ํ„ฐ ๋ฌด์—‡์„ ์ƒ์†๋ฐ›๋Š”์ง€๋ฅผ ๋‹ค์‹œ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ๋ฒ ์ด์Šค๋กœ ๋‹ค์‹œ ๋Œ์•„๊ฐ€์•ผ ํ•˜์ง€๋งŒ ์™„์ „ํžˆ ๋ฆฌํŒฉํ† ๋งํ•˜๊ธฐ์—๋Š” ๊ฒฐํ•ฉ๋„๊ฐ€ ๋„ˆ๋ฌด ๋†’์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ปค์งˆ ์ˆ˜๋ก, ๋ฌธ์ œ๋Š” ๋”์šฑ ์‹ฌ๊ฐํ•ด์ง€๋ฉฐ ํด๋ž˜์Šค์˜ ํ˜ผ์žกํ•จ์ด ๊ฐ€์ค‘๋˜์–ด ๋ฒ„๊ทธ๊ฐ€ ๋‚˜ํƒ€๋‚˜๋ฉด ํ•œ ๊ตฐ๋ฐ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฒ„๊ทธ์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ๊ณ ์ณ์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์Šค๋Š” ํ•ด๋กญ์Šต๋‹ˆ๋‹ค

๊ฝค๋‚˜ ๋Œ€๋‹ดํ•œ ๋ฌธ์žฅ์ด์ง€๋งŒ Eliiot์€ ์†Œํ”„ํŠธ์›จ์–ด ์žฌ์ž‘์„ฑ๊ณผ ๋ณต์ œ ๋ฌธ์ œ์— ์˜ํ•ด ํฐ ๊ธฐ์—…์—์„œ ๋‚ญ๋น„๋˜๋Š” ์‹œ๊ฐ„์˜ ์–‘์ด ๋” ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
ํฐ ๊ธฐ์—…์˜ ๊ฒฝ์šฐ ์–ด๋Š์ •๋„ ์—ฌ์œ ๋ฅผ ๊ฐ€์ง€๊ณ  ์ˆ˜์ •ํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ์Šคํƒ€ํŠธ์—…์€ ๊ทธ๋Ÿด ์—ฌ์œ ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
ES6์€ ์ƒˆ๋กœ์šด ๋ฌธ์„œ์—์„œ ํด๋ž˜์Šค ํŒจํ„ด์„ ํ™•์žฅํ•จ์œผ๋กœ์จ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ๋” ๋‚˜์˜๊ฒŒ ๋งŒ๋“ค์—ˆ๊ณ , ์ˆ˜๋งŽ์€ ํฌ์ŠคํŒ…๊ณผ ์ฑ…์—์„œ ํด๋ž˜์Šค์˜ ์‚ฌ์šฉ์„ ๊ฐ•์กฐํ•ฉ๋‹ˆ๋‹ค.

๋” ๊นจ๋—ํ•œ ์ฝ”๋“œ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ์—์„œ ์ƒ์„ฑ์ขŒ ํด๋ž˜์Šค ์ƒ์†์„ ์ œ๊ฑฐํ•œ๋‹ค๋ฉด

  • ์ฝ๊ณ  ์“ฐ๊ธฐ๊ฐ€ ๋” ์‰ฌ์›Œ์ง€๋ฉฐ
  • ๋” ์œ ์—ฐํ•ด์ง€๊ณ 
  • ๋” ํ‘œํ˜„์ ์ธ ์ฝ”๋“œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์–ธ์–ด์˜ ํŠน์„ฑ์— ๋Œ€ํ•ด ์—ด๋ฆฐ ๋งˆ์Œ์„ ๊ฐ€์ง€๋Š” ๊ฒƒ์ด ๋Œ€์ค‘์ ์ด์ง€๋งŒ, ๋ฌด์—‡์ด ์˜ณ์€ ๋ฐฉ๋ฒ•์ด๊ณ  ๊ทธ๋ฅธ ๋ฐฉ๋ฒ•์ธ์ง€๋Š” ๋ถ„๋ช…ํžˆ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•˜์„ธ์š”. ~ Eric Elliott

[์ •๋ฆฌ] RFC: React Server Components

2021.12.21 ์›๋ฌธ

์š”์•ฝ

  • ์„œ๋ฒ„์—์„œ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฒˆ๋“ค์‚ฌ์ด์ฆˆ์— ์ „ํ˜€ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค.
    • Server Components ์ฝ”๋“œ๋Š” ํด๋ผ์ด์–ธํŠธ์— ๋‹ค์šด๋กœ๋“œ ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ๊ฐ€ ๊ฐ์†Œํ•˜๋ฉฐ ์ด์— ๋”ฐ๋ผ ์ดˆ๊ธฐ ์‹œ๊ฐ„ ๊ฐ์†Œ์— ์˜ํ–ฅ์„ ์ค€๋‹ค.
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋‚˜ ํŒŒ์ผ์‹œ์Šคํ…œ๊ณผ ๊ฐ™์€ server-side ๋ฐ์ดํ„ฐ ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ธฐ์กด์— ์‚ฌ์šฉํ•˜๋˜ React ์ปดํฌ๋„ŒํŠธ์™€ ๊ฐ™์€ Client Components์™€ ํ†ตํ•ฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
    • Server Components๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„์—์„œ ๋กœ๋“œํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ๋‹จ์— props๋กœ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.
  • renderํ•  Client Components๋ฅผ ๋‹ค์ด๋‚ด๋ฏนํ•˜๊ฒŒ ์„ ํƒํ•จ์œผ๋กœ์จ ํ•„์š”ํ•œ ์ฝ”๋“œ๋งŒ ์ตœ์†Œํ•œ์œผ๋กœ ๋‹ค์šด๋กœ๋“œ๋ฐ›๊ฒŒ๋” ํ•œ๋‹ค.
  • reload๋  ๋•Œ client state๋ฅผ ๋ณด์กดํ•œ๋‹ค.
    • Server Component tree๊ฐ€ refetch๋˜๋”๋ผ๋„ ํด๋ผ์ด์–ธํŠธ์˜ ์ƒํƒœ, ํฌ์ปค์Šค, ์ง„ํ–‰์ค‘์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋ฐฉํ•ดํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • Server Component๋Š” UI ๋ Œ๋”๋ง ๋‹จ์œ„๋ฅผ ํด๋ผ์ด์–ธํŠธ๋กœ ์ ์ง„์ ์œผ๋กœ ์ŠคํŠธ๋ฆฌ๋ฐํ•˜์—ฌ ๋ Œ๋”๋ง๋œ๋‹ค. (Suspense์™€์˜ ๊ฒฐํ•ฉ)
  • ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„์˜ ์ฝ”๋“œ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค.

Motivation

  • ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ œ : React app์€ client ์ค‘์‹ฌ์ด๋ฉฐ ์„œ๋ฒ„๋ฅผ ์ถฉ๋ถ„ํžˆ ํ™œ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ

Zero-Bundle-Size ์ปดํฌ๋„ŒํŠธ

  • ์„œ๋“œํŒŒํ‹ฐ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ํŽธ๋ฆฌํ•˜์ง€๋งŒ ์ฝ”๋“œ ์‚ฌ์ด์ฆˆ๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋ฉฐ ์„ฑ๋Šฅ์— ๋ถ€์ •์ ์ธ ํšจ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค. ๊ทธ๋ ‡๋‹ค๊ณ  ํ•ด์„œ ๊ธฐ๋Šฅ๋“ค์„ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ์‹œ๊ฐ„์ด ๋งŽ์ด ์†Œ์š”๋˜๋ฉฐ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ์—ผ๋ ค๊ฐ€ ์žˆ๋‹ค. tree-shaking๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ๋„ ์žˆ์ง€๋งŒ, ๊ทธ๋Ÿผ์—๋„ ์ถ”๊ฐ€์ ์ธ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌํ•ด์•ผ๋งŒ ํ•œ๋‹ค.
// NoteWithMarkdown.server.js - Server Component === zero bundle size

import marked from 'marked'; // zero bundle size
import sanitizeHtml from 'sanitize-html'; // zero bundle size

function NoteWithMarkdown({text}) {
  const html = sanitizeHtml(marked(text));
  return (/* render */);
}
  • Server Component๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์„œ๋ฒ„์— staticํ•œ ์ปจํ…์ธ ๋ฅผ ๋ Œ๋”๋งํ•˜๊ฒŒ ํ•จ์œผ๋กœ์จ React์˜ ์žฅ์ ์„ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•˜๋ฉด์„œ๋„ ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค.

Full Access to the Backend

  • React app์„ ๋งŒ๋“ค ๋•Œ์˜ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ : ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‚˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜์Œ ์ €์žฅํ•  ์œ„์น˜๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ
  • ๊ฐœ๋ฐœ์ž๋“ค์€ UI๋ฅผ ๊ฐ•ํ™”ํ•˜๊ณ ์ž ์ถ”๊ฐ€์ ์ธ ์—”๋“œํฌ์ธํŠธ๋ฅผ ๋…ธ์ถœํ•ด์•ผ ํ•˜๊ฑฐ๋‚˜ ๋˜๋Š” UI๋ฅผ ์—ผ๋‘์— ๋‘์ง€ ์•Š์€ ์—”๋“œํฌ์ธํŠธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.
  • ํŒŒ์ผ ์‹œ์Šคํ…œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜๋„ ์žˆ๊ณ , ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ๋“ฑ์˜ ๊ธฐํƒ€ ๋ฐฑ์—”๋“œ์— ๋ฐ”๋กœ ์ ‘๊ทผํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์ž์›์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Automatic Code Splitting

  • Code splitting : app์„ ์ž‘์€ ๋ฒˆ๋“ค ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๋‚˜๋ˆ„์–ด ํด๋ผ์ด์–ธํŠธ์— ์ ์€ ์ฝ”๋“œ๋งŒ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ธฐ๋ฒ•
  • ์ผ๋ฐ˜์ ์ธ ์ ‘๊ทผ๋ฒ• : route๋งˆ๋‹ค ๋ฒˆ๋“ค์„ lazyํ•˜๊ฒŒ ๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ๋Ÿฐํƒ€์ž„ ์‹œ ๊ฐ ๊ธฐ์ค€์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์„ lazyํ•˜๊ฒŒ ๋กœ๋“œ
  • ์„ฑ๋Šฅ์„ ํ–ฅ์ƒํ•˜๋Š” ๋ฐ ๋ถ„๋ช… ์ข‹์œผ๋‚˜ ํ•œ๊ณ„์ ์ด ์กด์žฌ
    1. ๊ฐœ๋ฐœ์ž๊ฐ€ ์ผ๋ฐ˜์ ์ธ import ๋ฌธ์„ React.lazy๋กœ ์ˆ˜์ •ํ•ด์•ผ ํ•จ
    2. ์„ ํƒ๋œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋กœ๋”ฉ๋˜๋Š” ์‹œ์ ์„ ์ง€์—ฐ์‹œํ‚ด์œผ๋กœ์จ ์ ์€ ์ฝ”๋“œ๋ฅผ ๋กœ๋“œํ•˜๋Š” ์ด์ ์ด ์ƒ์‡„๋จ
  • Server Component๋Š” ์ด ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜๋Š”๊ฐ€?
    1. ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์˜ ๋ชจ๋“  import๋ฅผ code-split ์ง€์ ์˜ ๊ฐ€๋Šฅ์„ฑ์œผ๋กœ ๊ฐ„์ฃผํ•จ
    2. ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ ํƒํ• ์ง€ ์„œ๋ฒ„์—์„œ ๋” ์ผ์ฐ ๊ฒฐ์ •ํ•˜์—ฌ ๋ Œ๋”๋ง ํ”„๋กœ์„ธ์Šค ์ดˆ๊ธฐ์— ๋‹ค์šด๋กœ๋“œ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•จ

No Waterfalls

  • ๋‚˜์œ ์„ฑ๋Šฅ์€ ๋ฐ์ดํ„ฐ๋ฅผ fetchํ•˜๋Š” ๊ฒƒ์„ ์ˆœ์ฐจ์ ์œผ๋กœ ํ•  ๋•Œ ํ”ํ•˜๊ฒŒ ๋ฐœ์ƒํ•œ๋‹ค.
  • ๋กœ์ง์„ ์„œ๋ฒ„๋กœ ์˜ฎ๊น€์œผ๋กœ์จ request latency๋ฅผ ์ค„์ด๊ณ  ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚จ๋‹ค.

Avoiding the Abstraction Tax

  • "์ •์ ์ธ" ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” UI ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์ถ”์ƒํ™” ์ค‘ ์ผ๋ถ€๋ฅผ ์ปดํŒŒ์ผํ•˜๊ธฐ ์œ„ํ•ด ๋ฏธ๋ฆฌ ์ปดํŒŒ์ผ์„ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ JS๋Š” ๊ฐ€๋Šฅํ•˜์ง€ ์•Š๋‹ค.
  • ์ถ”์ƒํ™” ๋น„์šฉ์„ ์„œ๋ฒ„์— ์˜ฎ๊ฒจ์„œ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค.

Distinct Challenges, Unified Solution

  • ์ˆœ์ˆ˜ํ•œ ์„œ๋ฒ„๋ Œ๋”๋ง, ํด๋ผ์ด์–ธํŠธ ๋ Œ๋”๋ง์€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š๋‹ค.
  • ์„œ๋ฒ„ ๋ Œ๋”๋ง์™€ ํด๋ผ์ด์–ธํŠธ ๋ Œ๋”๋ง์€ ๋ณดํ†ต ๊ธฐ์ˆ  ์„ mixing ํ•ด์•ผ๋งŒ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ๋™์ผํ•œ ์–ธ์–ด, ๋™์ผํ•œ ํ”„๋ ˆ์ž„์›Œํฌ, ์‘์ง‘๋ ฅ ์žˆ๋Š” API ์ง‘ํ•ฉ์„ ์‚ฌ์šฉํ•˜๋ฉฐ ์„œ๋ฒ„, ํด๋ผ์ด์–ธํŠธ ๋ Œ๋”๋ง์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

[๋ฒˆ์—ญ] TypeScript 4.4 ์†Œ๊ฐœ

2021๋…„ 8์›” 26์ผ์— ์ž‘์„ฑ๋œ ์›๋ฌธ <Announcing TypeScript 4.4>์„ ์ฝ๊ณ  ๋ฒˆ์—ญํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

TypeScript 4.4๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ฆด ์ˆ˜ ์žˆ์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค!

TypeScript์— ๋Œ€ํ•ด ์•„์ง ๋“ค์–ด๋ณธ ์ ์ด ์—†์œผ์‹  ๋ถ„๋“ค์„ ์œ„ํ•ด ์„ค๋ช…ํ•˜์ž๋ฉด, TypeScript๋Š” ์ •์  ํƒ€์ž… ์„ ์œ„ํ•ด JavaScript์— ๋ฌธ๋ฒ•์„ ์ถ”๊ฐ€ํ•œ ์–ธ์–ด์ž…๋‹ˆ๋‹ค.
ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ปดํŒŒ์ผ๋Ÿฌ์™€ ๊ฐ™์€ ๋„๊ตฌ๋“ค์€ ํƒ€์ž…์„ ์ง€์šฐ๊ณ  ์–ด๋””์„œ๋“  ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋งŒ์„ ๋‚จ๊น๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ ํƒ€์ž…๋“ค์€ ํƒ€์ž… ์ฒดํฌ ๊ฐ€ ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค! ํƒ€์ž…์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์˜๋„๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๊ณ , ์—ฌ๋Ÿฌ๋ถ„์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ์ฝ”๋“œ๋ฅผ ์ฝ์–ด ์—๋Ÿฌ๋ฅผ ์žก์•„๋‚ผ ์ˆ˜ ์žˆ์ฃ .
ํƒ€์ž…์„ ์ฒดํฌํ•จ์œผ๋กœ์จ, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์˜คํƒ€, ๋กœ์ง ์—๋Ÿฌ ๋“ฑ ๋งŽ์€ ์˜ค๋ฅ˜๋“ค์„ ์žก์•„๋ƒ…๋‹ˆ๋‹ค! ์˜ค๋ฅ˜๋ฅผ ์žก์•„๋‚ด๋Š” ๊ฒƒ์„ ๋„˜์–ด ์ •ํ™•ํ•œ ์ฝ”๋“œ ์™„์„ฑ, ์ •์˜ํ•œ ๊ณณ์œผ๋กœ ์ด๋™, ๋ฆฌ๋„ค์ด๋ฐ๊ณผ ๊ฐ™์€ ์—๋””ํ„ฐ ๊ธฐ๋Šฅ์„ ๋”์šฑ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๊ฑด ์—ฌ๊ธฐ์„œ ์ฝ์–ด๋ณด์„ธ์š”!

TypeScript 4.4๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ Nuget์ด๋‚˜ npm์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

npm install typescript

์ด ๋ฒ„์ „์„ ์ง€์›ํ•˜๋Š” ์—๋””ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์•„๋ž˜๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ 4.4์˜ ์ฃผ์š” ๋ณ€ํ™”๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • Control Flow Analysis of Aliased Conditions and Discriminants
  • Symbol and Template String Pattern Index Signatures
  • Defaulting to the unknown Type in Catch Variables (--useUnknownInCatchVariables)
  • Exact Optional Property Types (--exactOptionalPropertyTypes)
  • Class static Blocks
  • tsc --help Updates and Improvements
  • Performance Improvements
  • Spelling Suggestions for JavaScript
  • Inlay Hints
  • Breaking Changes

alias๋œ ์กฐ๊ฑด์‹๊ณผ ํŒ๋ณ„์‹์˜ ์ œ์–ดํ๋ฆ„ ๋ถ„์„

Control Flow Analysis of Aliased Conditions and Discriminants

[์ •๋ฆฌ] Introducing Zero-Bundle-Size React Server Components

์›๋ฌธ, ๋™์˜์ƒ ๋งํฌ
#25 ๋ฅผ ์ •๋ฆฌํ•˜๋ฉด์„œ ๋ด„

  • UI Dev : Good UX Cheap maintenance Fast performance
  • ์„ธ ๊ฐ€์ง€๋ฅผ ๋‹ค ๋งŒ์กฑํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ค์›€ / Facebook์€ Relay์™€ GraphQL๋กœ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ์žˆ์Œ

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜์กด์ ์ด์ง€ ์•Š์œผ๋ฉด์„œ ๋ฆฌ์•กํŠธ ์ƒํƒœ๊ณ„์—์„œ ๋‹ค์ˆ˜๊ฐ€ ๋งŒ์กฑํ•  ์ˆ˜ ์žˆ๋Š” ํ•ด๊ฒฐ์ฑ…์— ๋Œ€ํ•œ ๊ณ ๋ฏผ

  • React ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„œ๋ฒ„๋กœ ์˜ฎ๊ฒจ์„œ waterfall ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ž
  • ์ปดํฌ๋„ŒํŠธ์™€ ์„œ๋ฒ„ ์‚ฌ์ด์˜ latency์˜ ๊ฐ์†Œ
  • RSC๋Š” SSR๊ณผ ๋‹ค๋ฅด๋‹ค. (complementary)
  • Shared component๋Š” ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ดํŠธ ์–‘์ชฝ์— ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ .client.js .server.js ๊ฐ™์€ ํ™•์žฅ์ž๊ฐ€ ์—†๊ณ  ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค. => ์ฆ‰ RSC๋Š” ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค. (zero)
  • RSC๋Š” React Suspense์™€ ์ž˜ ์ž‘๋™ํ•œ๋‹ค. RSC๋Š” HTML์„ ๋ Œ๋”ํ•˜์ง€ ์•Š๊ณ  ํŠน๋ณ„ํ•œ ํ˜•ํƒœ๋กœ stream down๋œ๋‹ค.
  • ๋ฐ์ดํ„ฐ์— ์ง์ ‘์ ์œผ๋กœ ์ ‘๊ทผํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด๋ณด๊ธฐ ๋•Œ๋ฌธ์— API๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

React Server Components

  • zero effect on bundle size
  • access the BE directly
  • automatic client code splitting
  • use as much or as little as you like
  • server mental model, modern UX

still in research and dev

์•Œ๋“ฏ ๋ง๋“ฏ,,

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ Value์™€ Reference์˜ ์ฐจ์ด

์›๋ฌธ : Explaining Value vs. Reference in Javascript
๋ถ€์ œ : ์–ด๋–ป๊ฒŒ ์ฐจ์ด๊ฐ€ ์žˆ๋Š”์ง€ ์ปดํ“จํ„ฐ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ดํŽด๋ณด์ž.

์ด ์•„ํ‹ฐํด์€ ์ €์˜ ์˜จ๋ผ์ธ ์ฝ”์Šค Step Up Your JS: A Comprehensive Guide to Intermediate JavaScript์—์„œ ์“ฐ์—ฌ์ง„ ๊ธ€์ž…๋‹ˆ๋‹ค. ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•œ ์ฝ”๋“œ ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ์™€ ์˜จ๋ผ์ธ ํ€ด์ฆˆ๋ฅผ ์ด ๊ณณ์—์„œ ์ฆ๊ฒจ๋ณด์„ธ์š”.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” _value_๋กœ ์ „๋‹ฌ๋˜๋Š” 5๊ฐ€์ง€์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค : Boolean, null, undefined, String, ๊ทธ๋ฆฌ๊ณ  Number๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํƒ€์ž…๋“ค์„ ์›์‹œ ํƒ€์ž…์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  _reference_๋กœ ์ „๋‹ฌ๋˜๋Š” 3๊ฐ€์ง€์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์ด ์žˆ์Šต๋‹ˆ๋‹ค : Array, Function, Object์ž…๋‹ˆ๋‹ค. ์ด ํƒ€์ž…๋“ค์€ ๊ธฐ์ˆ ์ ์œผ๋กœ๋Š” ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ํ†ตํ‹€์–ด **๊ฐ์ฒด(Objects)**๋ผ๊ณ  ๋ถ€๋ฅผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์›์‹œ ํƒ€์ž… (Primitives)

์›์‹œ ํƒ€์ž…์ด ๋ณ€์ˆ˜์— ํ• ๋‹น๋˜๋ฉด ๋ณ€์ˆ˜์— ์›์‹œ ๊ฐ’์„ ๊ฐ–๊ฒŒ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

var x = 10;
var y = 'abc';
var z = null;

x๋Š” 10์„ ๊ฐ–์Šต๋‹ˆ๋‹ค. y๋Š” 'abc'๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค. ์ด ๊ฐœ๋…์„ ์ž˜ ์•Œ๊ธฐ ์œ„ํ•ด, ์ด ๋ณ€์ˆ˜๋“ค๊ณผ ๊ฐ’๋“ค์ด ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์–ด๋–ป๊ฒŒ ๋ณด์ด๋Š”์ง€์— ๋Œ€ํ•œ ์ด๋ฏธ์ง€๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

= ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋ณ€์ˆ˜๋“ค์— ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋ฅผ ํ• ๋‹นํ•  ๋•Œ ์ƒˆ๋กœ์šด ๋ณ€์ˆ˜์— ๊ฐ’์„ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ฐ’์— ์˜ํ•ด ๋ณต์‚ฌ๋˜๋Š” ๊ฒƒ์ด์ฃ .

var x = 10;
var y = 'abc';

var a = x;
var b = y;

console.log(x, y, a, b); // -> 10, 'abc', 10, 'abc'

a์™€ x ๋ชจ๋‘ 10์„ ๊ฐ–๊ณ , b์™€ y ๋ชจ๋‘ 'abc'๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค. ๊ฐ’๋“ค์€ ๋ณต์‚ฌ๋œ ๊ฒƒ์ด๋ฏ€๋กœ ๊ฐ ๋ณ€์ˆ˜๋“ค์€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํŠน์ • ๋ณ€์ˆ˜๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค ํ•ด๋„ ๋‹ค๋ฅธ ๋ณ€์ˆ˜์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐ ๋ณ€์ˆ˜๋“ค๋ผ๋ฆฌ๋Š” ์–ด๋– ํ•œ ๊ด€๊ณ„๋„ ๊ฐ–์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

var x = 10;
var y = 'abc';

var a = x;
var b = y;

a = 5;
b = 'def';

console.log(x, y, a, b); // -> 10, 'abc', 5, 'def'

๊ฐ์ฒด (Objects)

ํ˜ผ๋ž€์Šค๋Ÿฌ์šธ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ผ๋‹จ ์ฐธ๊ณ  ์ฝ์–ด๋ณด์„ธ์š”. ์ฝ๊ณ  ๋‚˜๋ฉด ํ›จ์”ฌ ์‰ฌ์›Œ๋ณด์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์›์‹œ ๊ฐ’์ด ์•„๋‹Œ ๊ฐ’์„ ํ• ๋‹น๋ฐ›์€ ๋ณ€์ˆ˜๋“ค์€ ๊ฐ’์œผ๋กœ _์ฐธ์กฐ(reference)_๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ํ•ด๋‹น ์ฐธ์กฐ๋Š” ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๊ฐ์ฒด์˜ ์œ„์น˜๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๋“ค์€ ์‚ฌ์‹ค ์‹ค์ œ๋กœ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์˜ ์ปดํ“จํ„ฐ ๋ฉ”๋ชจ๋ฆฌ์˜ ํŠน์ • ์œ„์น˜์—์„œ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. arr = []๋ผ๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋ฐฐ์—ด์„ ํ•˜๋‚˜ ์ƒ์„ฑํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ณ€์ˆ˜ arr์€ ๋ฐฐ์—ด์˜ ์œ„์น˜, ์ฆ‰ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค.

address๊ฐ€ number๋‚˜ string ์ฒ˜๋Ÿผ ๊ฐ’์œผ๋กœ ์ „๋‹ฌ๋˜๋Š” ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ ํƒ€์ž…์ด๋ผ๊ณ  ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค. address๋Š” ์ฐธ์กฐ๋กœ ์ „๋‹ฌ๋˜๋Š” ๊ฐ’์˜ ๋ฉ”๋ชจ๋ฆฌ ์œ„์น˜๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. ๋”ฐ์˜ดํ‘œ๋กœ ํ‘œ์‹œ๋˜๋Š” ๋ฌธ์ž์—ด์ฒ˜๋Ÿผ address๋Š” <> ๊ธฐํ˜ธ๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

์ฐธ์กฐ ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋ฅผ ํ• ๋‹นํ•˜๊ณ  ์‚ฌ์šฉํ•  ๋•Œ ์•„๋ž˜์ฒ˜๋Ÿผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

1) var arr = [];
2) arr.push(1);

์ฒซ ๋ฒˆ์งธ ์ค„๊ณผ ๋‘ ๋ฒˆ์งธ ์ค„์€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค.

๋ณ€์ˆ˜ arr์— ํฌํ•จ๋œ ๊ฐ’, ์ฆ‰ ์ฃผ์†Œ๋Š” ๊ณ ์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๋Š” ๋ฐฐ์—ด์ด ๋ณ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. arr ์— ๊ฐ’์„ ๋„ฃ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•  ๋•Œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ๋ฉ”๋ชจ๋ฆฌ์— arr์˜ ์œ„์น˜๋กœ ๊ฐ€์„œ ๊ทธ ๊ณณ์— ์ €์žฅ๋œ ์ •๋ณด๋กœ ์ž‘์—…ํ•˜๋Š” ๊ฒ๋‹ˆ๋‹ค.

์ฐธ์กฐ์— ์˜ํ•œ ํ• ๋‹น (Assigning by Reference)

์ฐธ์กฐ ํƒ€์ž…์ธ ๊ฐ์ฒด๊ฐ€ = ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋กœ ๋ณต์‚ฌ๋  ๋•Œ ํ•ด๋‹น ๊ฐ’์˜ ์ฃผ์†Œ๋Š” ์‹ค์ œ๋กœ ๋ณต์‚ฌ๋˜๋Š” ์ฃผ์†Œ ๊ฐ’์ž…๋‹ˆ๋‹ค. ๊ฐ์ฒด๋Š” ๊ฐ’ ๋Œ€์‹ ์— ์ฐธ์กฐ ๊ฐ’์ด ๋ณต์‚ฌ๋ฉ๋‹ˆ๋‹ค.

var reference = [1];
var refCopy = reference;

์œ„ ์ฝ”๋“œ๋Š” ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ฐ ๋ณ€์ˆ˜๋Š” _๋™์ผํ•œ ๋ฐฐ์—ด_์˜ ์ฐธ์กฐ๊ฐ’์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ด ๋ง์€ reference ๋ณ€์ˆ˜๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด refCopy๋„ ๊ฐ™์ด ๋ณ€๊ฒฝ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

reference.push(2);
console.log(reference, refCopy); // -> [1, 2], [1, 2]

๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๋Š” ๋ฐฐ์—ด์— 2๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. reference์™€ refCopy๋Š” ๊ฐ™์€ ๋ฐฐ์—ด์„ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ์กฐ ๊ฐ’์˜ ์žฌํ• ๋‹น (Reassigning a Reference)

์ฐธ์กฐ ๋ณ€์ˆ˜๋ฅผ ์žฌํ• ๋‹นํ•˜๋ฉด ์ด์ „์˜ ์ฐธ์กฐ ๊ฐ’์„ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.

var obj = { first: 'reference' };

๋ฉ”๋ชจ๋ฆฌ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ๋ผ์ธ์ด ์žˆ๋‹ค๊ณ  ํ•ด๋ด…์‹œ๋‹ค.

var obj = { first: 'reference' };
obj = { second: 'ref2' }

obj์— ์ €์žฅ๋œ ์ฃผ์†Œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๊ฐ์ฒด๋Š” ์—ฌ์ „ํžˆ ๋ฉ”๋ชจ๋ฆฌ์— ๋‚จ์•„์žˆ๊ณ  ๋‹ค์Œ ๊ฐ์ฒด๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

์œ„ #234 ๊ฐ’์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด ๋‚จ์•„์žˆ๋Š” ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ’์ด ์—†์„ ๋•Œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰์…˜์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ์ฒด์˜ ๋ชจ๋“  ์ฐธ์กฐ๋ฅผ ์žƒ๊ณ  ๋” ์ด์ƒ ๊ทธ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์—”์ง„์€ ์•ˆ์ „ํ•˜๊ฒŒ ๋ฉ”๋ชจ๋ฆฌ๋กœ๋ถ€ํ„ฐ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์— ๊ฐ์ฒด `{ first: 'reference' }๋Š” ๋” ์ด์ƒ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ณ  ๊ฐ€๋น„์ง€์ฝœ๋ ‰์…˜์˜ ๋Œ€์ƒ์ด ๋ฉ๋‹ˆ๋‹ค.

== ๊ณผ ===

์ผ์น˜ ์—ฐ์‚ฐ์ž ==๊ณผ ===๊ฐ€ ์ฐธ์กฐ ํƒ€์ž…์˜ ๋ณ€์ˆ˜์— ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ ์ฐธ์กฐ ๊ฐ’์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ํ•ญ๋ชฉ์˜ ์ฐธ์กฐ๊ฐ’์„ ๊ฐ–๋Š” ๊ฒฝ์šฐ ๋น„๊ต ๊ฒฐ๊ณผ๋Š” true๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

var arrRef = [โ€™Hi!โ€™];
var arrRef2 = arrRef;

console.log(arrRef === arrRef2); // -> true

๋ณ„๊ฐœ์˜ ๊ฐ์ฒด๋ผ๋ฉด ๋™์ผํ•œ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค ํ•˜๋”๋ผ๋„ ๋น„๊ต ๊ฒฐ๊ณผ๋Š” false๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

var arr1 = ['Hi!'];
var arr2 = ['Hi!'];

console.log(arr1 === arr2); // -> false

๋‘ ๊ฐœ์˜ ๊ฐ์ฒด๊ฐ€ ์žˆ๊ณ  ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ฐ™์€์ง€ ํ™•์ธํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ๋‘ ๊ฐ์ฒด๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฌธ์ž์—ด์„ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ผ์น˜ ์—ฐ์‚ฐ์ž๊ฐ€ ์›์‹œ๊ฐ’์„ ๋น„๊ตํ•  ๋•Œ ๋‹จ์ˆœํžˆ ๊ฐ’์ด ๊ฐ™์œผ์ง€๋งŒ ๋น„๊ตํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

var arr1str = JSON.stringify(arr1);
var arr2str = JSON.stringify(arr2);

console.log(arr1str === arr2str); // true

๋˜ ๋‹ค๋ฅธ ์„ ํƒ์ง€๋Š” ๊ฐ์ฒด๋“ค ๋‚ด ์žฌ๊ท€์ ์ธ ๋ฃจํ”„์—์„œ ๊ฐ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ฐ™์€์ง€ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๋ฅผ ํ†ตํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ „๋‹ฌ

ํ•จ์ˆ˜์— ์›์‹œ ๊ฐ’์„ ์ „๋‹ฌํ•  ๋•Œ ํ•จ์ˆ˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฐ’์„ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” =์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ์‚ฌ์‹ค์ƒ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

var hundred = 100;
var two = 2;

function multiply(x, y) {
    // PAUSE
    return x * y;
}

var twoHundred = multiply(hundred, two);

์œ„์˜ ์˜ˆ์—์„œ hundred์— ๊ฐ’ 100์„ ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. multiply์— ์ด ๊ฐ’์„ ์ „๋‹ฌํ•  ๋•Œ x๋Š” ๊ฐ’ 100์„ ๊ฐ–๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. = ํ• ๋‹น์„ ์‚ฌ์šฉํ•  ๋•Œ์ฒ˜๋Ÿผ ๊ฐ’์ด ๋ณต์‚ฌ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ญ์‹œ๋‚˜ hundred์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. PAUSE ์ฃผ์„์—์„œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์–ด๋–ค ์ƒํƒœ์ธ์ง€์— ๋Œ€ํ•œ ์Šค๋ƒ…์ƒท์„ ๋ณด์—ฌ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

์ˆœ์ˆ˜ ํ•จ์ˆ˜

์™ธ๋ถ€ ์Šค์ฝ”ํ”„์— ์˜ํ–ฅ์„ ๋ผ์น˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜๋ฅผ _์ˆœ์ˆ˜ํ•จ์ˆ˜_๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์›์‹œ๊ฐ’๋งŒ ๋ฐ›๊ณ  ํ•จ์ˆ˜๋ฅผ ๋‘˜๋Ÿฌ์‹ผ ์™ธ๋ถ€ ์Šค์ฝ”ํ”„์— ์žˆ๋Š” ์–ด๋– ํ•œ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ•ด๋‹น ํ•จ์ˆ˜๋Š” ์ž๋™์ ์œผ๋กœ ์™ธ๋ถ€ ์Šค์ฝ”ํ”„์— ์˜ํ–ฅ์„ ๋ผ์น˜์ง€ ์•Š๋Š” ์ˆœ์ˆ˜ํ•จ์ˆ˜๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๋‚ด๋ถ€์—์„œ ์ƒ์„ฑ๋˜๋Š” ๋ชจ๋“  ๋ณ€์ˆ˜๋“ค์€ ํ•จ์ˆ˜๊ฐ€ ๋ฆฌํ„ด๋  ๋•Œ ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰ํ„ฐ์— ์˜ํ•ด ์ˆ˜์ง‘๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ํ•จ์ˆ˜๊ฐ€ ๊ฐ์ฒด๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š”๋‹ค๋ฉด ํ•จ์ˆ˜๋ฅผ ๋‘˜๋Ÿฌ์‹ผ ์Šค์ฝ”ํ”„๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐฐ์—ด์˜ ์ฐธ์กฐ๊ฐ’์„ ๋ฐ›์•„ ํ•ด๋‹น ๋ฐฐ์—ด์„ ๋ณ€๊ฒฝ์‹œํ‚จ๋‹ค๋ฉด ํ•จ์ˆ˜๋ฅผ ๋‘˜๋Ÿฌ์‹ผ ์Šค์ฝ”ํ”„์— ์žˆ๋Š” ๋ณ€์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ๋ฆฌํ„ดํ•˜๊ณ  ๋‚˜์„œ๋„ ๊ทธ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์™ธ๋ถ€ ์Šค์ฝ”ํ”„์— ์œ ํšจํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ถ”์ ํ•˜๊ธฐ ์–ด๋ ต๊ณ  ์›์น˜ ์•Š์€ ์‚ฌ์ด๋“œ์ดํŽ™ํŠธ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ Array.map๊ณผ Array.filter๋ฅผ ํฌํ•จํ•œ ๋งŽ์€ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฐฐ์—ด ํ•จ์ˆ˜๋“ค์€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋กœ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ๋ฐ›์•„ ๊ฐ์ฒด์˜ ์›๋ณธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์›๋ณธ์€ ๊ทธ๋Œ€๋กœ ๋‘์–ด ์™ธ๋ถ€ ์Šค์ฝ”ํ”„์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“ค์–ด์ง„ ๋ฐฐ์—ด์˜ ์ฐธ์กฐ๋ฅผ ๋ฆฌํ„ด๋ฐ›์Šต๋‹ˆ๋‹ค.

์ˆœ์ˆ˜ํ•จ์ˆ˜์™€ ๋น„์ˆœ์ˆ˜ํ•จ์ˆ˜์˜ ์˜ˆ๋ฅผ ๋ด…์‹œ๋‹ค.

function changeAgeImpure(person) {
    person.age = 25;
    return person;
}

var alex = {
    name: 'Alex',
    age: 30
};

var changedAlex = changeAgeImpure(alex);

console.log(alex); // -> { name: 'Alex', age: 25 }
console.log(changedAlex); // -> { name: 'Alex', age: 25 }

์ด ๋น„์ˆœ์ˆ˜ ํ•จ์ˆ˜๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„ age์˜ ๊ฐ’์„ 25๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ์ „๋‹ฌ๋ฐ›์€ ์ฐธ์กฐ๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— alex๊ฐ์ฒด๋ฅผ ์ง์ ‘์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.person๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•  ๋•Œ๋Š” ์ „๋‹ฌ๋ฐ›์€ ๊ฐ์ฒด์™€ ์ •ํ™•ํžˆ ๋™์ผํ•œ ๊ฐ์ฒด๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.alex์™€ alexChanged๋Š” ๋™์ผํ•œ ์ฐธ์กฐ๊ฐ’์„ ๊ฐ–๊ณ  ์žˆ์ฃ . person` ๋ณ€์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์— ์ฐธ์กฐ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ๊ฒƒ์€ ์ค‘๋ณต๋˜๋Š” ์ผ์ž…๋‹ˆ๋‹ค.

์ˆœ์ˆ˜ ํ•จ์ˆ˜์˜ ์˜ˆ๋ฅผ ๋ด…์‹œ๋‹ค.

function changeAgePure(person) {
    var newPersonObj = JSON.parse(JSON.stringify(person));
    newPersonObj.age = 25;
    return newPersonObj;
}

var alex = {
    name: 'Alex',
    age: 30
};

var alexChanged = changeAgePure(alex);

console.log(alex); // -> { name: 'Alex', age: 30 }
console.log(alexChanged); // -> { name: 'Alex', age: 25 }

์ด ํ•จ์ˆ˜์—์„œ๋Š” ์ „๋‹ฌ๋ฐ›์€ ๊ฐ์ฒด๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด JSON.stringify๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ๋ฌธ์ž์—ด์„ JSON.parse๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด๋กœ ํŒŒ์‹ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ณ€ํ™˜ ๊ณผ์ •์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๋™์ผํ•œ ๋™์ž‘์„ ํ•˜๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ์›๋ณธ ๊ฐ์ฒด๋ฅผ ํ†ตํ•œ ๋ฐ˜๋ณต๋ฌธ ๋‚ด์—์„œ ๊ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ƒˆ๋กœ์šด ๊ฐ์ฒด์— ๋™์ผํ•˜๊ฒŒ ํ• ๋‹นํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๋Š” ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋‚ด์—์„œ๋Š” ์ „๋‹ฌ๋ฐ›์€ ๊ฐ์ฒด์™€๋Š” ์™„์ „ํžˆ ๋ณ„๊ฐœ์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ๊ฐ์ฒด์˜ age ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณ€๊ฒฝ์‹œ์ผœ๋„ ์›๋ณธ ๊ฐ์ฒด๋Š” ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๊ฐ€ ์ˆœ์ˆ˜ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ๋‚ด๋ถ€ ์Šค์ฝ”ํ”„ ๋ฐ–์— ์žˆ๋Š” ์–ด๋– ํ•œ ๊ฐ์ฒด์—๋„ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ์‹ฌ์ง€์–ด ์ „๋‹ฌ๋ฐ›์€ ๊ฐ์ฒด์—๋„ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋˜๊ณ  ์ƒˆ๋กœ์šด ๋ณ€์ˆ˜์— ์ €์žฅ๋  ์ˆ˜๋„ ์žˆ๊ณ  ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋์„ ๋•Œ ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๋” ์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰ํ„ฐ๊ฐ€ ์ˆ˜์ง‘ํ•ฉ๋‹ˆ๋‹ค.

์ง์ ‘ ์‹คํ—˜ํ•ด๋ณด์„ธ์š”

Value vs. reference๋น„๊ต๋Š” ์ฝ”๋”ฉ ์ธํ„ฐ๋ทฐ์—์„œ ์ข…์ข… ๋ฌผ์–ด๋ณด๋Š” ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์–ด๋–ป๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ธ์ง€ ์ง์ ‘ ์•Œ์•„๋‚ด๋ณด์„ธ์š”.

function changeAgeAndReference(person) {
    person.age = 25;
    person = {
        name: 'John',
        age: 50
    };
    
    return person;
}

var personObj1 = {
    name: 'Alex',
    age: 30
};

var personObj2 = changeAgeAndReference(personObj1);
console.log(personObj1); // -> ?
console.log(personObj2); // -> ?

์ฒ˜์Œ์— ํ•จ์ˆ˜๋Š” ์ „๋‹ฌ๋ฐ›์€ ์›๋ณธ ๊ฐ์ฒด์˜ age ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋ณ€์ˆ˜์— ์žฌํ• ๋‹นํ•˜๊ณ  ๊ทธ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ฃ . ์ฝ˜์†” ์ฐฝ์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

console.log(personObj1); // -> { name: 'Alex', age: 25 }
console.log(personObj2); // -> { name: 'John', age: 50 }

ํ•จ์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์€ =๋กœ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ๊ณผ ์™„์ „ํžˆ ๋˜‘๊ฐ™๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์„ธ์š”. person ๋ณ€์ˆ˜๋Š” personObj1 ๊ฐ์ฒด์˜ ์ฐธ์กฐ๊ฐ’์„ ๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ฒ˜์Œ์—๋Š” ๊ทธ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์กฐ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋กœ ์žฌํ• ๋‹น๋˜๊ณ  ๋‚˜์„œ๋Š” ์›๋ณธ ๊ฐ์ฒด์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์žฌํ• ๋‹น์€ ์™ธ๋ถ€ ์Šค์ฝ”ํ”„์˜ personObj1 ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐ์ฒด๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. person์€ ์ƒˆ๋กœ์šด ์ฐธ์กฐ ๊ฐ’์„ ๊ฐ€์ง€์ง€๋งŒ ์žฌํ• ๋‹น์ด personObj1์„ ๋ณ€๊ฒฝ์‹œํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์œ„์˜ ์ฝ”๋“œ๋Š” ์•„๋ž˜ ์ฝ”๋“œ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

var personObj1 = {
    name: 'Alex',
    age: 30
};

var person = personObj1;
person.age = 25;

person = {
  name: 'john',
  age: 50
};

var personObj2 = person;

console.log(personObj1); // -> { name: 'Alex', age: 25 }
console.log(personObj2); // -> { name: 'John', age: '50' }

๋‘ ์ฝ”๋“œ์˜ ์ฐจ์ด๋Š” ํ•จ์ˆ˜์˜ ์‚ฌ์šฉ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด person์€ ๋” ์ด์ƒ ์Šค์ฝ”ํ”„์— ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋์ž…๋‹ˆ๋‹ค. ์ด์ œ ์ฝ”๋“œ๋ฅผ ์งœ์„ธ์š”.

์ด ๊ธ€์ด ์œ ์šฉํ•˜์…จ๋‹ค๋ฉด ํ•˜ํŠธ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ฃผ์‹œ๊ณ  ์ €์˜ ๋‹ค๋ฅธ ๊ธ€๋“ค๋„ ๋ด์ฃผ์„ธ์š”.

[์ •๋ฆฌ] ์ผ๊ธ‰ ๊ฐ์ฒด (first-class object)

Basically, first-class citizenship simply means โ€œbeing able to do what everyone else can do.โ€

์ผ๊ธ‰ ๊ฐ์ฒด์˜ ์กฐ๊ฑด

  1. ๋ณ€์ˆ˜๋‚˜ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์•ˆ์— ๋‹ด์„ ์ˆ˜ ์žˆ๋‹ค.
  2. ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ผ๊ธ‰ ๊ฐ์ฒด์ธ ํ•จ์ˆ˜๋ฅผ ์ผ๊ธ‰ ํ•จ์ˆ˜๋ผ๊ณ  ํ•œ๋‹ค. (first class function)

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ์˜ ์ผ๊ธ‰ ๊ฐ์ฒด

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ํ•จ์ˆ˜๋Š” ๊ฐ์ฒด์ด๋ฉฐ Object ํ”„๋กœํ† ํƒ€์ž…์„ ์ƒ์†๋ฐ›๋Š”๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ํ•จ์ˆ˜๋Š” ์ผ๊ธ‰ ๊ฐ์ฒด์ด๋ฉฐ ์ผ๊ธ‰ ํ•จ์ˆ˜์ด๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ํ•จ์ˆ˜๋„ ๊ฐ์ฒด์ด๋ฏ€๋กœ ๋ณดํ†ต ์ผ๊ธ‰ ๊ฐ์ฒด๋ผ๊ณ  ํ•˜๋Š” ๋“ฏ ํ•˜๋‹ค.

์กฐ๊ฑด์„ ์–ด๋–ป๊ฒŒ ๋งŒ์กฑํ•˜๋Š”๊ฐ€?

  1. var const let ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ€์ˆ˜์— ํ•จ์ˆ˜๋ฅผ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค.
  2. ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. ํ•จ์ˆ˜์—์„œ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ํ•จ์ˆ˜๊ฐ€ ์ผ๊ธ‰ ๊ฐ์ฒด์ธ ๊ฒƒ์ด ์ค‘์š”ํ•œ ์ด์œ 

  • ํ•จ์ˆ˜๋Š” ์ž๊ธฐ ์ž์‹ ์—๊ฒŒ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์‹ฌ์ง€์–ด ์ž์‹ ์œผ๋กœ๋ถ€ํ„ฐ ๋ฐ˜ํ™˜๋  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•จ์ˆ˜๊ฐ€ ์ผ๊ธ‰ ๊ฐ์ฒด๋ผ๋Š” ๊ฒƒ์€ flexibility๋ฅผ ์˜๋ฏธํ•˜๋Š”๋ฐ ์ฆ‰, ๋ชจ๋“  ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํŒจ๋Ÿฌ๋‹ค์ž„์— ์—ด๋ ค ์žˆ๋‹ค๋Š” ๊ฒƒ.
    • ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์ผ๊ธ‰ ๊ฐ์ฒด ํ•จ์ˆ˜๊ฐ€ ํ—ˆ์šฉํ•˜๋Š” ํŒจ๋Ÿฌ๋‹ค์ž„ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.
  • ๊ณ ์ฐจ ํ•จ์ˆ˜(high order function๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. (ex. each, filter, map, every ...)
  • ์ด๋ฒคํŠธ์— ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ์‰ฌ์›Œ์ง„๋‹ค.
  • ์ผ๊ธ‰ ๊ฐ์ฒด๊ฐ€ ํด๋กœ์ ธ์™€ ๋งŒ๋‚˜๋ฉด ์‹œ๋„ˆ์ง€ ํšจ๊ณผ๊ฐ€ ๋‚œ๋‹ค. ํ•จ์ˆ˜๋Š” ์ƒ์„ฑ๋  ๋‹น์‹œ์˜ Lexical env๋ฅผ ๊ธฐ์–ตํ•˜๋Š”๋ฐ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ณผ์ •์—์„œ env๋„ ํ•จ๊ป˜ ์ „๋‹ฌ๋œ๋‹ค. ์ด๋ฅผ ์ด์šฉํ•˜์—ฌ currying๊ณผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

'์ปค๋ง'์ด๋ž€ ํ•จ์ˆ˜ ํ•˜๋‚˜๊ฐ€ n๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›๋Š” ๊ณผ์ •์„ n๊ฐœ์˜ ํ•จ์ˆ˜๋กœ ๊ฐ๊ฐ์˜ ์ธ์ž๋ฅผ ๋ฐ›๋„๋ก ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ.
๋ถ€๋ถ„์ ์œผ๋กœ ์ ์šฉ๋œ ํ•จ์ˆ˜๋ฅผ ์ฒด์ธ์œผ๋กœ ๊ณ„์† ์ƒ์„ฑํ•˜์—ฌ ๊ฒฐ๊ณผ์ ์œผ๋กœ ๊ฐ’์„ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•จ.

์ฐธ๊ณ 

[๋ฒˆ์—ญ] Hello Yarn 2, Goodbye node_modules

2021๋…„ 8์›” 5์ผ์— ์ž‘์„ฑ๋œ <์›๋ฌธ : Hello Yarn 2, Goodbye node_modules>์„ ์ฝ๊ณ  ๋ฒˆ์—ญํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค :)

3๋…„์ฏค ์ „, 2017๋…„์— ํŽ˜์ด์Šค๋ถ ์—”์ง€๋‹ˆ์–ด๋ง ๋ธ”๋กœ๊ทธ์— Yarn 1.0์ด ๊ณต์‹์ ์œผ๋กœ ๋ฐœํ‘œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ฒซ ์ถœ์‹œ ์ดํ›„ ์•ฝ 11๊ฐœ์›” ๋งŒ์— 175,000 ์ด์ƒ์˜ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๊ฐ€ ์ƒˆ๋กœ์šด ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €๋กœ Yarn 1.0์„ ์‚ฌ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

Yarn์˜ ์„ฑ๊ณต ์Šคํ† ๋ฆฌ๊ฐ€ ์•„์ง๊นŒ์ง€๋„ ๊ณ„์† ๋˜๊ณ  ์žˆ์ง€๋งŒ, ์ด ๋„๊ตฌ๋Š” ๋Š๋ฆผ, ๋ณต์žก์„ฑ์˜ ์ฆ๊ฐ€, ๋ฐ์ดํ„ฐ ๊ณต๊ฐ„๊ณผ ๊ฐ™์€ ์ „ํ†ต์ ์ธ ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์˜ ์•ฝ์ ์„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Yarn2๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ „๋ฐ˜์ ์ธ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ๊ฐœ์„ ํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ๊ทผ๋ณธ์ ์ธ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

Yarn 2๋Š” ์–ด๋–ค ๊ฒŒ ์ƒˆ๋กœ์šด๊ฐ€์š”?

์ƒˆ๋กœ์šด ๋ฒ„์ „์€ ์ž‘๋…„ 1์›”์— ์ด๋ฏธ ๋ฆด๋ฆฌ์ฆˆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋งŽ์€ ํฐ ํ”„๋กœ์ ํŠธ๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ƒˆ๋กœ์šด Plugโ€™nโ€™Play์— ์ ์‘ํ•˜๋Š” ๋ฐ ๊ฝค ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ผ๋ถ€ ๋Œ€ํ˜• ๋„ค์ž„๋“œ ํ”„๋กœ์ ํŠธ๋Š” ์—ฌ์ „ํžˆ ํ˜ธํ™˜์„ฑ์„ ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅ์ค‘์ธ ์ƒํƒœ์ž…๋‹ˆ๋‹ค(์ž‘์„ฑ ์‹œ์ ์—์„œ๋Š” Angular, RN, Flow ๋“ฑ). ์ด์ œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ ๋ฒ ์ด์Šค์— ์ ์šฉํ•ด ๋ณผ ๊ธฐํšŒ์ž…๋‹ˆ๋‹ค.

Plugโ€™nโ€™Play ์ง€์›์ด Yarn 2์—์„œ ์˜ค๋Š” ๊ฐ€์žฅ ํฐ ๋ณ€ํ™”์ธ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. Yarn์˜ ์—…๋ฐ์ดํŠธ๋Š” ๋” ๋‹จ์ˆœํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋งŽ์€ ์ข‹์€ ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
Yarn์˜ ์œ ์ง€๋ณด์ˆ˜์ž๋“ค์€ ์ด๋Ÿฌํ•œ ๊ฐœ์„ ์— 1๋…„์˜ ์‹œ๊ฐ„์„ ์Ÿ์•„ ๋ถ€์—ˆ๊ณ , Yarn 2๊ฐ€ ์ถฉ๋ถ„ํžˆ ์ž˜ ๋งŒ๋“ค์–ด์กŒ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์‹คํžˆ ๋Š๋‚„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CLI ์ถœ๋ ฅ์—์„œ ๋””๋ฒ„๊ทธ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค

์ด์ œ ๋” ๊ตฌ์กฐํ™”๋œ CLI ์ถœ๋ ฅ์œผ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. Yarn ์ฝ˜์†” ํ…์ŠคํŠธ๋Š” ๊ธฐ๊ปํ•ด์•ผ ์‹œ๊ฐ์ ์ธ ํ™ฉ๋ฌด์ง€ ์ •๋„์˜€์ง€๋งŒ, ํฌ๋งทํŒ…์ด๋‚˜ ์ƒ‰์ƒ ๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๊ฐ€๋…์„ฑ์ด ๋”์šฑ ํ–ฅ์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์œ„ ์‚ฌ์ง„์—์„œ ๊ฐ ์ค„์— ์—๋Ÿฌ ์ฝ”๋“œ๊ฐ€ ์žˆ์–ด ๋””๋ฒ„๊ทธํ•˜๊ธฐ๊ฐ€ ํ›จ์”ฌ ์‰ฌ์›Œ์กŒ์Šต๋‹ˆ๋‹ค. ์—๋Ÿฌ์ฝ”๋“œ๋Š” ์ด ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

node_modules ๋ฟ๋งŒ์ด ์•„๋‹™๋‹ˆ๋‹ค

๋ฌผ๋ก  Yarn 2๋ฅผ ์ด์ „ ๋ฒ„์ „์˜ ๊ฐ€์น˜๋ฅผ ํ•˜๋ฝ์‹œํ‚ด์œผ๋กœ์จ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ, Yarn์€ ๊ฐ”์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์€ ํฐ ์ด์ •ํ‘œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ฒ„์ „์€ ํŒŒ์ผ์˜ I/O ์–‘์„ ์—„์ฒญ๋‚˜๊ฒŒ ๊ฐ์†Œ์‹œํ‚ด์œผ๋กœ์จ ์„ค์น˜ํ•˜๋Š” ๋™์•ˆ ์—„์ฒญ๋‚œ ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ•ด์ค๋‹ˆ๋‹ค.

Yarn์€ ์ด์ œ pnp.js ํŒŒ์ผ ํ•˜๋‚˜์— ํŒจํ‚ค์ง€ ์ฐธ์กฐ๋ฅผ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋Š” ์ง€๋„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ์—ฌ๋Ÿฌ๋ถ„์ด ์ฝ”๋“œ๋ฅผ ํ•œ๋ฒˆ ์‹คํ–‰ํ•˜๋ฉด ๋…ธ๋“œ๊ฐ€ ์ ์ ˆํ•œ ์œ„์น˜๋กœ ๊ฐ€๊ฒŒ๋” ํ•ด์ค๋‹ˆ๋‹ค.

์—ฌ์ „ํžˆ ๋‹ค์šด๋กœ๋“œ๋œ ํŒจํ‚ค์ง€๋Š” ์—ฌ๋Ÿฌ๋ถ„์˜ ๋””์Šคํฌ _์–ด๋”˜๊ฐ€_์— ๊ฐ€์•ผํ•˜๋Š”๋ฐ์š”. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ์ƒˆ .yarn ํด๋”์˜ ์šฉ๋„์ž…๋‹ˆ๋‹ค.
๊ทธ ์œ„์น˜๋Š” ์˜์กด์„ฑ์ด ์บ์‹ฑ๋˜๋Š” ์œ„์น˜๋กœ ๋” ์ ์€ ์„ค์น˜ ๊ณต๊ฐ„์„ ์ฐจ์ง€ํ•ฉ๋‹ˆ๋‹ค. (์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์—์„œ ์‹คํ—˜ํ•ด๋ณด๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.)

Yarn dlx

์„ค์น˜๋˜์ง€ ์•Š์€ ์›๊ฒฉ ํŒจํ‚ค์ง€๋ฅผ ์ง์ ‘ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด npm์˜ npx๋ฅผ ์‚ฌ์šฉํ–ˆ์–ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋“œ๋””์–ด Yarn์ด ๊ทธ ์ผ์„ ์ง์ ‘ ํ•˜๊ฒŒ ๋์Šต๋‹ˆ๋‹ค.
Yarn 2๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด yarn dlx ์ปค๋งจ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ์„ค์น˜ํ•˜์ง€ ์•Š๊ณ  ์ผ์‹œ์ ์ธ ํ™˜๊ฒฝ์—์„œ ํŒจํ‚ค์ง€๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Patch ํ”„๋กœํ† ์ฝœ

์˜์กด์„ฑ์„ ๋กœ์ปฌ๋กœ ํŒจ์นญํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ์‰ฌ์›Œ์กŒ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์€ Yarn์ด ์ผ์‹œ์ ์ธ ํด๋”์— ํŒจํ‚ค์ง€๋ฅผ ์ถ”์ถœํ•˜์—ฌ diff๋ฅผ ๊ฐ–๋Š” ํŒŒ์ผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

yarn patch node-fetch
yarn patch-commit /private/var/patchfolder > mypatch.patch

ํŒจ์น˜ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฏ€๋กœ ํ”„๋กœ์ ํŠธ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ๊ณต๊ฐ„์ด ๋ณ„๋กœ ์—†์Šต๋‹ˆ๋‹ค. ์ดํ›„ ํŒจ์น˜ ํŒŒ์ผ๋งŒ ์ฐธ์กฐํ•  ์ˆ˜๋„ ์žˆ์ฃ .

{
  "dependencies": {
    "node-fetch": "patch:[email protected]#./mypatch.patch"
  }
}

์ด๋Š” ์‹ฌ์ง€์–ด ๊ฐ„์ ‘์ ์ธ ์˜์กด์„ฑ์—๋„ ํšจ๊ณผ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ๊ณต์‹ ๋ฆด๋ฆฌ์ฆˆ ์ˆ˜์ •๋ณธ์ด ๋ฐœํ‘œ๋  ๋•Œ๊นŒ์ง€ ๋ณด์•ˆ ๋ฌธ์ œ๋ฅผ ํŒจ์น˜ํ•˜๋Š” ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.
์ด์— ๋Œ€ํ•œ ๋” ๋งŽ์€ ๋‚ด์šฉ์€ GitHub์˜ plugin-patch ๋ฌธ์„œ์™€ patch ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”

Workflow ๋ฆด๋ฆฌ์ฆˆ

์—ฌ๋Ÿฌ๋ถ„์ด (๋ชจ๋…ธ๋ ˆํฌ์ฒ˜๋Ÿผ) ์—ฌ๋Ÿฌ ์›Œํฌ์ŠคํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ ํŠธ๋ฆฌ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ‚ค์ง€๋“ค์„ ๋ฆด๋ฆฌ์ฆˆํ•˜๊ณ  ์ˆœ์ฐจ์ ์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๋Š” ๊ฒƒ์€ ์ง€๋ฃจํ•œ ์ผ์ž…๋‹ˆ๋‹ค.
์ด์ƒ์ ์œผ๋กœ ์—ฌ๋Ÿฌ๋ถ„์€ ์›Œํฌ์ŠคํŽ˜์ด์Šค์˜ ์ƒˆ๋กœ์šด ๋ฒ„์ „์„ ๋ฆด๋ฆฌ์ฆˆํ•˜๊ณ  ์ƒˆ ๋ฆด๋ฆฌ์ฆˆ์™€ ํ•จ๊ป˜ ๋ชจ๋“  ์˜์กด์„ฑ์ด ์ž๋™์ ์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ด๋Š” ์ •ํ™•ํžˆ Version plugin์ด ํ•˜๋Š” ์ผ์ž…๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ฆด๋ฆฌ์ฆˆ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ํ•ด์ œํ•˜์—ฌ ์—…๊ทธ๋ ˆ์ด๋“œ์˜ ๋Œ€์ƒ๊ณผ ์œ„์น˜๋ฅผ ํŒŒ์•…ํ•ด์•ผ ํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์„ ์—†์•ฑ๋‹ˆ๋‹ค.

๊ธฐ๋‹ค๋ฆฌ์ง€ ๋ง๊ณ  ์ง€๊ธˆ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์‹œ์ž‘ํ•˜์„ธ์š”

์—ฌ๋Ÿฌ๋ถ„์˜ ํŒจํ‚ค์ง€์˜ ๋ณต์žก์„ฑ์— ๋”ฐ๋ผ ์ƒˆ๋กœ์šด Yarn ๋ฒ„์ „์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•˜๋Š” ๊ฒƒ์€ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์ง€๋งŒ ์ถฉ๋ถ„ํžˆ ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š” ์ž‘์—…์ž…๋‹ˆ๋‹ค.
๋” ์ข‹์€ ์ด์œ ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์ด ๋ฆฌ์ŠคํŠธ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.
์ด๋ฏธ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์— ํ™•์‹ ์„ ๊ฐ€์กŒ๋‹ค๋ฉด ๊ฐ€์ด๋“œ๋ฅผ ์‚ดํŽด๋ณด์„ธ์š”.
์ด ์—…๋ฐ์ดํŠธ๋Š” ์—ฌ๋Ÿฌ๋ถ„๊ณผ ์—ฌ๋Ÿฌ๋ถ„์˜ ํŒ€, ๊ทธ๋ฆฌ๊ณ  ์—ฌ๋Ÿฌ๋ถ„์˜ ํ•˜๋“œ ๋“œ๋ผ์ด๋ธŒ๊นŒ์ง€ ๋ชจ๋‘๋ฅผ ์œ„ํ•œ ๊ธธ์ž…๋‹ˆ๋‹ค.

[์ •๋ฆฌ] FEConf 2021 : A track

์ปดํฌ๋„ŒํŠธ, ๋‹ค์‹œ ์ƒ๊ฐํ•˜๊ธฐ

์˜์ƒ ๋งํฌ, ์›์ง€ํ˜๋‹˜

  • React Component์˜ ์˜์กด์„ฑ์„ ๊ธฐ๋Šฅ์ ์œผ๋กœ ๋ถ„๋ฅ˜ํ•˜๋ฉด props, hooks๊ฐ€ ์žˆ๋‹ค.
  • ํŠน์ง•์ (feature)์œผ๋กœ ๋ถ„๋ฅ˜ํ•˜๋ฉด style, logic, global state, remote data schema (API ์„œ๋ฒ„์—์„œ ๋‚ด๋ ค์ฃผ๋Š” ๋ฐ์ดํ„ฐ ๋ชจ์–‘)
  • ์ƒˆ๋กœ์šด ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ๊ทธ ์ •๋ณด ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ•„์—ฐ์ ์œผ๋กœ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ˆ˜์ •ํ•˜๊ฒŒ ๋œ๋‹ค ์ˆจ์€ ์˜์กด์„ฑ

์ปดํฌ๋„ŒํŠธ ๋ฆฌํŒฉํ† ๋ง

  • ๋น„์Šทํ•œ ๊ด€์‹ฌ์‚ฌ๋ผ๋ฉด ๊ฐ€๊นŒ์šด ๊ณณ์— Keep Locality
    • ๋ณดํ†ต ๋กœ์ง์ด๋‚˜ ์Šคํƒ€์ผ์„ ๊ฐ™์€ ์œ„์น˜์— ๋‘๊ฒŒ ๋จ
    • ์œ„์—์„œ๋Š” ์•„์ด๋””๋งŒ ๋ฐ›๊ณ , ๋ชจ์–‘(์Šคํ‚ค๋งˆ)๋Š” ์ „์—ญ ์ƒํƒœ์—์„œ ๋ฐ›์Œ์œผ๋กœ์จ ์˜์กด์„ฑ์„ ๋Š์ž
  • ๋ฐ์ดํ„ฐ๋ฅผ ID ๊ธฐ๋ฐ˜์œผ๋กœ ์ •๋ฆฌํ•˜๊ธฐ Abstraction by Normalization
    • ๋ฐ์ดํ„ฐ ์ •๊ทœํ™”๋ฅผ ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ normalizr ์ฐธ๊ณ 
  • ์˜์กดํ•œ๋‹ค๋ฉด ๊ทธ๋Œ€๋กœ ๋“œ๋Ÿฌ๋‚ด๊ธฐ Make Explicit
    • props ๋„ค์ด๋ฐ์„ ์ง€์„ ๋•Œ๋Š” ์˜์กด์„ฑ์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋“œ๋Ÿฌ๋‚ด๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  • ๋ชจ๋ธ ๊ธฐ์ค€์œผ๋กœ ์ปดํฌ๋„ŒํŠธ ๋ถ„๋ฆฌํ•˜๊ธฐ Separating Components by Model
    • ํ•จ๊ป˜ ๋ณ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ๋“ค๊ณผ ๋”ฐ๋กœ ๋ณ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ๋“ค?
    • ์œ ์ €๋“ค์ด ์ƒ๊ฐํ•˜๋Š” ์ผ๊ด€์„ฑ์€ ๋ชจ๋ธ์ด ์ค‘์‹ฌ -> ๊ฐ™์€ ๋ชจ๋ธ์„ ์˜์กดํ•œ๋‹ค๋ฉด ์žฌ์‚ฌ์šฉ, ๋‹ค๋ฅธ ๋ชจ๋ธ์„ ์˜์กดํ•œ๋‹ค๋ฉด ๋ถ„๋ฆฌ

Global ID

  • ์•„์ด๋””๋งŒ ๊ฐ€์ง€๊ณ  ํŠน์ • ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ผํ•˜๊ฒŒ ์‹๋ณ„ํ•˜๋Š” ID ์ฒด๊ณ„
  • ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ ๋ชจ๋ธ ์ •๋ณด๋งˆ์ € ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ co-locate ํ•  ์ˆ˜ ์žˆ์Œ
  • GOI(Global Object Identification) : ์–ด๋– ํ•œ ์ฝ”๋“œ ์œ„์น˜, ๋งฅ๋ฝ์— ์žˆ๋“  global ID๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํŠน์ • ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” API
  • data flow : ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์ •๊ทœํ™”, ๋‚ด ์ปดํฌ๋„ŒํŠธ์—์„œ Global ID๋กœ ์ €์žฅ์†Œ์—์„œ ํŠน์ • ๋ฐ์ดํ„ฐ ์š”์ฒญ, ๋งŒ์•ฝ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” API ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ ์š”์ฒญํ•˜๊ณ  ์ €์žฅ ํ›„ ๋‚ด ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌ
  • Refetch๋ฅผ ํ•  ๋•Œ๋„ ์œ ์šฉ

์™œ ๋‚˜๋Š” React๋ฅผ ์‚ฌ๋ž‘ํ•˜๋Š”๊ฐ€

์˜์ƒ ๋งํฌ, ์•ˆํฌ์ข…๋‹˜

  • Reconciler : ๋ Œ๋”๋Ÿฌ์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ๊ณต์œ ๋˜๋ฉฐ ์šฐ๋ฆฌ๊ฐ€ ๋ฆฌ์•กํŠธ์˜ ๋ฌธ๋ฒ•์ด๋ผ๊ณ  ์ƒ๊ฐ๋˜์–ด์ง€๋Š” ๋ถ€๋ถ„ (components, props, state ๋“ฑ...)
    • React ์ฝ”๋“œ๋ฅผ ํ•ด์„ํ•˜๋Š” ์—”์ง„์˜ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•จ
  • React UI Tree๊ฐ€ ๊ทธ๋ ค์ง€๋Š” ํ™˜๊ฒฝ์€ ํ˜ธ์ŠคํŠธ ํ™˜๊ฒฝ๊ณผ ์ƒํ˜ธ์ž‘์šฉ -> ์–ด์…ˆ๋ธ”๋ฆฌ
ํ˜ธ์ŠคํŒ… ํ™˜๊ฒฝ ํŒจํ‚ค์ง€
HTML react-dom
iOS, Android ... react-native
terminal ink
Three.js react-three-fiber
JSON react-test-render
  • React์˜ ์ฝ”์–ด ๋กœ์ง์ด ์›น ํ™˜๊ฒฝ๊ณผ ์ง์ ‘์ ์œผ๋กœ ๋ถ™์ง€ ์•Š๋Š” ๊ฒƒ์ด React์˜ ์˜๋„์  ๊ฒฐ์ •
  • ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์˜ ๋™์  ์Šค์ฝ”ํ•‘ -> Context API
  • Fiber Reconciler ๋ฐฉ์‹ -> ์šด์˜์ฒด์ œ ์Šค์ผ€์ฅด๋ง
  • ๋Œ€์ˆ˜์  ํšจ๊ณผ -> Hooks, Suspense
  • ๋„์ „์ ์ธ ๊ณผ์ œ์— ๋Œ€ํ•œ ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์€ ๋‹ต์•ˆ์ง€๋ฅผ ํ›”์ณ๋ด„์œผ๋กœ์จ ์–ป์„ ์ˆ˜๋„ ์žˆ๋‹ค.

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์„ฑ๋Šฅ์˜ ๋น„๋ฐ€ : V8 ์—”์ง„ & ํžˆ๋“  ํด๋ž˜์Šค

๋ถ€์ œ : ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ C++ ์„ฑ๋Šฅ์„ ๋‹ฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•
์›๋ฌธ : Secret Behind JavaScript Performance: V8 & Hidden Classes

์˜ค๋Š˜๋‚  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์›น ๊ฐœ๋ฐœ์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ์–ธ์–ด๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ๋‹จ๊ณ„๊นŒ์ง€ ์˜ฌ๋ผ๊ฐ€๊ธฐ ์œ„ํ•ด ๋งŽ์€ ์žฅ์• ๋ฌผ์„ ํ†ต๊ณผํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ค‘ ํ•˜๋‚˜๋Š” ์‹คํ–‰ ์†๋„์— ๊ด€ํ•œ ๊ฒƒ์ธ๋ฐ, C++๊ณผ ๊ฐ™์€ ์–ธ์–ด์™€ ๋น„์Šทํ•œ ์„ฑ๋Šฅ์„ ๋‹ฌ์„ฑํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์„ฑ์ทจ๋Š” V8 ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„ ์—†์ด๋Š” ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ด ์•„ํ‹ฐํด์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์„ฑ๋Šฅ์„ ์–ป์„ ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ธฐ์ˆ ๊ณผ ๋” ๋‚˜์€ ์„ฑ๋Šฅ์„ ๊ฐ€์ง€๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์•Œ์•„์•ผ ํ•˜๋Š” ๊ฒƒ๋“ค์— ๋Œ€ํ•ด ์–˜๊ธฐํ•ด๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

V8์ด๋ž€ ๋ฌด์—‡์ด๊ณ  ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋‚˜์š”?

V8์€ ๊ตฌ๊ธ€์ด ์ œ์•ˆํ•œ ์˜คํ”ˆ์†Œ์Šค ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ž…๋‹ˆ๋‹ค. C++๋กœ ์ž‘์„ฑ๋˜์—ˆ์œผ๋ฉฐ ๊ตฌ๊ธ€ ํฌ๋กฌ์„ ๋น„๋กฏํ•œ ํฌ๋กœ๋ฏธ์›€ ์›น ๋ธŒ๋ผ์šฐ์ € ๊ทธ๋ฆฌ๊ณ  NodeJS๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๊ณผ ์ƒํ˜ธ ์ž‘์šฉํ•˜๋ฉฐ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ดˆ๊ธฐ์— V8์€ ์›น ๋ธŒ๋ผ์šฐ์ €์˜ ์„ฑ๋Šฅ ํ–ฅ์ƒ ๋ฉ”์ปค๋‹ˆ์ฆ˜์œผ๋กœ์„œ ์†Œ๊ฐœ๋˜์—ˆ๋Š”๋ฐ์š”. ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์—”์ง„๋“ค๋ณด๋‹ค ๋” ํ–ฅ์ƒ๋œ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

V8๊ณผ ๋‹ค๋ฅธ ์—”์ง„๋“ค์˜ ๊ฐ€์žฅ ๋‘๋“œ๋Ÿฌ์ง€๋Š” ์ฐจ์ด์ ์€ JIT(Just-In-Time) ์ปดํŒŒ์ผ๋Ÿฌ๋ผ๋Š” ์ ์ž…๋‹ˆ๋‹ค.

JIT ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๋Ÿฐํƒ€์ž„์— ๋ชจ๋“  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ๋จธ์‹  ์ฝ”๋“œ๋กœ ์ปดํŒŒ์ผํ•˜๋ฉฐ ์ค‘๊ฐ„ ์ฝ”๋“œ๋Š” ์ƒ์„ฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

image

์œ„ ๋‹ค์ด์–ด๊ทธ๋žจ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด, V8 ์—”์ง„์€ 2๊ฐœ์˜ ๋ฉ”์ธ ํŒŒํŠธ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ํŒŒํŠธ๋Š” ์ฝ”๋“œ๋ฅผ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋กœ ํ•ด์„ํ•˜๋Š” ํŒŒ์„œ์˜ ์—ญํ• ์„ ํ•˜๋ฉฐ, V8์˜ ์ตœ์‹  ๋ฒ„์ „์€ ์ด ๊ณผ์ •์—์„œ Ignition์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์„œ์— ์˜ํ•ด **์ถ”์ƒ ๊ตฌ๋ฌธ ํŠธ๋ฆฌ(AST)**๊ฐ€ ์ƒ์„ฑ๋˜๋Š”๋ฐ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋Š” ์ด๋ฅผ ์ž…๋ ฅ๊ฐ’์œผ๋กœ ๋ฐ›์•„ ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ณด๋‹ค ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ›จ์”ฌ ๋น ๋ฆ…๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์™œ V8 ์—”์ง„์€ ์ปดํŒŒ์ผ๋Ÿฌ ๋Œ€์‹ ์— ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฑธ๊นŒ์š”?

Ignition ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ํฐ ์ด์œ ๋Š” ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ค„์ด๊ธฐ ์œ„ํ•ด์„œ ์ž…๋‹ˆ๋‹ค. ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋Š” ์ „์ฒด ํ”„๋กœ๊ทธ๋žจ์„ ์ปดํŒŒ์ผํ•˜๋Š” ์ปดํŒŒ์ผ๋Ÿฌ์™€ ๋‹ค๋ฅด๊ฒŒ ์˜ค์ง ํ•„์š”ํ•œ ๋ผ์ธ๋งŒ ์ปดํŒŒ์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๊ฐ์†Œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Ignition ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๊ฐ€์žฅ ์ดˆ๊ธฐ์— ๋™์ž‘ํ•˜๋Š” ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ๋งŒ ์ž์‹ ์˜ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. Turbofan์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ƒ์„ฑ๋œ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋™์•ˆ ์–ป์€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋ฅผ ์ตœ์ ํ™”ํ•˜๊ณ  ๋” ์ตœ์ ํ™”๋œ ๋ฒ„์ „์œผ๋กœ ๋‹ค์‹œ ์ปดํŒŒ์ผํ•ฉ๋‹ˆ๋‹ค.

Note: V8์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๊ธฐ๋Š” ํ•˜๋‚˜ C++๋กœ ์ž‘์„ฑ๋˜์—ˆ์œผ๋ฉฐ , ํ•œ๋ฒˆ์— ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ž‘์—…๋“ค์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

V8์˜ ๋™์ž‘ ๋ฐฉ์‹์„ ์„ค๋ช…ํ•  ๋•Œ Ignition ์ธํ„ฐํ”„๋ฆฌํ„ฐ๊ฐ€ ์ž…๋ ฅ๊ฐ’์œผ๋กœ AST๋ฅผ ๋ฐ›๋Š”๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ์š”. ๊ทธ๋Ÿผ AST๊ฐ€ ๋ฌด์—‡์ธ์ง€, ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ป๊ฒŒ AST๊ฐ€ V8์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š”์ง€ ์‚ดํŽด๋ด…์‹œ๋‹ค.

ํŒ : ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋‹ค๋ฅด๊ฒŒ ๋นŒ๋“œํ•˜๊ธฐ

Bit๊ณผ ๊ฐ™์€ OSS ํˆด์€ ๋ชจ๋˜ ์•ฑ์„ ๋นŒ๋“œํ•˜๋Š” ๋ฐ ์ƒˆ๋กœ์šด ํŒจ๋Ÿฌ๋‹ค์ž„์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋†€๋ฆฌํ‹ฑ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ๋Œ€์‹ ์— ๋…๋ฆฝ์ ์ธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋นŒ๋“œํ•ด๋ณด์„ธ์š”. ๊ทธ๋Ÿฌ๊ณ  ๋‚˜์„œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•จ๊ป˜ ๊ตฌ์„ฑํ•˜์—ฌ ์›ํ•˜๋Š” ๋งŒํผ ์—ฌ๋Ÿฌ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋นŒ๋“œํ•˜๊ธฐ์— ๋” ๋น ๋ฅธ ๋ฐฉ๋ฒ•์€ ์•„๋‹ˆ์ง€๋งŒ ๋” ํ™•์žฅ์„ฑ ์žˆ์œผ๋ฉฐ ๊ฐœ๋ฐœ์„ ํ‘œ์ค€ํ™”ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

Abstract Syntax Tree

AST๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ถ”์ƒ์ ์ธ ๊ตฌ์กฐ๋กœ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋‚˜ V8์— ํ•œ์ •๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋Š” ๊ณ ์ˆ˜์ค€์˜ ์ฝ”๋“œ๋ฅผ ์ €์ˆ˜์ค€์œผ๋กœ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด AST๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋ฅผ AST๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ ์ด๋Š” ๋ณ€์ˆ˜ ํƒ€์ž…, ์œ„์น˜, ๊ตฌ๋ฌธ์˜ ์ˆœ์„œ์™€ ๊ฐ™์ด ์ฝ”๋“œ์—์„œ ํ•„์š”ํ•œ ์„ธ๋ถ€์‚ฌํ•ญ๋“ค์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ฃผ์„๊ณผ ๊ฐ™์ด ๋ถˆํ•„์š”ํ•œ ๋ถ€๋ถ„์„ ๋‹ค๋ฃจ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋” ์ž˜ ์ดํ•ดํ•˜๊ณ ์ž, ๊ฐ„๋‹จํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋กœ AST๋ฅผ ์ƒ์„ฑํ•ด๋ด…์‹œ๋‹ค.

// ํ•จ์ˆ˜ ์ •์˜
function addition(x, y){
   var answer = x + y;
   console.log(answer);
}
// ํ•จ์ˆ˜ ํ˜ธ์ถœ
addition(10,20);

์ด ์ฝ”๋“œ์— ๋Œ€ํ•œ AST๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด esprima์—์„œ ์ œ๊ณตํ•˜๋Š” ์˜จ๋ผ์ธ ํŒŒ์‹ฑ ํˆด์„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ์š”. ๋‹ค์Œ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์€ AST์˜ ํ•œ ํŒŒํŠธ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š”๋ฐ ์ „์ฒด AST๋ฅผ ๋ณด๊ณ  ์‹ถ๋‹ค๋ฉด ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

{
 โ€œtypeโ€: โ€œProgramโ€,
 โ€œbodyโ€: [
   {
     โ€œtypeโ€: โ€œFunctionDeclarationโ€,
     โ€œidโ€: {
       โ€œtypeโ€: โ€œIdentifierโ€,
       โ€œnameโ€: โ€œadditionโ€
     },
     โ€œparamsโ€: [
      {
       โ€œtypeโ€: โ€œIdentifierโ€,
       โ€œnameโ€: โ€œxโ€
      },
      {
       โ€œtypeโ€: โ€œIdentifierโ€,
       โ€œnameโ€: โ€œyโ€
      }
     ],
     โ€œbodyโ€: {
       โ€œtypeโ€: โ€œBlockStatementโ€,
       โ€œbodyโ€: [
        ...
       ],
      โ€œkindโ€: โ€œvarโ€
     },
   ...
 โ€œsourceTypeโ€: โ€œscriptโ€
}

AST๋Š” ๊ฐ ์ฝ”๋“œ ๋ผ์ธ์— ํ•ด๋‹นํ•˜๋Š” ํ‚ค-๊ฐ’ ์Œ๋“ค์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ดˆ๊ธฐ ํƒ€์ž… ์‹๋ณ„์ž๋Š” AST๊ฐ€ ํ”„๋กœ๊ทธ๋žจ์— ์†ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ •์˜ํ•˜๊ณ , ๋ชจ๋“  ์ฝ”๋“œ ๋ผ์ธ์€ ๊ฐ์ฒด์˜ ๋ฐฐ์—ด ๋ณธ๋ฌธ ๋‚ด์— ์ •์˜๋ฉ๋‹ˆ๋‹ค. ์•„๊นŒ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, ๋ชจ๋“  ํ•จ์ˆ˜ ์ •์˜๋‚˜ ๋ณ€์ˆ˜ ์ •์˜, ์ด๋ฆ„๊ณผ ํƒ€์ž… ๋“ฑ์€ ๋ผ์ธ ๋ณ„๋กœ ๊ตฌ์„ฑ๋˜๋ฉฐ ์ฃผ์„์€ ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค. ์ตœ์ ํ™” ๊ณผ์ •๊ณผ AST๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋ณ„๊ฐœ๋กœ V8์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์„ฑ๋Šฅ์˜ ํ–ฅ์ƒ์„ ์œ„ํ•ด ๋‹ค๋ฅธ ํŠธ๋ฆญ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€, ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ๋ด…์‹œ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ํžˆ๋“  ํด๋ž˜์Šค

์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ์•Œ๋“ฏ์ด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋™์  ํƒ€์ž… ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๊ทธ๋•Œ๊ทธ๋•Œ ๊ฐ์ฒด์— ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค.

image

๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฐฉ์‹์€ ๋” ๋งŽ์€ ๋™์ ์ธ ๋ฃฉ์—…์„ ์š”๊ตฌํ•˜๋ฏ€๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์„ฑ๋Šฅ์„ ์ €ํ•˜์‹œํ‚ต๋‹ˆ๋‹ค.

V8 ์—”์ง„์€ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ๊ทน๋ณตํ•˜๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰์„ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ํžˆ๋“  ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํžˆ๋“  ํด๋ž˜์Šค๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”๊ฐ€?

์—ฌ๋Ÿฌ๋ถ„์ด ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ, V8 ์—”์ง„์€ ๊ทธ์— ๋งž๋Š” ์ƒˆ๋กœ์šด ํžˆ๋“  ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ํ›„, ์—ฌ๋Ÿฌ๋ถ„์ด ๋™์ผํ•œ ๊ฐ์ฒด์— ์ƒˆ๋กœ์šด ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ ๊ฐ์ฒด๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ฌ ๋•Œ V8 ์—”์ง„์€ ์ด์ „์˜ ํด๋ž˜์Šค์—์„œ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๋Š” ์ƒˆ๋กœ์šด ํžˆ๋“  ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ƒˆ๋กœ์šด ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ์œ„์˜ ์˜ˆ์‹œ์—์„œ ์–ด๋–ป๊ฒŒ ํžˆ๋“  ํด๋ž˜์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š”์ง€ ๋ณผ๊นŒ์š”?

๋นˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ–ˆ์„ ๋•Œ V8์€ ๋Š”๊ทธ์— ์ƒ์‘ํ•˜์—ฌ ์–ด๋– ํ•œ ์˜คํ”„์…‹์ด ์—†๋Š” ํžˆ๋“  ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

image

๊ทธ ํ›„ ์ƒˆ๋กœ์šด ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ค๋ฉด V8 ์—”์ง„์€ ์ƒˆ๋กœ์šด ํžˆ๋“  ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ ์ด ํด๋ž˜์Šค๋Š” ์ด์ „์˜ ํžˆ๋“  ํด๋ž˜์Šค์˜ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๋ฅผ ์ƒ์†ํ•˜๋ฉฐ offset 0์— ๋Œ€ํ•œ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

image

์ด๋Ÿฌํ•œ ๋ฐฉ์‹์„ ํ†ตํ•ด ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„์ด ์ ‘๊ทผ๋  ๋•Œ ๋”•์…”๋„ˆ๋ฆฌ ๋ฃฉ์—…์„ ๋ฌด์‹œํ•˜๋ฉฐ V8์€ ํด๋ž˜์Šค C01์„ ์ง์ ‘ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด์— ์ƒˆ๋กœ์šด ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋™์ผํ•œ ๊ณผ์ •์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ํžˆ๋“  ํด๋ž˜์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด ์ด๋Š” ์ด์ „์˜ ํด๋ž˜์Šค์™€ ์ƒˆ๋กœ์šด ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ๋ชจ๋‘๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

image

์ด๋Ÿฌํ•œ ํžˆ๋“  ํด๋ž˜์Šค ๊ฐœ๋…์€ ๊ฐ™์€ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ๋  ๋•Œ ๋”•์…”๋„ˆ๋ฆฌ ๋ฃฉ์—…์„ ๋ฌด์‹œํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ด๋ฏธ ์ƒ์„ฑํ•œ ํด๋ž˜์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์—ฌ๋Ÿฌ๋ถ„์ด article์ด๋ผ๋Š” ๋นˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ–ˆ๋‹ค๋ฉด(const articleObject = {}, V8 ์—”์ง„์€ ์ƒˆ๋กœ์šด ํžˆ๋“  ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹ ์— ์ด๋ฏธ ์ƒ์„ฑ๋œ C01 ํด๋ž˜์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๋Ÿฌ๋ถ„์ด articleName์ด๋ผ๋Š” ์ƒˆ๋กœ์šด ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ articleObject๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ค๋ฉด V8์€ ๋” ์ด์ƒ ์ด์ „์— ์ƒ์„ฑํ•œname์ด๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๋งŒ ๊ฐ€์ง€๋Š” C02 ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋” ์ข‹์€ ์„ฑ๋Šฅ์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ

๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ๋ถ„์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ์˜ ์„ฑ๋Šฅ์„ ๊ทน๋Œ€ํ™”ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ์—ฌ๋Ÿฌ๋ถ„์€ ๋™์  ํ”„๋กœํผํ‹ฐ ํ• ๋‹น์„ ๊ฐ์†Œํ•ด์•ผ ํ•  ๊ฒ๋‹ˆ๋‹ค. NodeJS์—์„œ ๋ฃจํ”„๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ๊ฐ์ฒด์— ๋™์  ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค๋ฉด ๋ฃจํ”„ ๋‚ด์—์„œ ์„ฑ๋Šฅ์ด ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฃจํ”„ ๋‚ด์—์„œ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ๋ฃจํ”„ ๋ฐ–์—์„œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. V8์€ ์กด์žฌํ•˜๋Š” ํžˆ๋“  ํด๋ž˜์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ธ ๊ฒƒ์ด์ฃ .

๊ฒฐ๋ก 

์–ด๋–ป๊ฒŒ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋™์ž‘ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๋…ผ์˜๊ฐ€ ์žˆ์„ ๋•Œ๋งˆ๋‹ค ์ด๋ฒคํŠธ ๋ฃจํ”„, ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ, ์ฝœ๋ฐฑ ํ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ๊ฒƒ๋“ค์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ตฌํ˜„๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ V8 ์—”์ง„์˜ ํ•œ ๋ถ€๋ถ„์ผ ๋ฟŒ์ด๋ฉฐ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ์–ด๋–ป๊ฒŒ V8์ด ๋™์ž‘ํ•˜๋Š”์ง€๋ฅผ ์„ค๋ช…ํ•˜๊ณ ์ž ํ–ˆ์œผ๋ฉฐ V8์ด ์‚ฌ์šฉํ•˜๋Š” ํžˆ๋“  ํด๋ž˜์Šค ๊ฐœ๋…์„ ๋ง์”€๋“œ๋ฆฐ ๊ฒ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ์ด ์•„ํ‹ฐํด์—์„œ ์ƒˆ๋กœ์šด ๊ฒƒ๋“ค์„ ๋ฐฐ์› ๊ธธ ๋ฐ”๋ผ๋ฉฐ ๋Œ“๊ธ€์ฐฝ์—์„œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๊ณต์œ ํ•ด์ฃผ์„ธ์š”.

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ Call Stack์€ ๋ฌด์—‡์ด๋ฉฐ ์™œ ํ•„์š”ํ•œ๊ฐ€?

์›๋ฌธ : The JavaScript Call Stack - What It Is and Why It's Necessary

(๋ธŒ๋ผ์šฐ์ €์™€ ๊ฐ™์€ ํ˜ธ์ŠคํŒ… ํ™˜๊ฒฝ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋Š”) ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ heap๊ณผ ์‹ฑ๊ธ€ call stack์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ์˜ ์ธํ„ฐํ”„๋ฆฌํ„ฐ์ž…๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” DOM, AJAX, Timer์™€ ๊ฐ™์€ web API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด ์•„ํ‹ฐํด์€ call stack์ด ๋ฌด์—‡์ด๋ฉฐ ์™œ ํ•„์š”ํ•œ์ง€์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์„ ๋ชฉ์ ์œผ๋กœ ํ•˜๋Š” ๊ธ€์ž…๋‹ˆ๋‹ค. call stack์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์—์„œ ์–ด๋–ป๊ฒŒ "ํ•จ์ˆ˜ ๊ณ„์ธต๊ณผ ์‹คํ–‰ ์ˆœ์„œ"๊ฐ€ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ๋ช…๋ฃŒํ•˜๊ฒŒ ์•Œ๋ ค์ค„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

call stack๋Š” ์ฃผ๋กœ ํ•จ์ˆ˜ ํ˜ธ์ถœ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. call stack์€ ํ•˜๋‚˜์ด๋ฏ€๋กœ ํ•จ์ˆ˜ ์‹คํ–‰ ๋˜ํ•œ ํ•œ๋ฒˆ์— ํ•˜๋‚˜์”ฉ, ์œ„์—์„œ ์•„๋ž˜๋กœ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ call stack์ด ๋™๊ธฐ์ ์ด๋ผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜์ฃ .

call stack์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ (๋‚˜์ค‘์— ์•Œ์•„๋ณผ) ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค.

๋น„๋™๊ธฐ์ ์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์šฐ๋ฆฌ๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜, ์ด๋ฒคํŠธ ๋ฃจํ”„, ํƒœ์ŠคํŠธ ํ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„์— ์˜ํ•ด ์Šคํƒ์— push๋œ ํ›„ call stack์— ์˜ํ•ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

๋„ˆ๋ฌด ์„œ๋‘๋ฅด์ง€ ๋ง๊ณ , ๋จผ์ € call stack์ด ๋ฌด์—‡์ธ๊ฐ€?๋ผ๋Š” ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต์„ ์ฐพ์•„๋ด…์‹œ๋‹ค.

๊ฐ€์žฅ ๊ธฐ์ดˆ์ ์ธ ์ˆ˜์ค€์œผ๋กœ ์„ค๋ช…ํ•˜๋ฉด call stack์€ ์ผ์‹œ์ ์œผ๋กœ ์ €์žฅํ•˜๊ณ  ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ๊ด€๋ฆฌํ•˜๋Š” LIFO(Last In, First Out) ์›๋ฆฌ๋ฅผ ๋”ฐ๋ฅด๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

์ •์˜๋ฅผ ์ž์„ธํžˆ ์„ค๋ช…ํ•ด๋ด…์‹œ๋‹ค.

LIFO

call stack์— ๋Œ€ํ•ด ๋งํ•  ๋•Œ LIFO ์›๋ฆฌ๋ฅผ ๋”ฐ๋ฅธ๋‹ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋งˆ์ง€๋ง‰์— ์Šคํƒ์— push๋œ ํ•จ์ˆ˜๊ฐ€ ์–ด๋–ค ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜๋  ๋•Œ ๋จผ์ € popํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ฝ˜์†”์— ์Šคํƒ ์ถ”์  ์—๋Ÿฌ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” LIFO๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ๋ด…์‹œ๋‹ค.

function firstFunction(){
  throw new Error('Stack Trace Error');
}

function secondFunction(){
  firstFunction();
}

function thirdFunction(){
  secondFunction();
}

thirdFunction();

์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์—๋Ÿฌ๋ฅผ ๋งŒ๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋“ค์ด ์–ด๋–ป๊ฒŒ ์Œ“์ด๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ์Šคํƒ์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์ด์–ด๊ทธ๋žจ์„ ๋ด…์‹œ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์€ ์Šคํƒ์— ์Œ“์ธ ํ•จ์ˆ˜๋“ค์ด firstFunction()๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•„์ฐจ๋ฆด ๊ฒ๋‹ˆ๋‹ค. (์ด ํ•จ์ˆ˜๋Š” ์Šคํƒ์— ๋งˆ์ง€๋ง‰์œผ๋กœ ๋“ค์–ด๊ฐ„ ํ•จ์ˆ˜์ด๊ณ  error์„ throwํ•˜๊ณ  pop๋ฉ๋‹ˆ๋‹ค.) ๊ทธ ๋‹ค์Œ์€ secondFunction()์ด๊ณ  ๊ทธ ๋‹ค์Œ์ด ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ๋•Œ ๊ฐ€์žฅ ๋จผ์ € Push๋œ thirdFunction()์ž…๋‹ˆ๋‹ค.

์ผ์‹œ์  ์ €์žฅ (Temporarily store)

ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ํ•จ์ˆ˜, ํŒŒ๋ผ๋ฏธํ„ฐ, ๋ณ€์ˆ˜๋“ค์€ ์Šคํƒ ํ”„๋ ˆ์ž„์—์„œ call stack์œผ๋กœ push๋ฉ๋‹ˆ๋‹ค. ์ด ์Šคํƒ ํ”„๋ ˆ์ž„์€ ์Šคํƒ์˜ ๋ฉ”๋ชจ๋ฆฌ ์œ„์น˜์ž…๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๋Š” ํ•จ์ˆ˜๊ฐ€ ์Šคํƒ์—์„œ pop๋  ๋•Œ ๋ฐ˜ํ™˜๋˜๋ฉด ์ง€์›Œ์ง‘๋‹ˆ๋‹ค.

ํ•จ์ˆ˜ ํ˜ธ์ถœ์˜ ๊ด€๋ฆฌ (Manage function invocation)

call stack์€ ๊ฐ ์Šคํƒ ํ”„๋ ˆ์ž„์˜ ์œ„์น˜์˜ ๊ธฐ๋ก์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰๋  ๋‹ค์Œ ํ•จ์ˆ˜๋ฅผ ์•Œ๊ณ  ์žˆ๋Š” ๊ฒƒ์ด์ฃ . (์‹คํ–‰ ํ›„์—๋Š” ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.) ์ด๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋™๊ธฐ์ ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€๊ฒŒ ๊ณ„์‚ฐ๋Œ€์™€ ๊ฐ™์€ ํ์—์„œ ์„œ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์„ธ์š”. ์•ž ์‚ฌ๋žŒ์ด ๋๋‚˜์•ผ๋งŒ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฐจ๋ก€๊ฐ€ ์˜ต๋‹ˆ๋‹ค. ์ด๊ฒŒ ๋ฐ”๋กœ ๋™๊ธฐ์ ์ธ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋ฅผ "ํ•จ์ˆ˜ ํ˜ธ์ถœ์˜ ๊ด€๋ฆฌ"๋ผ๊ณ  ํ•˜๋Š” ๊ฒƒ์ด๊ณ ์š”.

call stack์€ ์–ด๋–ป๊ฒŒ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ๊ด€๋ฆฌํ•˜๋Š”๊ฐ€?

ํ•œ ํ•จ์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ƒ˜ํ”Œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด์„œ ๋‹ต์„ ์ฐพ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๋ณด์„ธ์š”.

function firstFunction(){
  console.log("Hello from firstFunction");
}

function secondFunction(){
  firstFunction();
  console.log("The end from secondFunction");
}

secondFunction();

์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋ฉฐ ์ผ์–ด๋‚˜๋Š” ์ผ๋“ค์ž…๋‹ˆ๋‹ค.

  1. secondFunction()์ด ์‹คํ–‰๋  ๋•Œ ๋นˆ ์Šคํƒ ํ”„๋ ˆ์ž„์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด ํ”„๋ ˆ์ž„์€ ํ”„๋กœ๊ทธ๋žจ์˜ (์ต๋ช…์˜) ๋ฉ”์ธ ์—”ํŠธ๋ฆฌ ํฌ์ธํŠธ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
  2. secondFunction()๋Š” ์Šคํƒ์— push๋œ firstFunction()๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  3. firstFunction()๋Š” ๋ฐ˜ํ™˜๋˜๊ณ  ์ฝ˜์†”์— "Hello from firstFunction"์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
  4. firstFunction()๋Š” ์Šคํƒ์—์„œ pop๋ฉ๋‹ˆ๋‹ค.
  5. ์‹คํ–‰ ์ˆœ์„œ๊ฐ€ secondFunction()๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.
  6. secondFunction()๋Š” ๋ฐ˜ํ™˜๋˜๋ฉฐ ์ฝ˜์†”์— "The end from secondFunction"์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
  7. secondFunction()๋Š” ์Šคํƒ์—์„œ Pop๋˜๋ฉฐ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ง€์›Œ์ง‘๋‹ˆ๋‹ค.

์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋Š” ์™œ ๋ฐœ์ƒํ•˜๋Š”๊ฐ€?

์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋Š” ์žฌ๊ท€ํ•จ์ˆ˜๊ฐ€ ํƒˆ์ถœ ์ง€์  ์—†์ด ํ˜ธ์ถœ๋  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” ์Šคํƒ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ธฐ ์ „์— ์ˆ˜์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋งฅ์‹œ๋ฉˆ ์Šคํƒ ํ˜ธ์ถœ ํšŸ์ˆ˜๊ฐ€ ์ •ํ•ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ๋ฅผ ๋ณด์‹ญ์‹œ์˜ค.

function callMyself(){
  callMyself();
}

callMyself();

callMyself()๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ "Maximum call size exceeded"๋ฅผ throwํ•˜๊ธฐ ์ „๊นŒ์ง€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๊ฐ€ ๋ฐœ์ƒํ•˜์ฃ .

์š”์•ฝ

call stack์˜ ์ฃผ์š” ์ด์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ๋งŒ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ์ž…๋‹ˆ๋‹ค.
  2. ์ฝ”๋“œ ์‹คํ–‰์ด ๋™๊ธฐ์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.
  3. ํ•จ์ˆ˜ ํ˜ธ์ถœ์€ ์ผ์‹œ์ ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ฐจ์ง€ํ•˜๋Š” ์Šคํƒ ํ”„๋ ˆ์ž„์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  4. LIFO๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์•„ํ‹ฐํด์—์„œ call stack ์•„ํ‹ฐํด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋น„๋™๊ธฐ์ ์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
์˜ˆ์ œ ์ฝ”๋“œ๋Š” GitHub repo์—์„œ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ์–ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๋ฐ•์ˆ˜๋ฅผ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š”. ๊ทธ๋Ÿผ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๋„ ์ด ์•„ํ‹ฐํด์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋ฉ˜ํŠธ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] Type๊ณผ Interface ๋” ์ด์ƒ ํ—ท๊ฐˆ๋ คํ•˜์ง€ ๋งˆ์„ธ์š”

์›๋ฌธ : https://javascript.plainenglish.io/no-more-confusion-about-typescripts-type-and-interface-63c39418ae35

image

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๋งˆ์Šคํ„ฐ ์‹œ๋ฆฌ์ฆˆ์— ์˜ค์‹  ๊ฒƒ์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ์‹œ๋ฆฌ์ฆˆ๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ˜•ํƒœ๋กœ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ์ฝ”์–ด ์ง€์‹๊ณผ ๊ธฐ์ˆ ๋“ค์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ™์ด ๋ฐฐ์›Œ๋ณด์•„์š”! ์ด์ „ ๊ธ€๋“ค์€ ์•„๋ž˜๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”

๋งŒ์•ฝ ์—ฌ๋Ÿฌ๋ถ„์ด ๋ ˆ์ฃผ๋ฉ”์— ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๊ฒฝ๋ ฅ์„ ์ผ๋‹ค๋ฉด, ์•„๋งˆ ๋ฉด์ ‘๊ด€์€ type๊ณผ interface์˜ ์ฐจ์ด์ ์ด ๋ฌด์—‡์ธ์ง€ ๋ฌผ์–ด๋ณผ ๊ฒ๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ๋Œ€๋‹ตํ•ด์•ผ ํ• ์ง€ ์•„์‹œ๊ฒ ๋‚˜์š”? ๋ชจ๋ฅด๊ฒ ๋‹ค๋ฉด, ์ด ๊ธ€์„ ์ฝ๊ณ  ์ž˜ ์ดํ•ดํ•˜์‹ค ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ ๊ฐ™๋„ค์š”.

ํƒ€์ž… ๋ณ„์นญ(alias)์€ ํƒ€์ž…์— ์ƒˆ๋กœ์šด ์ด๋ฆ„์„ ๋ถ€์—ฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๊ณ , ์›์‹œ ํƒ€์ž…๊ณผ ๊ฐ™์€ ๋น„๊ฐ์ฒด ํƒ€์ž…์ด๋‚˜ ํ•ฉ์ง‘ํ•ฉ์— ๋„ค์ด๋ฐํ•  ๋•Œ๋„ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

type MyNumber = number;
type StringOrNumber = string | number;
type Text = string | string[];
type Point = [number, number];
type Callback = (data: string) => void;

Typescript 1.6์—์„œ ํƒ€์ž… ๋ณ„์นญ์€ ์ œ๋„ˆ๋ฆญ ํƒ€์ž…์„ ์ง€์›ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ ์ž‘์—…ํ•  ๋•Œ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” Partial, Required, Pick, Record, ๊ทธ๋ฆฌ๊ณ  Exclude์™€ ๊ฐ™์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž…๋„ ํƒ€์ž… ๋ณ„์นญ์œผ๋กœ ์ •์˜๋ฉ๋‹ˆ๋‹ค.

image

๊ฐ์ฒด ํƒ€์ž…์„ ์ •์˜ํ•  ๋•Œ interface๊ฐ€ ์ฃผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. Vue 3์˜ App ๊ฐ์ฒด๋กœ interface๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •์˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

image

์œ„ ์ฝ”๋“œ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด, interface๋ฅผ ์ •์˜ํ•  ๋•Œ ๊ฐ์ฒด ํƒ€์ž…์— ํ”„๋กœํผํ‹ฐ์™€ ๋ฉ”์†Œ๋“œ ๋ชจ๋‘๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘˜์˜ ๋น„์Šทํ•œ ์ ์„ ๋จผ์ € ์•Œ๋ ค๋“œ๋ฆฌ๊ณ  type๊ณผ interface์˜ ์—ญํ• ์„ ์ดํ•ดํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์œ ์‚ฌ์ 

ํƒ€์ž… ๋ณ„์นญ๊ณผ ์ธํ„ฐํŽ˜์ด์Šค ๋ชจ๋‘ ๊ฐ์ฒด๋‚˜ ํ•จ์ˆ˜ ํƒ€์ž…์„ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

ํƒ€์ž… ๋ณ„์นญ(type alias)

type Point = {
  x: number;
  y: number;
};
โ€‹
type SetPoint = (x: number, y: number) => void;

์œ„ ์ฝ”๋“œ์—์„œ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด ํƒ€์ž…๊ณผ ํ•ฉ์ˆ˜ ํƒ€์ž…์— type ํ‚ค์›Œ๋“œ๋กœ ๋ณ„์นญ์„ ๋ถ€์—ฌํ•จ์œผ๋กœ์จ ๋‹ค๋ฅธ ๊ณณ์—์„œ๋„ ์ด ํƒ€์ž…๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ธํ„ฐํŽ˜์ด์Šค

interface Point {
  x: number;
  y: number;
}
โ€‹
interface SetPoint {
  (x: number, y: number): void;
}

ํƒ€์ž… ๋ณ„์นญ๊ณผ ์ธํ„ฐํŽ˜์ด์Šค ๋ชจ๋‘ ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๋‹ค.

ํƒ€์ž… ๋ณ„์นญ์€ &์— ์˜ํ•ด ํ™•์žฅ๋˜์ง€๋งŒ ์ธํ„ฐํŽ˜์ด์Šค๋Š” extends์— ์˜ํ•ด ํ™•์žฅ๋ฉ๋‹ˆ๋‹ค.

image

image

๊ทธ๋ ‡๋‹ค๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํƒ€์ž… ๋ณ„์นญ์œผ๋กœ ์ •์˜๋œ ํƒ€์ž…์„ extends๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”? ๋‹ต์€ '๊ทธ๋ ‡๋‹ค'์ž…๋‹ˆ๋‹ค. ์ถ”๊ฐ€์ ์œผ๋กœ ํƒ€์ž… ๋ณ„์นญ ๋˜ํ•œ & ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•˜์—ฌ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ •์˜๋œ ํƒ€์ž…์„ ํ™•์žฅํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

image

image

๊ทธ๋Ÿผ ์ด์ œ ํƒ€์ž… ๋ณ„์นญ๊ณผ ์ธํ„ฐํŽ˜์ด์Šค์˜ ์œ ์‚ฌ์ ์„ ์•Œ๊ฒŒ ๋˜์…จ๋‚˜์š”? ๊ทธ๋Ÿผ ์ฐจ์ด์ ์— ๋Œ€ํ•ด ์–˜๊ธฐํ•ด๋ด…์‹œ๋‹ค.

์ฐจ์ด์ 

  1. ํƒ€์ž… ๋ณ„์นญ์€ ์›์‹œ ํƒ€์ž…, ์œ ๋‹ˆ์˜จ ํƒ€์ž…, ํŠœํ”Œ ํƒ€์ž…์— ๋Œ€ํ•ด ๋ณ„์นญ์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๊ทธ๋Ÿด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
type MyNumber = number; // primitive type
type StringOrNumber = string | number; // union type
type Point = [number, number]; // tuple type
  1. ๋™์ผํ•œ ์ด๋ฆ„์˜ ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ž๋™์ ์œผ๋กœ ํ•ฉ์ณ์ง€์ง€๋งŒ(Declaration Merging, ์„ ์–ธ ๋ณ‘ํ•ฉ) ํƒ€์ž… ๋ณ„์นญ์€ ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

image

image

์„ ์–ธ ๋ณ‘ํ•ฉ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐœ๋ฐœํ•  ๋•Œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋” ์ข‹์€ ๋ณด์•ˆ์ ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด webext-bridge ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ProtocolMap ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์ด ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž๋“ค์€ ํŽธํ•˜๊ฒŒ ProtocolMap ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ํ›„, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‚ด๋ถ€์— ์ œ๊ณต๋˜๋Š” onMessage ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปค์Šคํ…€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ๋•Œ ์„œ๋กœ ๋‹ค๋ฅธ ๋ฉ”์‹œ์ง€์— ํ•ด๋‹นํ•˜๋Š” ๋ฉ”์„ธ์ง€ ๋ฐ”๋”” ํƒ€์ž…๋“ค์„ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

extends ProtocolMap interface

import { ProtocolWithReturn } from 'webext-bridge'
โ€‹
declare module 'webext-bridge' {
  export interface ProtocolMap {
    foo: { title: string }
    bar: ProtocolWithReturn<CustomDataType, CustomReturnType>
  }
}

listen for custom messages

import { onMessage } from 'webext-bridge'
โ€‹
onMessage('foo', ({ data }) => {
  // type of `data` will be `{ title: string }`
  console.log(data.title)
}

image
image

์ด ๋ถ€๋ถ„์— ๋Œ€ํ•ด ํฅ๋ฏธ๊ฐ€ ์žˆ์œผ์‹œ๋‹ค๋ฉด webext-bridge์˜ onMessage์— ๋Œ€ํ•œ ํƒ€์ž… ์ •์˜๋ฅผ ์‚ดํŽด๋ณด์„ธ์š”. ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋ฉด ์ €์™€ ๋Œ€ํ™”ํ•˜์‹ค ์ˆ˜ ์žˆ์–ด์š”. ๋งˆ์ง€๋ง‰์œผ๋กœ ํƒ€์ž… ๋ณ„์นญ๊ณผ ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•œ ๋ช‡๋ช‡ ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์š”์•ฝํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์–ธ์ œ type์„ ์‚ฌ์šฉํ• ๊นŒ์š”?

  1. ์›์‹œ ํƒ€์ž…์— ๋ณ„์นญ์„ ์ •์˜ํ•  ๋•Œ๋Š” type์„ ์“ฐ์„ธ์š”
  2. ํŠœํ”Œ ํƒ€์ž…์„ ์ •์˜ํ•  ๋•Œ type์„ ์“ฐ์„ธ์š”
  3. ํ•จ์ˆ˜ ํƒ€์ž…์„ ์ •์˜ํ•  ๋•Œ type์„ ์“ฐ์„ธ์š”
  4. ์œ ๋‹ˆ์˜จ ํƒ€์ž…์„ ์ •์˜ํ•  ๋•Œ type์„ ์“ฐ์„ธ์š”
  5. ๋งคํ•‘๋œ ํƒ€์ž…์„ ์ •์˜ํ•  ๋•Œ type์„ ์“ฐ์„ธ์š”

์–ธ์ œ interface์„ ์‚ฌ์šฉํ• ๊นŒ์š”?

  1. ์„ ์–ธ ๋ณ‘ํ•ฉ ๊ธฐ๋Šฅ์˜ ์žฅ์ ์„ ํ™œ์šฉํ•˜๋ ค๋ฉด interface๋ฅผ ์“ฐ์„ธ์š”
  2. ๊ฐ์ฒด ํƒ€์ž…์„ ์ •์˜ํ•˜๊ณ  type์„ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์„ ๋•Œ interface๋ฅผ ์“ฐ์„ธ์š”

์ด ๊ธ€์„ ์ฝ๊ณ  ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ํƒ€์ž… ๋ณ„์นญ๊ณผ ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ฐจ์ด๋ฅผ ์ด๋ฏธ ์ดํ•ดํ•˜์…จ์œผ๋ฆฌ๋ผ ๋ฏฟ์Šต๋‹ˆ๋‹ค.

[๋ฒˆ์—ญ] ReactJS์˜ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•œ 5๊ฐ€์ง€ ์ถ”์ฒœ ํˆด

2020๋…„ 3์›” 17์ผ์— ์ž‘์„ฑ๋œ 5 Recommended Tools for Optimizing Performance in ReactJS์„ ์ฝ๊ณ  ๋ฒˆ์—ญํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

์†๋„์™€ ์ตœ์ ํ™”๋ฅผ ํ•˜๊ณ ์ž ํ•˜๋Š” ๋งˆ์Œ์—์„œ, ๋ฆฌ์•กํŠธ์˜ ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง๊ณผ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ์ œ๊ฐ€ ์ข‹์•„ํ•˜๋Š” ๋„๊ตฌ ๋ชฉ๋ก์„ ์‚ดํŽด๋ด…์‹œ๋‹ค.

1. <Profiler />

์ƒŒ๋“œ๋ฐ•์Šค ๋งํฌ

B. Vaughn๊ฐ€ ๊ฐœ๋ฐœํ•œ ๋ฆฌ์•กํŠธ์˜ ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ Profiler๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋ฆฌ๋ Œ๋”๋˜์—ˆ๋Š”์ง€, ๋ Œ๋”๋ง์ด ์†Œ๋น„ํ•œ ์‹œ๊ฐ„๊ณผ ๋ฆฌ์†Œ์Šค๋ฅผ ์ธก์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Profiler๋Š” onRender์— ํ•จ์ˆ˜ prop์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์ด๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ ๋  ๋•Œ๋งˆ๋‹ค time metrics๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ฆฌ์•กํŠธ ์•ฑ์—์„œ ๋น„ํšจ์œจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๊ฑฐ๋‚˜ ํƒ์ง€ํ•˜๋Š” ๋ฐ ์ข‹์€ ๋ฐฉ์•ˆ์ž…๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ๋ฅผ ๋ด…์‹œ๋‹ค.

import { unstable_Profiler as Profiler } from "react"

<Profiler id="Counter" onRender={callback}>
    <Counter />
</Profiler>

id prop์€ ๋ ˆํฌํŠธ๋˜๋Š” ํ”„๋กœํŒŒ์ผ๋Ÿฌ๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. onRender์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” Counter ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ ๋  ๋•Œ๋งˆ๋‹ค ์•„๋ž˜ ์ธ์ˆ˜์™€ ํ•จ๊ป˜ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

function callback(id, phase, actualTime, baseTime, startTime, commitTime) {
    
log("id: " + id, "phase:" + phase, "actualTime:" + actualTime,   "baseTime: " + baseTime, "startTime: " + startTime, "commitTime: " +  commitTime)
}

ํ•จ์ˆ˜ ์ธ์ˆ˜๋Š” Counter ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” time metrics์ž…๋‹ˆ๋‹ค. ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ด…์‹œ๋‹ค.

  • id : Profiler ์ปดํฌ๋„ŒํŠธ์— ์„ค์ •๋˜๋Š” ๊ณ ์œ  ์•„์ด๋””
  • phase : ์ปดํฌ๋„ŒํŠธ๊ฐ€ "๋งˆ์šดํŠธ"๋œ ๊ฒƒ์ธ์ง€, "์—…๋ฐ์ดํŠธ/๋ฆฌ๋ Œ๋”" ๋œ ๊ฒƒ์ธ์ง€ ์•Œ๋ ค์คŒ
  • actualTime : Profiler์˜ ํ•˜์œ„ ํ•ญ๋ชฉ๋“ค์ด ๋งˆ์šดํŠธํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ ํ•˜๋Š”๋ฐ ๊ฑธ๋ฆฐ ์‹œ๊ฐ„
  • baseTime : Profiler ํŠธ๋ฆฌ์˜ ๊ฐ ์ปดํฌ๋„ŒํŠธ๋“ค์ด ๋งˆ์šดํŠธํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ ํ•˜๋Š”๋ฐ ๊ฑธ๋ฆฐ ์‹œ๊ฐ„
  • startTime : Profiler๊ฐ€ ๋งˆ์šดํŠธ/๋ Œ๋”๋ฅผ ์ธก์ •ํ•˜๋Š” ๊ฒƒ์„ ์‹œ์ž‘ํ•œ ์‹œ๊ฐ„
  • commitTime : ์—…๋ฐ์ดํŠธ๋ฅผ ์ปค๋ฐ‹ํ•˜๋Š”๋ฐ ๊ฑธ๋ฆฐ ์‹œ๊ฐ„

์ด ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์€ ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๊ฐ€ ๋Š๋ฆฌ๊ฒŒ ๋งŒ๋“œ๋Š”์ง€, ์ข‹์€ ์„ฑ๋Šฅ์„ ๋ณด์ด๋Š”์ง€ ํŒŒ์•…ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๋ฐ๋ชจ ํ”„๋กœ์ ํŠธ

Counter 1๊ณผ Counter 2 ๋‘ ๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ Profiler ์ปดํฌ๋„ŒํŠธ๋กœ ๊ฐ์‹ธ๊ณ  "Counter1" "Counter2" ์•„์ด๋””๋ฅผ ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. DOM์—์„œ ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ time metric๋ฅผ ๋ณด์ด๊ฒŒ๋” ํ–ˆ์œผ๋‹ˆ ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ๋  ๋•Œ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„์„ ๋ณด์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ๋ฒˆ ์‹œ๋„ํ•ด๋ณด์„ธ์š” ๐Ÿ™‚

2. React Developer tools

โ€˜React Developer toolsโ€™๋Š” ๋ฆฌ์•กํŠธ ํŒ€์—์„œ ๊ฐœ๋ฐœํ•œ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์˜ ์ต์Šคํ…์…˜์ž…๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์†Œ๊ฐœํ•  ํ•„์š”๋„ ์—†๊ธฐ๋Š” ํ•˜์ง€๋งŒ ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์ฃผ๋ชฉํ–ˆ์œผ๋ฉด ํ•˜๋Š” ํ•œ ๊ฐ€์ง€ ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ "Highlight Updates"์ž…๋‹ˆ๋‹ค. ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜๋Š”์ง€ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋Š” ์•„์ฃผ ์ข‹์€ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์˜ ๋ฐ”์šด๋”๋ฆฌ๋ฅผ ์ƒ‰์ƒ์œผ๋กœ ๊ฐ•์กฐํ•ด์ค๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ์‹œ๋‹ค.

Main์ด ๋ฆฌ๋ Œ๋”๋œ๋‹ค๋ฉด, Counter์™€ Count ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ๊ณ  ์žˆ๋Š” ๋ฐ”์šด๋”๋ฆฌ๊ฐ€ ์ž ๊น ์ƒ‰์ƒ์œผ๋กœ ๊ฐ•์กฐ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”ํ•˜๋ ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์˜ ๊ด€๋ฆฌ์ž ๋„๊ตฌ์—์„œ "React" ํƒญ์„ ํด๋ฆญํ•˜์„ธ์š”. ์šฐ์ธก ์ƒ๋‹จ์— ์žˆ๋Š” ์„ค์ • ์•„์ด์ฝ˜์„ ๋ˆ„๋ฅด๋ฉด ํŒ์—…์ฐฝ์ด ๋œน๋‹ˆ๋‹ค.
"Highlight Updates" ์ฒดํฌ๋ฐ•์Šค๋ฅผ ํด๋ฆญํ•˜์„ธ์š”.

์ปฌ๋Ÿฌ ๋ฐด๋“œ์˜ ์œ ํ˜•์€ ์–ผ๋งˆ๋‚˜ ์ž์ฃผ/๋นˆ๋ฒˆํ•˜๊ฒŒ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜๋Š”์ง€์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

|    green - ๋นˆ๋„๊ฐ€ ๋‚ฎ์Œ
|    blue - ๋นˆ๋„๊ฐ€ ํ‰๊ท 
v    red - ๋นˆ๋„๊ฐ€ ๋†’์Œ

์ด ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ƒ‰์ƒ์œผ๋กœ ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋นˆ๋ฒˆํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธ ๋˜๋Š”์ง€ ๋น ๋ฅด๊ฒŒ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๊ณ  ์ ์ ˆํ•œ ์ตœ์ ํ™”๋ฅผ ์ทจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. Bit.dev

Bit์€ ์ปดํฌ๋„ŒํŠธ ๊ณต์œ , ์กฐ์ง, ์žฌ์‚ฌ์šฉ์„ ํ•˜๋Š” ๋ฐ ์•„์ฃผ ์ข‹์€ ํˆด์ž…๋‹ˆ๋‹ค. ์ €๋Š” ๋ฏธ๋ž˜์—์„œ์˜ ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด ํŒ€๊ณผ ํ•จ๊ป˜ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ณต์œ  ์ปฌ๋ ‰์…˜์— ํผ๋ธ”๋ฆฌ์‹ฑํ•˜๊ณ  ์ƒ์„ฑํ•˜๊ณ ์ž ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ ๊ทน๋Œ€ํ™”ํ•จ์— ๋”ฐ๋ผ ์ข‹์€ ํ”„๋ž™ํ‹ฐ์Šค์™€ ๋น ๋ฅธ ๊ฐœ๋ฐœ์„ ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ด€์ ์—์„œ ๋˜ ๋‹ค๋ฅธ ์ค‘์š”ํ•œ ๊ฒƒ์€ ์—ฌ๋Ÿฌ๋ถ„์ด ํ•„์š”ํ•œ ๊ฒƒ๋งŒ ๋น ๋ฅด๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ „์ฒด์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ผ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ๋งŒ ํ•„์š”ํ•œ ๊ฒƒ์ด์ฃ . ํŠนํžˆ ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์•„์ฃผ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด ์—ฌ๋Ÿฌ๋ถ„์ด ์œ ๋ช…ํ•œ Material-UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด ์ „์ฒด๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ bit.dev์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ณต์œ ํ•œ๋‹ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์˜ ์•ฑ์—์„œ ์–ด๋–ค ๋…๋ฆฝ์ ์ธ ์ปดํฌ๋„ŒํŠธ๋งŒ ์„ ํƒํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„์ฃผ ๊ฐ„๋‹จํ•œ to-do app์œผ๋กœ๋ถ€ํ„ฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ณต์œ ํ•˜๋Š” ์งง์€ ์˜ˆ์ œ๋ฅผ ๋ณด์—ฌ๋“œ๋ฆด๊ฒŒ์š”.

๋จผ์ €, Bit.dev์— ์ปดํฌ๋„ŒํŠธ ์ปฌ๋ ‰์…˜์„ ์ƒ์„ฑํ•˜์„ธ์š”.
๊ทธ๋ฆฌ๊ณ  Bit์˜ CLI ํˆด์„ ์ „์—ญ์œผ๋กœ ์„ค์น˜ํ•˜๊ณ  ๋กœ๊ทธ์ธ ํ•˜์„ธ์š”.

$ yarn global add bit-bin
$ bit login

๊ทธ ํ›„ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์—์„œ ๊ณต์œ ๋ฅผ ์‹œ์ž‘ํ•˜์„ธ์š”.

// Initialize a workspace in your projectโ€™s directory
$ bit init --package-manager yarn
// Add components to track
$ bit add src/components/*

// Configure a compiler to make the usable in other build setups
// I use here the React with TypeScipt compiler
$ bit import bit.envs/compilers/react-typescript --compiler

// Tag your added components (this will also build and test them)
$ bit tag --all 1.0.0
// Export them to your component collection at bit.dev
$ bit export <user-name>.<collection-name>

์ด ์•ฑ์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์˜ ๊ณต์œ ๋œ ์ปฌ๋ ‰์…˜์ธ ์ตœ์ข… ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.

4. why-did-you-render

Welldone software์—์„œ ๋งŒ๋“  ์ด ๋„๊ตฌ๋Š” ๋‚ญ๋น„๋˜๋Š” ๋ฆฌ๋ Œ๋”์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ์ค๋‹ˆ๋‹ค.
์ปดํฌ๋„ŒํŠธ์˜ prop์—์„œ ์ฐจ์ด๋ฅผ ํ™•์ธํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜์—ˆ๋Š”๋ฐ props๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๋ผ๋ฉด ์ฝ˜์†”๋กœ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

์ค‘๋ณต๋˜๋Š” ๋ฆฌ๋ Œ๋”๋ง์€ ์ž‘์€ ์•ฑ์—์„œ๋Š” ๋ฐœ๊ฒฌ๋  ์ˆ˜ ์—†์„์ง€๋ผ๋„ ํฐ ์Šค์ผ€์ผ์ผ ๋•Œ๋Š” ์•„์ฃผ ๋ถ„๋ช…ํ•˜๊ฒŒ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค.
์ด ๋„๊ตฌ๋Š” ์‹ค์ œ๋กœ ๋ฆฌ์•กํŠธ์™€ ์—ฐ๊ฒฐ๋˜์–ด ์ปดํฌ๋„ŒํŠธ์˜ ๋ผ์ดํ”„์‚ฌ์ดํด์„ ๋”ฐ๋ฅด๋ฏ€๋กœ ๋ฆฌ๋ Œ๋”๋ง๋  ๋•Œ ์ปดํฌ๋„ŒํŠธ prop์˜ ์ฐจ์ด๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉํ•˜๊ธฐ ๊ฝค ์‰ฝ์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” npm install @welldone-software/why-did-you-render --save๋ฅผ ํ†ตํ•ด ๋„๊ตฌ๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ ๋‹ค์Œ์€ ์•„๋ž˜์ฒ˜๋Ÿผ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ whyDidYouRender ํ”„๋กœํผํ‹ฐ๋ฅผ ์ •์ ์œผ๋กœ ์ง์ ‘ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

class Counter extends React.Component {
  static whyDidYouRender = true;
  render() {
   //...
  }
}

ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

function Counter() {
  return(
   // ...
  )
}

Counter.whyDidYouRender = true;

5. ์„ฑ๋Šฅ ํƒ€์ž„๋ผ์ธ (๋ธŒ๋ผ์šฐ์ € ํ”„๋กœํŒŒ์ผ๋ง)

์ด ๋„๊ตฌ๋Š” ํฌ๋กฌ ๊ฐœ๋ฐœ์ž๋„๊ตฌ์— ๋‚ด์žฅ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. Performance ํƒญ์—์„œ ์ฐพ์œผ์‹ค ์ˆ˜ ์žˆ์ฃ .
๋”์ฐํ•˜๊ฒŒ ๋ฆฌ๋ Œ๋”๋ง๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ์‹๋ณ„ํ•  ๋•Œ ํŠนํžˆ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ถˆํ•„์š”ํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธ ๋˜๋Š” UI์™€ ์–ผ๋งˆ๋‚˜ ์ž์ฃผ ์ผ์–ด๋‚˜๋Š”์ง€๋ฅผ ์•„๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

ํˆด์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋จผ์ € development ๋ชจ๋“œ๋กœ ๋ฆฌ์•กํŠธ ์•ฑ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
localhost:3000๋กœ ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ €์— ์•ฑ์„ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

๊ด€๋ฆฌ์ž ๋„๊ตฌ๋ฅผ ์—ด์–ด "Performance" ํƒญ์„ ํด๋ฆญํ•˜์„ธ์š”. ์•„๋ฌด๊ฒƒ๋„ ์—†๋‹ค๋ฉด "Timeline"์„ ํด๋ฆญํ•˜์„ธ์š”. "Performance"์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ "Record" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ "Ctrl + E"๋ฅผ ๋ˆ„๋ฅด๋ฉด ๊ด€๋ฆฌ์ž๋„๊ตฌ๊ฐ€ ๊ธฐ๋ก์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
์—ฌ๋Ÿฌ๋ถ„์ด ๊ฒ€์‚ฌํ•˜๊ณ  ์‹ถ์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์•ฑ์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

20์ดˆ๋ฅผ ๊ธฐ๋กํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•˜๋Š”๋ฐ 20์ดˆ๋ฅผ ๋„˜์–ด ๊ธฐ๋กํ•˜๋ฉด ํฌ๋กฌ ๋ธŒ๋ผ์šฐ์ €์— ๋ถ€๋‹ด์ด ๊ฐ€๊ฒŒ ๋  ๊ฒ๋‹ˆ๋‹ค.

๋‹ค ๋์œผ๋ฉด "Stop" ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š”.

ํƒญ์ด ํƒ€์ž„๋ผ์ธ์„ ๋กœ๋“œํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๋“œ๋ž˜๊ทธ๋ฅผ ํ†ตํ•ด ์˜ค๋ฒ„๋ทฐ์—์„œ ๊ด€์‹ฌ์žˆ๋Š” ์˜์—ญ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์šฐ์Šค ํœ ๊ณผ WASD ํ‚ค๋ฅผ ์ด์šฉํ•ด ํ™•๋Œ€์ถ•์†Œ, ์ƒํ•˜์ขŒ์šฐ ์ด๋™์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
์—ฌ๊ธฐ ๋ฐ๋ชจ๋กœ ์ƒ์„ฑํ•œ Counter ์•ฑ์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

class Counter1 extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            count: 0
        }
    }

    render() {
        return (
            <div className="counter">
                <div>
                    Count: {this.state.count}
                </div>
                <div>
                    <button onClick={() => {this.setState({count: this.state.count + 1})}}>Incr</button>
                    <button onClick={() => {this.setState({count: this.state.count - 1})}}>Decr</button>
                </div>
            </div>
        )
    }
}

class App extends React.Component {
    render() {
        return (
            <Counter1 />
        )
    }
}

์•ฑ์ด ๋กœ๋“œ๋  ๋•Œ๋ถ€ํ„ฐ Incr Decr ๋ฒ„ํŠผ์„ ๋‘ ๋ฒˆ ๋ˆŒ๋ €์„ ๋•Œ ์•ฑ์˜ ํƒ€์ด๋ฐ์„ ๊ธฐ๋กํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค.
Record ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ณ  ์•ฑ์„ ๋กœ๋“œํ•ด์„œ ๊ฐ ๋ฒ„ํŠผ์„ ํ•œ๋ฒˆ ๋ˆŒ๋ €์Šต๋‹ˆ๋‹ค.

ํƒ€์ž„๋ผ์ธ ๋ ˆํฌํŠธ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.

W ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ™•๋Œ€ ์ถ•์†Œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.


๊ฐ ์˜ค๋žœ์ง€ ์ƒ‰์ƒ์˜ ๋ฐ”๋Š” ์ปดํฌ๋„ŒํŠธ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๊ฐ ๋ฐ” ๋‚ด์— ๋‚˜์—ด๋œ ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„๊ณผ ๋ฐœ์ƒํ•œ ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฉ”์†Œ๋“œ ๋˜ํ•œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์šฐ๋ฆฌ์˜ ์บก์ณ์—์„œ App์™€ Counter1์€ [mount]๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š”๋ฐ ์ด๋Š” DOM์— ๋งˆ์šดํŠธ๋œ ์ฒ˜์Œ์„ ๋‚˜ํƒ€๋‚ด๊ณ  ์–ผ๋งˆ๋‚˜ ๊ฑธ๋ ธ๋Š”์ง€๋„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

ํƒ€์ž„๋ผ์ธ์„ ์ด๋™ํ•˜์—ฌ Incr๊ณผ Decr ๋ฒ„ํŠผ๋“ค์„ ๋ˆŒ๋ €์„ ๋•Œ Counter1์ด ์—…๋ฐ์ดํŠธ๋˜๋Š” ํƒ€์ž„๋ผ์ธ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Incr ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ์ž…๋‹ˆ๋‹ค. Counter1์ด ๋ฆฌ๋ Œ๋”๋ง ๋˜์—ˆ์„ ๋•Œ ๋™์ž‘ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— [update] ํ…์ŠคํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
Counter1 ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๋Š” ๋ฐ 24.00ms๊ฐ€ ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค.

Decr ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ Counter1 ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—…๋ฐ์ดํŠธ๋œ ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค.
์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋˜๋Š” ๊ฐ ์‹œ์ ์— ๊ทธ๋ž˜ํ”„์— ์ƒˆ๋กœ์šด ํ–‰์ด ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—ฌ๋Ÿฌ๋ฒˆ ๋ฆฌ๋ Œ๋”๋ง ๋˜๋Š” ์ƒํ™ฉ์—์„œ ์ด ๊ทธ๋ž˜ํ”„๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ƒํ™ฉ์„ ์ง„๋‹จํ•˜๋Š” ๊ฒƒ์ด ๋”์šฑ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค. ๋˜ํ•œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋  ๋•Œ ํ•„์š”ํ•œ ์‹œ๊ฐ„์„ ์ถ”์ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ–‰์ด ๊ธธ์ˆ˜๋ก, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋˜๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„๋„ ๊ธด ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‹ค์–‘ํ•œ ํŽ˜์ด์ง€๋“ค์„ ์ง„๋‹จํ•˜๋Š” ๋ฐ ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ณ  ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ๊ฒƒ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์„ธ์š”.

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”๊ฐ€?

์›๋ฌธ : https://blog.devgenius.io/how-javascript-works-behind-the-scenes-88c546173f32
๋ถ€์ œ : An overview walk-through of all the core components that are involved in the execution of JavaScript code.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ ์  ์ธ๊ธฐ๋ฅผ ๋” ๋Œ๊ฒŒ ๋˜๋ฉด์„œ ์—ฌ๋Ÿฌ ํŒ€๋“ค์€ ๋‹ค์–‘ํ•œ ์ˆ˜์ค€์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ™œ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ, ๋ฐฑ์—”๋“œ, ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์•ฑ, ์ž„๋ฒ ๋””๋“œ ๋””๋ฐ”์ด์Šค ๋“ฑ์—์„œ ๋ง์ด์ฃ . ์ด ์•„ํ‹ฐํด์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹ค์ œ๋กœ ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•ด ํŒŒ๋ณด๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ์š”

์•„๋งˆ ๋Œ€๋ถ€๋ถ„์€ V8 ์—”์ง„์˜ ๊ฐœ๋…์„ ๋“ค์–ด๋ดค์„ ๊ฒƒ์ด๋ฉฐ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‹จ์ผ ์Šค๋ ˆ๋“œ์ด๊ฑฐ๋‚˜ ์ฝœ๋ฐฑ ํ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” ์ด๋Ÿฌํ•œ ๊ฐœ๋…๋“ค์„ ์ž์„ธํ•˜๊ฒŒ ์‚ดํŽด๋ณด๊ณ  ์‹ค์ œ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์„ธ๋ถ€์‚ฌํ•ญ๋“ค์„ ์•Œ๊ฒŒ ๋œ๋‹ค๋ฉด, ์ œ๊ณต๋˜๋Š” API๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ํ™œ์šฉํ•จ์œผ๋กœ์จ ์ฐจ๋‹จ๋˜์ง€ ์•Š๋Š” ์•ฑ์„ ์ž˜ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋  ๊ฒ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์ด ๋น„๊ต์  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ฒ˜์Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด, ์ด ํฌ์ŠคํŠธ๋Š” ์™œ ๋‹ค๋ฅธ ์–ธ์–ด๋“ค์— ๋น„ํ•ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ "์ด์ƒํ•œ" ์–ธ์–ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š”์ง€ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋ฆฌ๋ผ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์—ฌ๋Ÿฌ๋ถ„์ด ๊ฒฝํ—˜์ด ์žˆ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ์—ฌ๋Ÿฌ๋ถ„์ด ๋งค์ผ ์‚ฌ์šฉํ•˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋Ÿฐํƒ€์ž„์ด ์‹ค์ œ๋กœ ๋™์ž‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์‹ ์„ ํ•œ ์ธ์‚ฌ์ดํŠธ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์•„ํ‹ฐํด์—์„œ ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ๊ณผ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ ์‹คํ–‰์— ๊ด€๋ จ๋œ ๋ชจ๋“  ํ•ต์‹ฌ์ ์ธ ๊ตฌ์„ฑ์š”์†Œ๋“ค์˜ ๊ฐœ์š”๊ฐ€ ๋  ๊ฒƒ์ด๋ฉฐ ์•„๋ž˜์˜ ์š”์†Œ๋“ค์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

  1. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„
  2. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ
  3. ์ฝœ์Šคํƒ
  4. ๋™์‹œ์„ฑ๊ณผ ์ด๋ฒคํŠธ ๋ฃจํ”„

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ด…์‹œ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„

์ด์ „์— ๋“ค์–ด๋ดค์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์ธํ„ฐํ”„๋ฆฌํ„ฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๋ฐ”์ด๋„ˆ๋ฆฌ ์ฝ”๋“œ๋กœ ์ปดํŒŒ์ผํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์˜ ์ปดํ“จํ„ฐ๋Š” ์ผ๋ฐ˜์ ์ธ ํ…์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์–ด๋–ป๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ผ๊นŒ์š”?

๊ทธ๊ฒƒ์ด ๋ฐ”๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ด ํ•˜๋Š” ์ผ์ž…๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋‹จ์ˆœํ•œ ์ปดํ“จํ„ฐ ํ”„๋กœ๊ทธ๋žจ์ž…๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ์˜ค๋Š˜๋‚  ๋ชจ๋“  ๋ชจ๋˜ ๋ธŒ๋ผ์šฐ์ €์— ๋‚ด์žฅ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์ด ๋ธŒ๋ผ์šฐ์ €์— ๋กœ๋“œ๋˜๋ฉด ์—”์ง„์€ ํŒŒ์ผ์„ ์œ„์—์„œ๋ถ€ํ„ฐ ์•„๋ž˜๋กœ ํ•œ์ค„์”ฉ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. (๊ฐ„๋‹จํžˆ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ํ˜ธ์ด์ŠคํŒ…์— ๋Œ€ํ•œ ์„ค๋ช…์€ ์ƒ๋žตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.) ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ์ฝ”๋“œ๋ฅผ ๋ผ์ธ๋งˆ๋‹ค ํŒŒ์‹ฑํ•˜์—ฌ ์ด๋ฅผ ๋จธ์‹  ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ๋ธŒ๋ผ์šฐ์ €๋Š” ๊ฐ์ž๋งŒ์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ด ์žˆ๋Š”๋ฐ ์ด ์ค‘ ๊ฐ€์žฅ ์ž˜ ์•Œ๋ ค์ง„ ์—”์ง„์€ ๊ตฌ๊ธ€์˜ V8์ž…๋‹ˆ๋‹ค. V8 ์—”์ง„์€ ๊ตฌ๊ธ€ ํฌ๋กฌ ๋ธŒ๋ผ์šฐ์ € ๋ฟ๋งŒ ์•„๋‹ˆ๋‹ค ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋Ÿฐํƒ€์ž„์ธ Node.js์—์„œ๋„ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

image

์—”์ง„์€ ๋‘ ๊ฐœ์˜ ํ•ต์‹ฌ ์š”์†Œ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

  • ๋ฉ”๋ชจ๋ฆฌ ํž™(memory heap) - ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ด ์ผ์–ด๋‚˜๋Š” ๊ณณ
  • ์ฝœ ์Šคํƒ(call stack) - ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค ์Šคํƒ ํ”„๋ ˆ์ž„์ด ์žˆ๋Š” ๊ณณ

์–ด๋–ค ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ด๋“  ์ฝœ์Šคํƒ๊ณผ ํž™์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝœ ์Šคํƒ์€ ์‹ค์ œ๋กœ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. ํž™์€ ๊ตฌ์กฐํ™”๋˜์ง€ ์•Š์€ ๋ฉ”๋ชจ๋ฆฌ ํ’€๋กœ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

๋Ÿฐํƒ€์ž„

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜๋Š”๋ฐ, ์‚ฌ์‹ค ์—”์ง„์€ ํ˜ผ์ž ๋™์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ(JRE)์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ํ™˜๊ฒฝ ๋‚ด์—์„œ ๋‹ค๋ฅธ ๊ตฌ์„ฑ์š”์†Œ๋“ค๊ณผ ํ•จ๊ป˜ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. JRE๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅด ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋งŒ๋“œ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์ด ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  HTTP ์š”์ฒญ๋“ค์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค.

JRE๋Š” ๋‹ค์Œ ๊ตฌ์„ฑ์š”์†Œ๋“ค๋กœ ์ด๋ฃจ์–ด์ง„ ํ•˜๋‚˜์˜ ์ปจํ…Œ์ด๋„ˆ์ž…๋‹ˆ๋‹ค.

  1. JS ์—”์ง„
  2. web api
  3. ์ฝœ๋ฐฑ ํ or ๋ฉ”์‹œ์ง€ ํ
  4. ์ด๋ฒคํŠธ ํ…Œ์ด๋ธ”
  5. ์ด๋ฒคํŠธ ๋ฃจํ”„

image

๊ทธ๋Ÿผ ์ด์ œ ์•„์ฃผ ์ธ๊ธฐ์žˆ๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„์™€ ์ฝœ๋ฐฑ ํ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝœ ์Šคํƒ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ธ๋ฐ ์ด๋Š” ํ•˜๋‚˜์˜ ์ฝœ ์Šคํƒ์„ ๊ฐ€์ง„๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ•œ๋ฒˆ์— ํ•œ ๊ฐ€์ง€๋งŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝœ ์Šคํƒ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ ๋‚ด ์œ„์น˜๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ๋‚ด๋ถ€๋กœ ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๋ฉด ์Šคํƒ์˜ ํƒ‘์— ํ•จ์ˆ˜๋ฅผ ๋†“์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋กœ๋ถ€ํ„ฐ ๋ฐ˜ํ™˜๋  ๋•Œ ์Šคํƒ์˜ ํƒ‘์—์„œ ํ•จ์ˆ˜๋ฅผ ๊บผ๋ƒ…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์Šคํƒ์ด ํ•˜๋Š” ์ „๋ถ€์ž…๋‹ˆ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ๋ด…์‹œ๋‹ค.

function multiply(x, y) {
    return x * y;
}function printSquare(x) {
    var s = multiply(x, x);
    console.log(s);
}printSquare(5);

์—”์ง„์ด ์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์‹œ์ž‘ํ•  ๋•Œ, ์ฝœ ์Šคํƒ์€ ๋น„์–ด์žˆ์„ ๊ฒ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๊ณ  ๋‚˜์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹จ๊ณ„๋กœ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค.

image

์ฝœ ์Šคํƒ์˜ ๊ฐ ์—”ํŠธ๋ฆฌ๋Š” ์Šคํƒ ํ”„๋ ˆ์ž„์ด๋ผ๊ณ  ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค.

์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ์—์„œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๋ฐ๋“œ๋ฝ๊ณผ ๊ฐ™์ด ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ณต์žกํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋‹ค๋ฃฐ ํ•„์š”๊ฐ€ ์—†์–ด ๊ฝค ์‰ฌ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ ๋˜ํ•œ ์ œ์•ฝ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ํ•˜๋‚˜์˜ ์ฝœ ์Šคํƒ์„ ๊ฐ€์ง€๋Š” ๊ฒƒ์ด์ฃ .

๋™์‹œ์„ฑ & ์ด๋ฒคํŠธ ๋ฃจํ”„

์ฝœ ์Šคํƒ์—์„œ ์ฒ˜๋ฆฌํ•  ๋•Œ ๊ต‰์žฅํžˆ ๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ• ๊นŒ์š”? ์˜ˆ๋ฅผ ๋“ค์–ด ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์•„์ฃผ ๋ณต์žกํ•œ ์ด๋ฏธ์ง€ ๋ณ€ํ™˜์„ ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์„ธ์š”. ์—ฌ๋Ÿฌ๋ถ„์€ ์ด๊ฒŒ ์™œ ๋ฌธ์ œ์ธ์ง€ ์˜๋ฌธ์ด ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ์ฝœ์Šคํƒ์ด ์‹คํ–‰ํ•  ํ•จ์ˆ˜๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋™์•ˆ ๋ธŒ๋ผ์šฐ์ €๋Š” ์•„๋ฌด๊ฒƒ๋„ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰ block๋˜์–ด ์žˆ์ฃ . ์ด๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ Œ๋”ํ•  ์ˆ˜ ์—†๊ณ  ๋‹ค๋ฅธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜๋„ ์—†์œผ๋ฉฐ ๋ง‰ํ˜€๋ฒ„๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์—ฌ๋Ÿฌ๋ถ„์ด ์œ ๋™์ ์ธ UI๋ฅผ ๊ทธ๋ฆฌ๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์— ๋ฌธ์ œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ๋งŒ์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์ผ๋‹จ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ฝœ ์Šคํƒ์—์„œ ๋งŽ์€ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ์ˆœ๊ฐ„ ๊ฝค ์˜ค๋žซ๋™์•ˆ ๋ฐ˜์‘ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ €๋Š” ์›น ํŽ˜์ด์ง€๋ฅผ ์ข…๋ฃŒํ•  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•ด ๋ฌป๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์กฐ์น˜๋ฅผ ์ทจํ•˜์ฃ . ๋™์‹œ์„ฑ๊ณผ ์ด๋ฒคํŠธ ๋ฃจํ”„์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์•„๋ž˜ ์•„ํ‹ฐํด์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด ๊นŠ๊ฒŒ ์ดํ•ดํ•˜๊ธฐ

์›๋ฌธ : Diving Deeper in JavaScripts Objects

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด๋Š” ์งง๊ณ  ๊ฐ„๊ฒฐํ•œ ๋ฌธ๋ฒ•์ด ๋“œ๋Ÿฌ๋‚ด๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๋งŽ์€ ๊ฒƒ๋“ค์„ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์‰ฝ๊ณ , ์–ด๋ ต์ง€ ์•Š๊ณ , ์œ ์—ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์ด ๊ฐ์ฒด์— ๋” ๋งŽ์€ ๊ฒƒ์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด์˜ ๊ฐ€๋ ค์ง„ ์ ๋“ค์„ ์‚ดํŽด๋ณด๊ณ  ๋ณต์žกํ•œ ์ ์„ ์ดํ•ดํ•ด๋ณผ ๊ฒ๋‹ˆ๋‹ค. ์ด ์•„ํ‹ฐํด์„ ์ฝ๊ณ  ๋‚˜๋ฉด ์—ฌ๋Ÿฌ๋ถ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์งˆ๋ฌธ๋“ค์— ๋‹ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์–ด๋–ป๊ฒŒ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ง€์šธ ์ˆ˜ ์—†๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€?
  • ํ”„๋กœํผํ‹ฐ ์ ‘๊ทผ์ž๋Š” ๋ฌด์—‡์ด๊ณ  ๊ทธ๋“ค์˜ ํŠน์ง•์€ ๋ฌด์—‡์ธ๊ฐ€?
  • ์–ด๋–ป๊ฒŒ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ฑฐ๋‚˜ ์ˆจ๊ธธ ์ˆ˜ ์žˆ๋Š”๊ฐ€?
  • ์™œ ์–ด๋–ค ํ”„๋กœํผํ‹ฐ๋“ค์€ for-in๋ฌธ์ด๋‚˜ Object.keys์— ๋ณด์ด์ง€ ์•Š๋Š”๊ฐ€?
  • ๋ณ€๊ฒฝ์œผ๋กœ๋ถ€ํ„ฐ ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ "๋ณดํ˜ธ"ํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€?
  • ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€?
obj.id = 5;
console.log(obj.id)
// => '101' ( 5 in binary )

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด์— ๋Œ€ํ•œ ๊ธฐ์ดˆ๋ฅผ ๋จผ์ € ๋ณด๊ณ  ์‹ถ๋‹ค๋ฉด ์ œ๊ฐ€ ์“ด ๋‹ค๋ฅธ ์•„ํ‹ฐํด์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

ํŒ : ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ์žฌ์‚ฌ์šฉํ•˜๋ ค๋ฉด Bit์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ์ด๋Š” ๋น ๋ฅด๊ฒŒ ๋นŒ๋“œํ•˜๊ณ  Lego์ฒ˜๋Ÿผ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœํผํ‹ฐ์˜ ํƒ€์ž…

๋ฐ์ดํ„ฐ ํ”„๋กœํผํ‹ฐ

์ด๋Ÿฐ ์‹์œผ๋กœ ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const obj = {
  name: 'Arfat',
  id: 5
}

obj.name  // => 'Arfat'

obj ๊ฐ์ฒด์—์„œ name๊ณผ id ํ”„๋กœํผํ‹ฐ๋Š” ๋ฐ์ดํ„ฐ ํ”„๋กœํผํ‹ฐ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ์ด๋ฃจ๋Š” ํ‰๋ฒ”ํ•œ ํ˜•ํƒœ์˜ ํ”„๋กœํผํ‹ฐ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๋‹ค๋ฅธ ํ”„๋กœํผํ‹ฐ ํƒ€์ž…์€ ๋ฌด์—‡์ผ๊นŒ์š”?

์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ (Accessor Properties)

C#์ด๋‚˜ ํŒŒ์ด์ฌ ๊ฐ™์€ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์น˜๋ฉด getter ์™€ setter ๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ์š”. ์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ๋Š” get๊ณผ set ํ•จ์ˆ˜, ๋‘ ๊ฐ€์ง€ ํ•จ์ˆ˜์˜ ์กฐํ•ฉ์ž…๋‹ˆ๋‹ค.

์ „ํ†ต์ ์ธ key: value ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹ ์— ๋‹ค์Œ์˜ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const accessorObj = {
  get name() {
    return 'Arfat';
  }
};

accessorObj.name; // => 'Arfat'

const dataObj = {
  name: 'Arfat',
};

dataObj.name; // => 'Arfat'

accessorObj์™€ dataObj๋ฅผ ๋ณด๋ฉฐ ๋น„๊ตํ•ด๋ณด์„ธ์š”. ๋‘ ๊ฐ์ฒด๋Š” ๋™์ผํ•œ ๋™์ž‘์„ ํ•ฉ๋‹ˆ๋‹ค. get ํ‚ค์›Œ๋“œ์— ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฝ์„ ๋•Œ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด ์†Œ๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ฆ‰, accessorObj.name(); ์œผ๋กœ ์“ฐ๋ฉด ํ‹€๋ฆฐ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

accessorObj.name์„ ์ฝ์„ ๋•Œ name ํ•จ์ˆ˜๋Š” ์‹คํ–‰๋˜์–ด name key์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

key์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ ์‚ฌ์šฉํ•˜์—ฌ get ํ•จ์ˆ˜๋Š” getter๋กœ ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์—ฌ๋Ÿฌ๋ถ„์ด accessorObj.name = 'New Person';๋กœ ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•˜๋ฉด ์‹ค์ œ๋กœ ๊ฐฑ์‹ ์ด ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. name ํ‚ค์— ํ•ด๋‹นํ•˜๋Š” setter ํ•จ์ˆ˜๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. setter ํ•จ์ˆ˜๋Š” getter ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’๋“ค์„ ์„ค์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

const accessorObj = {
  _name: 'Arfat',
  get name() {
    return this._name;
  },
  set name(value) {
    this._name = value;
  }
};

setter ํ•จ์ˆ˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ• ๋‹น๋œ ๊ฐ’์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. ํ”„๋กœํผํ‹ฐ์— ๊ฐ’์„ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ์ „์—ญ๋ณ€์ˆ˜๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—์„œ๋Š” ์ „ํ†ต์ ์ธ "private" ํ”„๋กœํผํ‹ฐ์ธ _name์„ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น ๊ฐ’์— name ๊ฐ’์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

getter ํ•จ์ˆ˜์—์„œ๋Š” ํ•ด๋‹น ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์ „์— ํ”„๋กœํผํ‹ฐ๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์ œ๊ฐ€ ์ด๋ฅผ ์„ค๋ช…ํ•ด์ค๋‹ˆ๋‹ค. ๋˜ํ•œ ์œ„ ์งˆ๋ฌธ๋“ค์— ๋Œ€ํ•œ ๋‹ต์„ ํ•˜๋‚˜ ํ•ด์ค๋‹ˆ๋‹ค.

const obj = {
  get name() {
    return this._name.toUpperCase();
  },
  set name(value) {
    this._name = value;
  },
  get id() {
    return this._id.toString(2); // Returns binary of a number
  },
  set id(value) {
    this._id = value;
  }
}

obj.name = 'Arfat';
obj.name;
// => 'ARFAT'

obj.id = 5;
obj.id;
// => '101

ํ‰๋ฒ”ํ•œ ๋ฐ์ดํ„ฐ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ๋Š”๋ฐ๋„ ์™œ ์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ์š”? ํ”„๋กœํผํ‹ฐ ์ ‘๊ทผ์„ ๊ธฐ๋กํ•˜๊ฑฐ๋‚˜ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ฐ€์ง„ ๊ฐ’๋“ค์— ๋Œ€ํ•œ ๊ธฐ๋ก์„ ์œ ์ง€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋“ค์ด ๊ฝค ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ๋Š” ๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ์˜ ์‚ฌ์šฉ์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜์˜ ํž˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ ‘๊ทผ์ž ์‚ฌ์šฉ์— ๋Œ€ํ•ด ๋” ์•Œ์•„๋ณด์‹œ๋ ค๋ฉด ์—ฌ๊ธฐ๋ฅผ ์ฝ์–ด๋ณด์„ธ์š”.

์–ด๋–ป๊ฒŒ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ์ธ์ง€ ๋ฐ์ดํ„ฐ ํ”„๋กœํผํ‹ฐ์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ์„๊นŒ์š”? ์•Œ์•„๋ด…์‹œ๋‹ค.

๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ ๋””์Šคํฌ๋ฆฝํ„ฐ

์–ธ๋œป ๋ณด๊ธฐ์—๋Š” ๊ฐ์ฒด์˜ ํ‚ค์™€ ๊ฐ’ ๊ฐ„์— 1:1 ๋งคํ•‘์ด ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ์ „ํ˜€ ์‚ฌ์‹ค์ด ์•„๋‹™๋‹ˆ๋‹ค.

ํ”„๋กœํผํ‹ฐ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ (Property Attributes)

๊ฐ์ฒด์˜ ๋ชจ๋“  ํ‚ค๋Š” ํ‚ค์— ๊ด€๋ จ๋œ ๊ฐ’์˜ ํŠน์„ฑ์„ ์ •์˜ํ•˜๋Š” ํ”„๋กœํผํ‹ฐ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ์˜ ์ง‘ํ•ฉ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. key-value ์Œ์„ ์„ค๋ช…ํ•˜๋Š” _๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ_๋กœ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์ฃ . ์งง๊ฒŒ ๋งํ•˜๋ฉด, ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋Š” ๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ์˜ ์ƒํƒœ๋ฅผ ์ •์˜ํ•˜๊ณ  ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

ํ”„๋กœํผํ‹ฐ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ์ง‘ํ•ฉ์€ ํ”„๋กœํผํ‹ฐ ๋””์Šคํฌ๋ฆฝํ„ฐ๋กœ ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค.

๋””์Šคํฌ๋ฆฝํ„ฐ์—๋Š” 6๊ฐ€์ง€์˜ ํ”„๋กœํผํ‹ฐ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • [[Value]]
  • [[Get]]
  • [[Set]]
  • [[Writable]]
  • [[Enumerable]]
  • [[Configurable]]

์™œ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ์ด๋ฆ„์ด [[]]๋กœ ๊ฐ์‹ธ์ ธ ์žˆ์„๊นŒ์š”? ๋‘ ๊ฐœ์˜ ๋Œ€๊ด„ํ˜ธ๋Š” ECMA ์ŠคํŽ™์— ๋”ฐ๋ผ **๋‚ด๋ถ€ ํ”„๋กœํผํ‹ฐ(internal properties)**๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ์ฝ”๋“œ ๋‚ด์—์„œ ์ง์ ‘์ ์œผ๋กœ ๊ฑด๋“œ๋ฆด ์ˆ˜ ์—†๋Š” ํ”„๋กœํผํ‹ฐ์ธ ๊ฒƒ์ด์ฃ . ๋‚ด๋ถ€ ํ”„๋กœํผํ‹ฐ๋ฅผ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์–ธ์–ด๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ๋ฅผ ๋ด…์‹œ๋‹ค.

์œ„ ์ด๋ฏธ์ง€์—์„œ ๊ฐ์ฒด๋Š” x, y 2๊ฐœ์˜ ํ‚ค๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ๊ฐ ํ”„๋กœํผํ‹ฐ์— ๋ฐ›๋Š” ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ๋ชฉ๋ก์„ ๋ณผ ์ˆ˜ ์žˆ์ฃ .

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์–ด๋–ป๊ฒŒ ๋™์ผํ•œ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์„๊นŒ์š”? Object.getOwnPropertyDescriptor ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ทธ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ์ฒด์™€ ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„์„ ๋ฐ›์•„์„œ ํ•„์š”ํ•œ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ๊ฐ–๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ ์ฝ”๋“œ ์ƒ˜ํ”Œ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

const object = {
  x: 5,
  y: 6
};

Object.getOwnPropertyDescriptor(object, 'x');
/* 
{ 
  value: 5, 
  writable: true, 
  enumerable: true, 
  configurable: true 
}
*/

์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์‚ดํŽด๋ณด๊ณ  ์–ด๋–ป๊ฒŒ ๋„์›€์ด ๋˜๋Š”์ง€ ์•Œ์•„๋ด…์‹œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ ์ด ์ด๋ฏธ์ง€๋กœ ์˜ค๊ฒ ์Šต๋‹ˆ๋‹ค.

[[Value]]

ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ–ˆ์„ ๋•Œ ๋ฐ˜ํ™˜๋˜๋Š” value๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์œ„ ์˜ˆ์—์„œ object.x๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋ ค ํ•  ๋•Œ ์‚ฌ์‹ค์€ [[Value]] ์–ดํŠธ๋ฆฌ๋ทฐํŠธ์—์„œ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด์ฃ . ๋ฐ์ดํ„ฐ ํ”„๋กœํผํ‹ฐ์—์„œ .์œผ๋กœ ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ []์œผ๋กœ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ๋„ ์ด๋Ÿฐ ์‹์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

[[Get]]

getter ํ”„๋กœํผํ‹ฐ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์„ ์–ธํ•˜๋Š” ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•ด ์ ‘๊ทผํ•  ๋•Œ๋งˆ๋‹ค ํ”„๋กœํผํ‹ฐ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ๋นˆ ์ธ์ˆ˜ ๋ฆฌ์ŠคํŠธ์™€ ํ•จ๊ป˜ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

[[Set]]

setter ํ”„๋กœํผํ‹ฐ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์„ ์–ธํ•œ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•ด ์ ‘๊ทผํ•  ๋•Œ๋งˆ๋‹ค ํ• ๋‹น๋œ ๊ฐ’์„ ํฌํ•จํ•œ ์ธ์ˆ˜ ๋ชฉ๋ก์„ ์œ ์ผํ•œ ์ธ์ˆ˜๋กœ ํ•จ๊ป˜ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

  set x(val) {
    console.log(val) // => 23
  }
}

obj.x = 23;

์œ„ ์˜ˆ์—์„œ ํ• ๋‹น๋ฌธ์˜ ์˜ค๋ฅธ์ชฝ์˜ ๊ฐ’์€ setter ํ•จ์ˆ˜์— var ์ธ์ž๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. ์ฆ๊ฑฐ๋กœ ์ด ์ฝ”๋“œ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

[[Writable]]

์ด ๊ฐ’์€ boolean ํƒ€์ž…์ž…๋‹ˆ๋‹ค. ๊ฐ’์„ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ๋Š”์ง€ ์•„๋‹Œ์ง€์— ๋Œ€ํ•œ ๊ฐ’์ด์ฃ . false์ธ ๊ฒฝ์šฐ์—๋Š” ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

[[Enumerable]]

์ด ๊ฐ’๋„ boolean ํƒ€์ž…์ž…๋‹ˆ๋‹ค. ์ด ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋Š” for-in ๋ฃจํ”„์—์„œ ๋ณด์ด๋Š”์ง€ ์•„๋‹Œ์ง€๋ฅผ ์•Œ๋ ค์ค๋‹ˆ๋‹ค. ๋งŒ์•ฝ true๋ผ๋ฉด for-in ๋ฃจํ”„๋ฌธ์—์„œ ์ด ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ฐ˜๋ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

[[Configurable]]

์ด ๊ฐ’ ์—ญ์‹œ boolean์ž…๋‹ˆ๋‹ค.

์ด ๊ฐ’์ด false๋ผ๋ฉด

  • ํ”„๋กœํผํ‹ฐ์˜ ์‚ญ์ œ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋˜ํ•œ ๋ฐ์ดํ„ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ๋กœ ๋˜๋Š” ๊ทธ ๋ฐ˜๋Œ€๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ๋„ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ ๋‘ ํ”„๋กœํผํ‹ฐ ํƒ€์ž…์˜ ๋ณ€ํ™˜์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ๊ฐ’์„ ๋ฐ”๊พธ๋Š” ๊ฒƒ๋„ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. enumerable configurable get set ๋ชจ๋‘ ๊ณ ์ •๋œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.

์ด ํ”„๋กœํผํ‹ฐ์˜ ์˜ํ–ฅ์€ ํ”„๋กœํผํ‹ฐ ํƒ€์ž…์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์œ„์— ์„ค๋ช…ํ•œ ํŠน์ง•๊ณผ ๋ณ„๋„๋กœ ๋˜ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์ง•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ฐ์ดํ„ฐ ํ”„๋กœํผํ‹ฐ๋ผ๋ฉด, writable์€ true์—์„œ false๋กœ๋งŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • writable์ด false๊ฐ€ ๋˜๊ธฐ ์ „์—, [[Value]] ์–ดํŠธ๋ฆฌ๋ทฐํŠธ์˜ ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•œ๋ฒˆ writable์ด false๊ฐ€ ๋˜๋ฉด configurable ๋˜ํ•œ false๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ํ”„๋กœํผํ‹ฐ๊ฐ€ ์“ธ ์ˆ˜ ์—†๊ณ  ์‚ญ์ œํ•  ์ˆ˜ ์—†๊ณ  ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋˜๋Š” ๊ฒ๋‹ˆ๋‹ค.

6๊ฐ€์ง€ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ ํƒ€์ž…์— ์กด์žฌํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

  • ๋ฐ์ดํ„ฐ ํ”„๋กœํผํ‹ฐ์˜ ๊ฒฝ์šฐ value writable enumerable configurable ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ์˜ ๊ฒฝ์šฐ value๋‚˜ writable ๋Œ€์‹ ์— get set์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋””์Šคํฌ๋ฆฝํ„ฐ ์‚ฌ์šฉํ•˜๊ธฐ

๋””์Šคํฌ๋ฆฝํ„ฐ์— ๋Œ€ํ•ด ๋ฐฐ์› ๋Š”๋ฐ ์ด์ œ ์šฐ๋ฆฌ์˜ ๊ฐ์ฒด์˜ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์„ค์ •ํ•˜๊ณ  ๋ณ€๊ฒฝํ• ๊นŒ์š”? ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—๋Š” ์ด ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋Ÿฌ ํ•จ์ˆ˜๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ดํŽด๋ด…์‹œ๋‹ค.

Obejct.getOwnPropertyDescriptor

์œ„์—์„œ ๋ดค๋˜ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ฐ์ฒด์™€ ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„์„ ๋ฐ›์•„ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ํฌํ•จํ•œ ๊ฐ์ฒด๋‚˜ undefined๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

Object.defineProperty

Object์˜ static ๋ฉ”์†Œ๋“œ๋กœ ์ฃผ์–ด์ง„ ๊ฐ์ฒด์— ๋Œ€ํ•ด ์ƒˆ๋กœ์šด ํ”„๋กœํผํ‹ฐ๋ฅผ ์ •์˜ํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์ฒด, ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„, ๋””์Šคํฌ๋ฆฝํ„ฐ ์„ธ ๊ฐ€์ง€ ์ธ์ˆ˜๋ฅผ ๋ฐ›๊ณ  ๋ณ€๊ฒฝ๋œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ๋ฅผ ๋ด…์‹œ๋‹ค.

const obj = {};

Object.defineProperty(obj, 'id', {
  value: 42
});

console.log(obj);
// => { }

console.log(obj.id);
// => 42

Object.defineProperty(obj, 'name', {
  value: 'Arfat',
  writable: false,
  enumerable: true,
  configurable: true
});

console.log(obj.name);
// => 'Arfat'

obj.name = 'Arfat Salman'

console.log(obj.name);
// => 'Arfat' 
// (instead of 'Arfat Salman')

Object.defineProperty(obj, 'lastName', {
  value: 'Salman',
  enumerable: false,
});

console.log(Object.keys(obj));
// => [ 'name' ]

delete obj.id;

console.log(obj.id);
// => 42

Object.defineProperties(obj, {
  property1: {
    value: 42,
    writable: true
  },
  property2: {}
});

console.log(obj.property1)
// => 42

๊ธธ์–ด๋ณด์ด์ง€๋งŒ ์‚ฌ์‹ค์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณผ๊นŒ์š”.

  • ์„ธ ๋ฒˆ์งธ ์ค„์—์„œ, obj์™€ ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„ id, [[Value]] ํ•„๋“œ๋ฅผ ์˜๋ฏธํ•˜๋Š” value ํ‚ค์— 42 ๊ฐ’์„ ๊ฐ€์ง€๋Š” ๋””์Šคํฌ๋ฆฝํ„ฐ ์„ธ ๊ฐ€์ง€ ์ธ์ˆ˜๋ฅผ defineProperty๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  • enumberable์ด๋‚˜ configurable๊ณผ ๊ฐ™์€ ํ”„๋กœํผํ‹ฐ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋ฉด ๊ธฐ๋ณธ ๊ฐ’์œผ๋กœ false๋กœ ์„ค์ •๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์„ธ์š”. ์ด ๊ฒฝ์šฐ์—๋Š” writable, enumerable, configurable ๋ชจ๋‘ false๋กœ ์„ค์ •๋˜์–ด ์žˆ๋Š” id๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • 7๋ฒˆ์งธ ์ค„์—์„œ obj๋ฅผ ์ถœ๋ ฅํ•˜์ง€๋งŒ id ํ”„๋กœํผํ‹ฐ๊ฐ€ ์—ด๊ฑฐ ๋ถˆ๊ฐ€๋Šฅํ•œ ์†์„ฑ์ด๋ฏ€๋กœ ์ถœ๋ ฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ 10๋ฒˆ์งธ ์ค„์—์„œ ๋ณด์ด๋“ฏ์ด ํ”„๋กœํผํ‹ฐ๋Š” ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.
  • 13๋ฒˆ์งธ ์ค„์—์„œ ์ „์ฒด ๋””์Šคํฌ๋ฆฝํ„ฐ ์ง‘ํ•ฉ์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. writable์„ false๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • 20๋ฒˆ์งธ ์ค„๊ณผ 25๋ฒˆ์งธ ์ค„์—์„œ name ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. 23๋ฒˆ์งธ ์ค„์—์„œ ๊ฐ’์„ ์ˆ˜์ •ํ–ˆ์ง€๋งŒ non-writabilityํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜์ • ํšจ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ธฐ์กด์˜ ๊ฐ’์ด ๋‘ ๋ฒˆ ๋ณด์ด๋Š” ๊ฑฐ์ฃ .
  • 37๋ฒˆ ์งธ ์ค„์—์„œ id๋ฅผ ์ œ๊ฑฐํ•˜๋ ค ํ•˜์ง€๋งŒ configurable์ด false๋กœ ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 39๋ฒˆ์งธ ์ค„์—์„œ ๋ณด์ด๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ œ๊ฑฐ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
  • 42๋ฒˆ์งธ ์ค„์—์„œ defineProperty ์˜ ๋ฐฐ์น˜ ๋ฒ„์ „์ธ Object.defineProperties๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

Object.defineProperty๋Š” ํ•œ๋ฒˆ์— ํ•˜๋‚˜์˜ ํ”„๋กœํผํ‹ฐ๋งŒ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ค์ •ํ•˜๋ ค๋ฉด Object.defineProperties๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์ฒด์˜ ๋ณดํ˜ธ

์•„๋ฌด๋„ ๊ฐ์ฒด๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์œ ์—ฐ์„ฑ ๋•๋ถ„์— ๊ฑด๋“œ๋ฆฌ๋ ค๊ณ  ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ์‹ค์ˆ˜๋กœ ๊ฐ์ฒด์— ํ”„๋กœํผํ‹ฐ๋ฅผ ํ• ๋‹นํ•˜๊ธฐ๊ฐ€ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ฐ์ฒด๋ฅผ ๋ณดํ˜ธํ•˜๋Š” ์ฃผ์š” 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ด…์‹œ๋‹ค.

Object.preventExtensions

Object.preventExtensions ๋ฉ”์†Œ๋“œ๋Š” ๊ฐ์ฒด์— ํ”„๋กœํผํ‹ฐ๋ฅผ ๋”ํ•˜์—ฌ ์ƒˆ๋กœ์šด ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„ ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ํ™•์žฅ๋˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ญ์ œํ•˜๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•˜๋‹ˆ ์ฃผ์˜ํ•˜์„ธ์š”.

const obj = {
  id: 42
};

Object.preventExtensions(obj);

obj.name = 'Arfat';
console.log(obj); // => { id: 42 } 

Object.isExtensible์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด๊ฐ€ ํ™•์žฅ ๋ถˆ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋ฉด ํ•ด๋‹น ๊ฐ์ฒด์— ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์ฃ .

Object.seal

seal ๋ฉ”์†Œ๋“œ๋Š” ๊ฐ์ฒด๋ฅผ ๋ด‰์ธํ•ฉ๋‹ˆ๋‹ค. ๋ด‰์ธํ•œ๋‹ค๋Š” ๊ฒƒ์€ -

  • Object.preventExtensions์™€ ๊ฐ™์ด ์ƒˆ๋กœ์šด ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์Šต๋‹ˆ๋‹ค.
  • ์กด์žฌํ•˜๋Š” ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๋ฅผ non-configurableํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  • ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’๋“ค์ด writableํ•œ ๊ฒฝ์šฐ๋ผ๋ฉด ์—ฌ์ „ํžˆ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ์ฆ‰, ํ”„๋กœํผํ‹ฐ์˜ ์ถ”๊ฐ€ ๋ฐ ์‚ญ์ œ๋ฅผ ๋ง‰๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
const obj = {
  id: 42
};
Object.seal(obj);
delete obj.id  // (does not work)
obj.name = 'Arfat'; // (does not work)
console.log(obj); // => { id: 42 }
Object.isExtensible(obj); // => false
Object.isSealed(obj); //=> true

๊ฐ์ฒด๊ฐ€ ๋ด‰์ธ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด Object.isSealed๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

Object.freeze

freeze๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ฐ์ฒด๊ฐ€ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ํฐ ๋ณดํ˜ธ๋ง‰์ž…๋‹ˆ๋‹ค.

  • Object.freeze๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ๋ด‰์ธํ•ฉ๋‹ˆ๋‹ค.
  • ์กด์žฌํ•˜๋Š” ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ์˜ _๋ณ€๊ฒฝ_์„ ๋ง‰์Šต๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด๊ฐ€ ๋ด‰์ธ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋””์Šคํฌ๋ฆฝํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ๋„ ๋ง‰์Šต๋‹ˆ๋‹ค.
const obj = {
  id: 42
};

Object.freeze(obj);
delete obj.id  // (does not work)
obj.name = 'Arfat'; // (does not work)
console.log(obj); // => { id: 42 }
Object.isExtensible(obj); // => false
Object.isSealed(obj); //=> true
Object.isFrozen(obj); // => true

Object.isFrozen์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด๊ฐ€ ์–ผ์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•œ ์ ์€ ์ด ๋ฉ”์†Œ๋“œ๋“ค์€ ๊ฐ์ฒด์˜ ์ง์ ‘์ ์ธ ํ”„๋กœํผํ‹ฐ๋งŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ค‘์ฒฉ๋œ ๊ฐ์ฒด์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

ํ…Œ์ด๋ธ” ํ‘œ๋กœ ์ •๋ฆฌ๋œ ๊ฒƒ์„ ๋ณด์‹ญ์‹œ์˜ค.

๊ฒฐ๋ก 

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ฐ์ฒด๋Š” ๊ต‰์žฅํžˆ ํ”ํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด์˜ ์ง„์งœ ํž˜์„ ์•„๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด ์•„ํ‹ฐํด์ด ํšจ๊ณผ์ ์œผ๋กœ ์ž˜ ์ „๋‹ฌ๋˜์—ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋˜ํ•œ ์•„ํ‹ฐํด ์ดˆ๋ฐ˜์— ์žˆ๋˜ ์งˆ๋ฌธ๋“ค์— ๋Œ€ํ•ด ์ด์ œ ๋‹ต์„ ํ•˜์‹ค ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค. ์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

[LIST] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ปจ์…‰ 33๊ฐ€์ง€ ๊ด€๋ จ

์ถœ์ฒ˜

1. Call Stack

Reference

Articles

Videos


2. Primitive Types

Reference

Articles

Videos


3. Value Types and Reference Types

Articles

Videos


4. Implicit, Explicit, Nominal, Structuring and Duck Typing

Articles

Videos

Books


5. == vs === vs typeof

Articles

Videos


6. Function Scope, Block Scope and Lexical Scope

Books

Articles

Videos


7. Expression vs Statement

Articles

Videos


8. IIFE, Modules and Namespaces

Articles

Videos


9. Message Queue and Event Loop

Articles

Videos


10. setTimeout, setInterval and requestAnimationFrame

Articles

Videos


11. JavaScript Engines

Articles

Videos


12. Bitwise Operators, Type Arrays and Array Buffers

Articles

Videos


13. DOM and Layout Trees

Books

Articles

Videos


14. Factories and Classes

Articles

Videos


15. this, call, apply and bind

Reference

Articles

Videos


16. new, Constructor, instanceof and Instances

Articles


17. Prototype Inheritance and Prototype Chain

Reference

Articles

Videos

Books


18. Object.create and Object.assign

Reference

Articles

Videos


19. map, reduce, filter

Articles

Videos


20. Pure Functions, Side Effects, State Mutation and Event Propagation

Articles

Videos


21. Closures

Reference

Articles

Videos


22. High Order Functions

Books

Articles

Videos


23. Recursion

Articles

Videos


24. Collections and Generators

Reference

Articles

Videos


25. Promises

Reference

Articles

Videos


26. async/await

Reference

Books

Articles

Videos


27. Data Structures

Articles

Videos


28. Expensive Operation and Big O Notation

Articles

Videos


29. Algorithms

Articles


30. Inheritance, Polymorphism and Code Reuse

Reference

Articles

Videos


31. Design Patterns

Books

Articles

Videos


32. Partial Applications, Currying, Compose and Pipe

Books

Articles

Videos


33. Clean Code

Articles

Videos

[๋ฒˆ์—ญ] BFF(Backend for Frontend)๋ž€?

๋ถ€์ œ : Get to know the benefits of using the BFF pattern in practice
์›๋ฌธ : https://blog.bitsrc.io/bff-pattern-backend-for-frontend-an-introduction-e4fa965128bf

์—ฌ๋Ÿฌ๋ถ„์ด ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•œ ์ด์ปค๋จธ์Šค ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ ๋‹ค๊ณ  ์ƒ์ƒํ•ด๋ณด์„ธ์š”. ๊ณ ๊ฐ, ์ฃผ๋ฌธ, ๋ฌผ๊ฑด, ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋“ฑ์— ๋Œ€ํ•œ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๊ฐ€ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๋Š” ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ์‚ฌ์šฉํ•˜๋Š” API๋ฅผ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ”„๋ก ํŠธ์—”๋“œ์— ๋ฐ˜ํ™˜๋˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ์ •ํ™•ํžˆ ์›ํ•˜๋Š” ๋Œ€๋กœ ํฌ๋งทํŒ…๋˜๊ฑฐ๋‚˜ ํ•„ํ„ฐ๋ง ๋˜์–ด ์žˆ์ง€ ์•Š์„ ๊ฒ๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๊ฒฝ์šฐ์— ํ”„๋ก ํŠธ์—”๋“œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ํฌ๋งทํŒ…ํ•  ์ˆ˜ ์žˆ๋Š” ๋กœ์ง์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ์— ์ด๋Ÿฐ ๋กœ์ง์ด ๋‹ด๊ธฐ๋ฉด ๋” ๋งŽ์€ ๋ธŒ๋ผ์šฐ์ € ์ž์›์ด ์†Œ๋ชจ๋ฉ๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ์šฐ๋ฆฌ๋Š” ํ”„๋ก ํŠธ์—”๋“œ ๋กœ์ง์„ ์ค‘๊ฐ„ ๋ ˆ์ด์–ด๋กœ ์˜ฎ๊ธฐ๊ณ ์ž ํ•˜๋Š” ๋ชฉ์ ์œผ๋กœ BFF๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ค‘๊ฐ„ ์ธต์ด BFF์ธ ๊ฒƒ์ด์ฃ . ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ํŠน์ • ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๋ฉด BFF์—์„œ API๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

BFF๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์ผ์„ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • ๊ด€๋ จ๋œ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค API๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.
  • ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ํฌ๋งทํŒ…ํ•ฉ๋‹ˆ๋‹ค.
  • ํฌ๋งทํŒ…๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํ”„๋ก ํŠธ์—”๋“œ๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ ํ”„๋ก ํŠธ์—”๋“œ์—๋Š” ๋” ์ ์€ ๋กœ์ง๋งŒ์ด ๋‚จ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ BFF๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๊ฒƒ์„ ๋Šฅ๋ฅ ์ ์œผ๋กœ ํ•ด์ฃผ๊ณ  ํ”„๋ก ํŠธ์—”๋“œ์— ์ดˆ์ ์„ ๋งž์ถ˜ ์ธํ„ฐํŽ˜์ด์Šค ์ œ๊ณต์ž์˜ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐฑ์—”๋“œ-ํ”„๋ก ํŠธ์—”๋“œ ๊ด€๊ณ„๋Š” ๋” ๋‹จ์ˆœํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๋‹ค๋ฅธ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๊ทธ๋“ค๋ผ๋ฆฌ ํƒ€์ž…์„ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฒฐํ•ฉ๋˜์ง€ ์•Š์€ ํ”„๋กœ์ ํŠธ ์‚ฌ์ด์—์„œ ํƒ€์ž…(๋˜๋Š” ์ฝ”๋“œ ์กฐ๊ฐ)์„ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•ด ์–ด๋–ป๊ฒŒ Bit์„ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์„ธ์š”.

์–ด๋–ป๊ฒŒ ์ด์ปค๋จธ์Šค ์˜ˆ์ œ์— ์ ํ•ฉํ•œ๊ฐ€?

์•„๋ž˜ ๋‹ค์ด์–ด๊ทธ๋žจ์€ ๊ฐ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๊ฐ€ BFF๋ฅผ ํ†ตํ•ด ํ”„๋ก ํŠธ์—”๋“œ์™€ ์—ฐ๊ฒฐ๋˜๋Š” ๊ตฌ์กฐ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

image

BFF์˜ ์—ญํ• 

์ด๋ฏธ ์œ„์—์„œ ๋ดค๋“ฏ์ด, BFF๋Š” ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์‚ฌ์ด์—์„œ ๋‹จ์ˆœํ•œ ์ธํ„ฐํŽ˜์ด์Šค ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ, ํ”„๋ก ํŠธ์—”๋“œ ํŒ€์€ BFF๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ฑ…์ž„์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

ํ•˜๋‚˜์˜ BFF๋Š” ํ•˜๋‚˜์˜ UI์— ๋Œ€ํ•ด๋งŒ ์ดˆ์ ์ด ๋งž์ถฐ์ง‘๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ๋‹จ์ˆœํ•˜๊ฒŒ ํ•˜๊ณ  ๋ฐฑ์—”๋“œ๋ฅผ ํ†ตํ•œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด ์ผ๊ด€๋œ ๋ทฐ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋‹ค์Œ ์งˆ๋ฌธ์ด ๋‚˜์˜ค๊ฒ ์ฃ . ์—ฌ๋Ÿฌ UI์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ BFF๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ๊ฑธ๊นŒ์š”? ์ด ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต์€ ์ด ์•„ํ‹ฐํด ๋งˆ์ง€๋ง‰ ์„น์…˜์—์„œ ๋‹ตํ•ด๋“œ๋ฆฌ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ณ„์† ์ฝ์–ด์ฃผ์„ธ์š”. ๐Ÿ˜Š

BFF๋Š” latency(๋Œ€๊ธฐ์‹œ๊ฐ„)๋ฅผ ์ฆ๊ฐ€์‹œํ‚ฌ๊นŒ?

BFF๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ๋‹ค๋ฅธ ์™ธ๋ถ€ API, ์„œ๋น„์Šค ๋“ฑ ์‚ฌ์ด์—์„œ ํ•˜๋‚˜์˜ ํ”„๋ก์‹œ ์„œ๋ฒ„์˜ ์—ญํ• ์„ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์š”์ฒญ์ด ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋‹น์—ฐํžˆ ๋Œ€๊ธฐ์‹œ๊ฐ„์„ ์ฆ๊ฐ€์‹œํ‚ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ BFF์˜ ๋Œ€๊ธฐ์‹œ๊ฐ„์€ ํ”„๋ก ํŠธ์—”๋“œ์— ์ตœ์ ํ™”๋˜์ง€ ์•Š์€ ์—ฌ๋Ÿฌ ์„œ๋น„์Šค๋ฅผ ์œ„ํ•ด ๋ธŒ๋ผ์šฐ์ €์˜ ๋งŽ์€ ์ž์›์„ ์†Œ๋น„ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์— ๋น„ํ•˜๋ฉด ์ถฉ๋ถ„ํžˆ ๋ฌด์‹œํ•  ๋งŒํ•œ ์ •๋„์ž…๋‹ˆ๋‹ค.

BFF๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋‹ค๋ฅธ ๋ฐฑ์—”๋“œ/๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์— ๋Œ€ํ•ด ์ง€๋Šฅ์ ์ธ ๋ฐฐ์น˜ ํ˜ธ์ถœ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ณ  ํ•œ๋ฒˆ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€ํ™˜ํ•˜์—ฌ ๋” ํŽธ๋ฆฌํ•œ ํ‘œํ˜„์‹์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด๋Š” ํ•œ ์ปค๋„ฅ์…˜์„ ๋งŒ๋“œ๋Š”๋ฐ ์ˆ˜ ์ดˆ๊ฐ€ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋Š” 2G๋‚˜ 3G ๋„คํŠธ์›Œํฌ์˜ ๋ชจ๋ฐ”์ผ ํด๋ผ์ด์–ธํŠธ๋“ค์—๊ฒŒ ๊ต‰์žฅํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

BFF ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ

๋‹ค๋ฅธ ํŒจํ„ด๋“ค๊ณผ ๊ฐ™์ด, ์—ฌ๋Ÿฌ๋ถ„์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ BFF๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ปจํ…์ŠคํŠธ์™€ ์—ฌ๋Ÿฌ๋ถ„์ด ๋”ฐ๋ฅด๊ณ ์ž ํ•˜๋Š” ์•„ํ‚คํ…์ฒ˜์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์—ฌ๋Ÿฌ๋ถ„์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‹จ์ˆœํ•œ ๋ชจ๋†€๋ฆฌํ‹ฑ ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฅธ๋‹ค๋ฉด BFF๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐ€์น˜๊ฐ€ ๊ฑฐ์˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์— ์˜์กดํ•˜๊ณ  ๋งŽ์€ ์™ธ๋ถ€ API๋‚˜ ๋‹ค๋ฅธ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด, ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ๊ฐ„์†Œํ™”ํ•˜๊ณ  ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋งŽ์€ ํšจ์œจ์„ฑ์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ BFF๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋”๋ถˆ์–ด, ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํŠน์ • ํ”„๋ก ํŠธ์—”๋“œ ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•ด ์ตœ์ ํ™”๋œ ๋ฐฑ์—”๋“œ๋ฅผ ๊ฐœ๋ฐœํ•ด์•ผ ํ•˜๊ฑฐ๋‚˜ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ต‰์žฅํžˆ ๋งŽ์€ ์–‘์˜ ์ง‘ํ•ฉ ์—ฐ์‚ฐ์„ ์š”๊ตฌํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด BFF๋Š” ๊ฝค ์ ์ ˆํ•œ ์„ ํƒ์ง€๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ๊ฐœ์˜ BFF๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์„๊นŒ?

๊ทธ๋Ÿผ์š”! ๊ทธ๊ฒƒ์ด ๋ฐ”๋กœ BFF๋ฅผ ์„ ํƒํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ „ํ†ต์ ์ธ ์ ‘๊ทผ๋ฐฉ์‹(BFF๊ฐ€ ์—†๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜)์€ ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ์— ๋Œ€ํ•ด ๋‹จ ํ•˜๋‚˜์˜ API ๊ฒŒ์ดํŠธ์›จ์ด๋งŒ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ฃ .

image

๊ทธ๋Ÿฌ๋‚˜ BFF๋ฅผ ๋งŒ๋“œ๋Š” ๋ชฉ์ ์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ํด๋ผ์ด์–ธํŠธ์— ๋” ๋งž์ถฐ์ง„ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ชจ๋ฐ”์ผ UI์— ์˜ํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ฐจ์ด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์—์„œ ๋” ๋‚˜์€ ๋ฐ์ดํ„ฐ ํ‘œํ˜„๋ฐฉ์‹์„ ์œ„ํ•ด ๋‘ ๊ฐœ์˜ BFF๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ BFF๋ฅผ ๊ฐ€์ง€๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‹ค์ด์–ด๊ทธ๋žจ์„ ์‚ดํŽด๋ด…์‹œ๋‹ค.

image

์—ฌ๋Ÿฌ๋ถ„์ด ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด, ๊ฐ ํด๋ผ์ด์–ธํŠธ๋Š” BFF๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์„œ๋น„์Šค์— ๋Œ€ํ•œ ์‘๋‹ต๊ฐ’๋“ค์„ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.

BFF์˜ ์žฅ์ 

  • ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ - ํ”„๋ก ํŠธ์—”๋“œ ์š”๊ตฌ์‚ฌํ•ญ์€ ๋ฐฑ์—”๋“œ ๊ด€์‹ฌ์‚ฌ๋กœ๋ถ€ํ„ฐ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ๊ฐ€ ์‰ฝ์Šต๋‹ˆ๋‹ค.
  • API ์œ ์ง€๋ณด์ˆ˜์™€ ๋ณ€๊ฒฝ์— ์šฉ์ด - ํด๋ผ์ด์–ธํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ API ๊ตฌ์กฐ์— ๋Œ€ํ•ด ์•Œ์•„์•ผ ํ•˜๋Š” ๊ฒƒ์„ ์ค„์ด๋ฏ€๋กœ ์ด๋Š” API ๋ณ€๊ฒฝ์‚ฌํ•ญ์— ๋Œ€ํ•ด ๋” ํƒ„๋ ฅ์„ฑ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
  • ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ๋” ๋‚˜์€ ์—๋Ÿฌ ํ•ธ๋“ค๋ง ๊ฐ€๋Šฅ - ๋Œ€๋ถ€๋ถ„์˜ ์‹œ๊ฐ„์—์„œ ์„œ๋ฒ„ ์—๋Ÿฌ๋Š” ํ”„๋ก ํŠธ์—”๋“œ ์œ ์ €์—๊ฒŒ ์˜๋ฏธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ๋ณด๋‚ด๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐ”๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค๋Š” BFF๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ฃผ์–ด์•ผ ํ•˜๋Š” ์—๋Ÿฌ์™€ ๋งคํ•‘ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” UX๋ฅผ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ณ‘๋ ฌ์ ์œผ๋กœ ์—ฌ๋Ÿฌ ๋””๋ฐ”์ด์Šค ํƒ€์ž…์—์„œ ๋ฐฑ์—”๋“œ ํ˜ธ์ถœ - ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ธŒ๋ผ์šฐ์ € BFF์— ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๋™์•ˆ ๋ชจ๋ฐ”์ผ ๋””๋ฐ”์ด์Šค๋“ค์€ ๋™์ผํ•œ ๊ฒƒ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์„œ๋น„์Šค๋กœ๋ถ€ํ„ฐ ๋” ๋นจ๋ฆฌ ์‘๋‹ต๊ฐ’์„ ์–ป๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • ๋” ๋‚˜์€ ๋ณด์•ˆ์„ฑ - ํŠน์ • ๋ฏผ๊ฐํ•œ ์ •๋ณด๋Š” ์ˆจ๊ธฐ๋ฉด์„œ ๋™์‹œ์— ํ”„๋ก ํŠธ์—”๋“œ์— ์‘๋‹ต๊ฐ’์„ ๋ณด๋‚ผ ๋•Œ ๋ถˆํ•„์š”ํ•œ ์ •๋ณด๋Š” ์ƒ๋žต๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ถ”์ƒํ™”๋Š” ๊ณต๊ฒฉ์ž๋“ค์ด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํƒ€๊ฒŸํŒ…ํ•˜๋Š” ๊ฒƒ์„ ์–ด๋ ต๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ปดํฌ๋„ŒํŠธ์˜ ์†Œ์œ ๊ถŒ ๊ณต์œ  - ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‹ค์–‘ํ•œ ํŒŒํŠธ๋“ค์ด ์‰ฝ๊ฒŒ ์„œ๋กœ ๋‹ค๋ฅธ ํŒ€๋“ค์— ์˜ํ•ด ๋‹ค๋ค„์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ ํŒ€์€ ํด๋ผ์ด์–ธํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๋ฆฌ์†Œ์Šค ์†Œ๋น„์ธต์— ๋Œ€ํ•ด ์†Œ์œ ๊ถŒ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ด๋Š” ๋” ๋น ๋ฅธ ๊ฐœ๋ฐœ์†๋„๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์•„๋ž˜ ๋‹ค์ด์–ด๊ทธ๋žจ์€ BFF์— ๋”ฐ๋ผ ํŒ€์ด ๋ถ„๋ฆฌ๋˜๋Š” ์˜ˆ์ œ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

image

BFF์— ๋Œ€ํ•œ ๋ชจ๋ฒ” ์‚ฌ๋ก€

BFF์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋Š” ๋™์•ˆ ๋†€๋ผ์šด ๊ฒƒ๋“ค์ด ๋งŽ์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ BFF๋Š” ๋ชจ๋“  ์œ„ํ—˜์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?
๋Œ€๋‹ต์€ '์•„๋‹ˆ์˜ค'์ž…๋‹ˆ๋‹ค! ๋ชจ๋“  ๋‹ค๋ฅธ ๊ธฐ์ˆ ์ด๋‚˜ ํŒจํ„ด๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ BFF๋„ ์œ„ํ—˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„ํ—˜๋“ค์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” ๋ชจ๋ฒ” ์‚ฌ๋ก€๋“ค์„ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ์ž์ฒด์ ์œผ๋กœ ํฌํ•จํ•˜๋Š” API๋กœ BFF๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๋ผ - ์ž์ฒด์ ์œผ๋กœ ํฌํ•จ๋œ API๋Š” ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์ธต์— ์žˆ์–ด์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฐœ๋ฐœ์ž๋“ค์€ ์ด ์ ์„ ์žŠ๊ณ  BFF์—์„œ ์„œ๋น„์Šค ๋ ˆ๋ฒจ์˜ API๋ฅผ ๊ตฌํ˜„ํ•˜๊ณค ํ•ฉ๋‹ˆ๋‹ค. BFF๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋น„์Šค ์‚ฌ์ด์—์„œ ๋ฒˆ์—ญ์˜ ์—ญํ• ์„ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ์„œ๋น„์Šค API๋กœ๋ถ€ํ„ฐ ๋ฐ˜ํ™˜๋  ๋•Œ BFF์˜ ๋ชฉ์ ์€ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ํด๋ผ์ด์–ธํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋งž๋Š” ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • BFF ๋กœ์ง์˜ ์ค‘๋ณต์„ ํ”ผํ•˜๋ผ - ํ•˜๋‚˜์˜ BFF๋Š” ๋””๋ฐ”์ด์Šค ํƒ€์ž…์ด ์•„๋‹ˆ๋ผ ํŠน์ •ํ•œ UX์— ๋ถ€ํ•ฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์ด ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋Œ€๋ถ€๋ถ„์—์„œ ๋ชจ๋“  ๋ชจ๋ฐ”์ผ ๋””๋ฐ”์ด์Šค๋Š” ๋™์ผํ•œ UX๋ฅผ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ๋ผ๋ฉด ๋ชจ๋“  ๋™์ž‘ ์‹œ์Šคํ…œ์— ๋Œ€ํ•ด์„œ ํ•˜๋‚˜์˜ BFF๋กœ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. iOS์™€ Android์— ๋Œ€ํ•ด ๋ณ„๋„์˜ BFF๊ฐ€ ์žˆ์–ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  • BFF์— ๋Œ€ํ•œ ์ง€๋‚˜์นœ ์˜์กด์„ ํ”ผํ•˜๋ผ - BFF๋Š” ํ•œ๋‚ฑ ๋ฒˆ์—ญํ•˜๋Š” ๋ ˆ์ด์–ด์ผ๋ฟ์ž…๋‹ˆ๋‹ค. ์ผ์ • ์ˆ˜์ค€์˜ ๋ณด์•ˆ์„ ์ œ๊ณตํ•˜๊ธฐ๋„ ํ•˜์ฃ . ๊ทธ๋ ‡์ง€๋งŒ, ์—ฌ๋Ÿฌ๋ถ„์ด ์˜์กดํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๋งŽ์ด ์˜์กดํ•˜์ง€ ๋งˆ์„ธ์š”. ์—ฌ๋Ÿฌ๋ถ„์˜ API ๋ ˆ์ด์–ด์™€ ํ”„๋ก ํŠธ์—”๋“œ ๋ ˆ์ด์–ด๋Š” BFF ์กด์žฌ ์—ฌ๋ถ€์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋ชจ๋“  ๊ธฐ๋Šฅ๊ณผ ๋ณด์•ˆ์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. BFF๋Š” ํ‹ˆ์„ ๋ฉ”์šฐ๋Š” ์šฉ๋„์ด์ง€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๊ธฐ๋Šฅ์ด๋‚˜ ์„œ๋น„์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์šฉ๋„๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

์š”์•ฝ

BFF ํŒจํ„ด์€ ๊ฐœ๋ฐœ์„ ๋„์šธ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ UX๋ฅผ ๋งค์šฐ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ BFF๋Š” ํ”„๋ก ํŠธ์—”๋“œ์— ์ง‘์ค‘ํ•˜๋ฉฐ ๋ฐ์ดํ„ฐ ์ตœ์ ํ™”์™€ ์ง‘๊ณ„๋ฅผ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ์ด์ „์— BFF ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด๋ณธ ์ ์ด ์—†๋‹ค๋ฉด ์ง€๊ธˆ์ด ์‹œ์ž‘ํ•  ๋•Œ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ๊ฒฝํ—˜๊ณผ ์˜๊ฒฌ์„ ๋‚˜์ค‘์— ์ €์—๊ฒŒ ๊ณต์œ ํ•ด์ฃผ์„ธ์š”. ๐Ÿ˜ƒ

[๋ฒˆ์—ญ] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋””์ž์ธ ํŒจํ„ด Part 1 : ํŒฉํ† ๋ฆฌ ํŒจํ„ด

์›๋ฌธ : JavaScript Design Patterns Part 1: The Factory Pattern์„ ์ฝ๊ณ  ๋ฒˆ์—ญํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

์ตœ๊ทผ ์ž‘์—…ํ•œ ํ”„๋กœ์ ํŠธ์˜ ๊ทœ๋ชจ๊ฐ€ ์ปค์ง€๋ฉด์„œ, ๋”์šฑ ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ๊ฐ€ ์šฉ์ดํ•˜๊ณ  ํ™•์žฅ์„ฑ์ด ์ข‹์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๋””์ž์ธ ํŒจํ„ด์— ๋Œ€ํ•ด ๊นŠ๊ฒŒ ์•Œ์•„๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์กŒ์Šต๋‹ˆ๋‹ค. ๋””์ž์ธ ํŒจํ„ด์€ ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ๋“ค์— ์‹œ๊ฐ„์ด๋‚˜ ํ…Œ์ŠคํŠธ ์†”๋ฃจ์…˜์„ ์ ์šฉํ•˜๊ธฐ ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์œผ๋กœ ๊ทธ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์ฃ .

์šฐ๋ฆฌ๊ฐ€ ์•Œ์•„๋ณผ ๋Œ€๋ถ€๋ถ„์˜ ๋””์ž์ธ ํŒจํ„ด์€์€ ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๊ณ  ์žˆ๊ณ  ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉฐ ์ˆ˜๋ฐ˜๋˜๋Š” ์—ฌ๋Ÿฌ ๋ณต์žกํ•œ ๊ฒƒ๋“ค์ด๋‚˜ ๋กœ์ง์„ ์ถ”์ƒํ™”ํ•˜๋ฉด์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๋ช…ํ™•ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋ฏ€๋กœ ์†Œ์œ„ creational ํŒจํ„ด๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด ํŒจํ„ด์€ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์ด๋ผ๊ณ  ๋ถ€๋ฅด๋ฉฐ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์‰ฝ๊ฒŒ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ๋” ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋‚˜ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ์–ธ์–ด๋กœ๋ถ€ํ„ฐ ๋น„๋กฏ๋˜์—ˆ๋‹ค๊ณ  ํ•˜์—ฌ ์šฐ๋ฆฌ๊ฐ€ ํด๋ž˜์Šค๋‚˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์งœ์•ผํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์‚ฌ์‹ค ๋ฌธ๋ฒ•์  sugar์— ๋ถˆ๊ณผํ•˜์—ฌ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ์–ธ์–ด์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ํ•  ๋ฟ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ํ•  ๊ฒƒ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํ”„๋กœํ† ํƒ€์ž… ์ƒ์†๊ณผ OLOO(Objects Linking to Other Objects, ๊ณต์œ ๋˜๋Š” ํ”„๋กœํ† ํƒ€์ž…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ์ฒด๋“ค์„ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธ)๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ”„๋กœํ† ํƒ€์ž… ์ž์ฒด๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด์ผ๋ฟ์ด๊ณ  ํด๋ž˜์Šค๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์ƒ์†๊ณผ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ์ƒ์†๊ณผ์˜ ์ฐจ์ด๋ฅผ ์„ ๊ฐ€์žฅ ์ž˜ ์„ค๋ช…ํ•˜๋Š” ๊ธ€์€ Eric Elliot์˜ ์•„ํ‹ฐํด์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

๊ทธ๋Ÿผ ์ด์ œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค.

์ด ๊ธ€์— ์žˆ๋Š” ๋ชจ๋“  ์˜ˆ์ œ ์ฝ”๋“œ์™€ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฐ€์ด๋“œ๋Š” GitHub์—์„œ ๋ณด์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์•„ํ‹ฐํด์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ๋ถ„์€ Node๋ฅผ ์„ค์น˜ํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์„ค์น˜ํ•˜์ง€ ์•Š์œผ์…จ๋‹ค๋ฉด ์ด ์•ˆ๋‚ด์‚ฌํ•ญ์„ ๋”ฐ๋ฅด์„ธ์š”. GitHub ๋ ˆํฌ readme์— ์ฝ”๋“œ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์œผ์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ € ํด๋”๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”. ์ด ํด๋”๋ฅผ javascript-design-patters๋ผ ํ•˜๊ณ , ์ด ์•ˆ์— factory ํด๋”๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

ํŒฉํ† ๋ฆฌ ํŒจํ„ด ๋™์ž‘

ํŒฉํ† ๋ฆฌ ํŒจํ„ด์€ ๊ฐ์ฒด์˜ ์—ฌ๋Ÿฌ ํƒ€์ž…์œผ๋กœ ์ƒ์„ฑ์ž๋ฅผ ๊ฐ์‹ธ๊ณ  ๊ฐ„๋‹จํ•œ API๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ตฌ์ฒดํ™”๋œ ๊ฐ์ฒด ํƒ€์ž…์„ ๋ฆฌํ„ดํ•˜๋Š” ๊ฐ„๋‹จํ•œ API๋ฅผ ๋…ธ์ถœํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

์ƒ์„ฑ์ž๋ฅผ ์ƒ์„ฑํ•ด๋ณด๋Š” ๊ฒƒ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ฉ์‹œ๋‹ค. ์ด ํ•จ์ˆ˜๋“ค์€ ํ˜ธ์ถœ๋˜์—ˆ์„ ๋•Œ ํŠน์ • ํƒ€์ž…์˜ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
factory ํด๋”์—์„œ laptop.js ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

const Laptop = function({ ram, hdd, name }) {
  this.ram = ram || 0;
  this.hdd = hdd || 0;
  this.name = name || "";
};

module.exports = Laptop;

์ด ํŒŒ์ผ์—์„œ Laptop ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์ฒด๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„ ๊ฐ ๊ฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค์˜ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ์˜ ๊ฐ’์œผ๋กœ ๊ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—์„œ๋Š” RAM ์‚ฌ์ด์ฆˆ, HDD ์‚ฌ์ด์ฆˆ, ๋””๋ฐ”์ด์Šค ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์ฃ . ๊ทธ ํ›„ Laptop ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ๋ชจ๋“ˆ๋กœ๋ถ€ํ„ฐ exportํ•ฉ๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ํŒŒ์ผ์ธ tablet.js๋ฅผ ์ƒ์„ฑํ•ด๋ด…์‹œ๋‹ค. ๋น„์Šทํ•˜์ง€๋งŒ ์ข€ ๋” ํƒœ๋ธ”๋ฆฟ์— ๊ด€๋ จ๋œ ๊ฒƒ๋“ค์„ ์ถ”๊ฐ€ํ•ด๋ด…์‹œ๋‹ค.

const Tablet = function({ ram, hdd, name, network }) {
    this.ram = ram || 0;
    this.hdd = hdd || 0;
    this.network = network || 0;
    this.name = name || "";
};

module.exports = Tablet;

์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“ค์—ˆ์œผ๋‹ˆ ์ด๋Ÿฐ ์•„์ดํ…œ๋“ค์„ ๊ฐ€์ง€๋Š” ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” API๋ฅผ ๋…ธ์ถœํ•  ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. gadgetFactory.js ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.

const Laptop = require("./laptop");
const Tablet = require("./tablet");
const gadget = { Laptop, Tablet };
module.exports = {
    createGadget(type, attributes) {
        const GadgetType = gadget[type];
        return new GadgetType(attributes);
    }
};

Laptop๊ณผ Tablet ๊ฐ์ฒด๋“ค์„ ์ƒ์„ฑํ•˜๋Š” ์ƒ์„ฑ์ž๋ฅผ import ํ•œ ํ›„ ์ƒ์„ฑ์ž ์ด๋ฆ„์„ key๋กœ ์‚ฌ์šฉํ•˜๋Š” gadget ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” gadget[type]์„ ์‚ฌ์šฉํ•˜์—ฌ ์›ํ•˜๋Š” ์ƒ์„ฑ์ž์˜ ํƒ€์ž…์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํƒ€์ž…์€ "Laptop"์ด๊ฑฐ๋‚˜ "Tablet"์ž…๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ createGadget ๋ฉ”์†Œ๋“œ๋ฅผ ํฌํ•จํ•œ ๊ฐ์ฒด๋ฅผ exportํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋Š” ์ฒซ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ gadget type์„ ๋ฐ›๊ณ  ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ๊ฐ’๋“ค์„ ํ•ด๋‹น ์ƒ์„ฑ์ž์— ๋„˜๊ฒจ์ฃผ๋ฉด์„œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ new ํ‚ค์›Œ๋“œ๋กœ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์‹คํ–‰ํ•˜๋Š” ํ•จ์ˆ˜์— this ๋ฐ”์ธ๋”ฉ์ด ๋œ ๋นˆ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜๋ฐ›๋Š” ๊ฒƒ์— ์ฃผ๋ชฉํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋…ํŠนํ•จ์€ ์ƒ์„ฑ์ž ํ•จ์ˆ˜์™€ ์ด ๋ฐฉ์‹์œผ๋กœ ์ƒ์„ฑํ•œ ์ƒˆ ๊ฐ์ฒด ์‚ฌ์ด์˜ ํ”„๋กœํ† ํƒ€์ž… ๊ด€๊ณ„๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋” ์ž์„ธํ•œ ๊ฒƒ์€ ๋‚˜์ค‘์— ๋‹ค๋ฃฐ ๋””์ž์ธ ํŒจํ„ด์—์„œ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ์ฃผ๋ชฉํ•  ์ ์€ ๋Œ€๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์€ ๊ด€์Šต์ด์ง€ ํ•„์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•˜๋Š”๊ฒƒ์€ ์–ด๋–ค ํŠน๋ณ„ํ•œ ๊ธฐ๋Šฅ๋„ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ํ•จ์ˆ˜ ์ด๋ฆ„์ด๋‚˜ ๋ณ€์ˆ˜ ์ด๋ฆ„์—์„œ ๋ณดํ†ต ์‚ฌ์šฉํ•˜๋“ฏ์ด camelCase๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ํŒฉํ† ๋ฆฌ ํŒจํ„ด API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํŒŒ์ผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. index.js ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.

const gadgetFactory = require("./gadgetFactory");

const myLaptop = gadgetFactory.createGadget("Laptop", {
    ram: 8,
    ssd: 256,
    name: "Bab's MacBook Pro"
});

const myTablet = gadgetFactory.createGadget("Tablet", {
    ram: 4,
    hdd: 128,
    name: "Bab's iPad",
    network: '4G'
});

console.log(myLaptop);
console.log(myTablet);

์•„๋งˆ ์—ฌ๋Ÿฌ๋ถ„์€ ์ฒซ ๋ฒˆ์งธ๋กœ laptop์ด๋‚˜ tablet ์ƒ์„ฑ์ž๊ฐ€ ์ง์ ‘์ ์œผ๋กœ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์…จ์„ ๊ฒ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ์€ gadgetFactory ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋‘ ๊ฐ€์ง€ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ฝ˜์†”์— ์ถœ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ„ฐ๋ฏธ๋„์—์„œ ์•„๊นŒ ์ƒ์„ฑํ•œ javascript-design-patterns ํด๋”๋ฅผ ์ฐพ์•„ ํƒ€์ดํ•‘ํ•˜์„ธ์š”.

$ node ./factory/index.js

์ฝ˜์†”์—๋Š” ์ด๋ ‡๊ฒŒ ์ถœ๋ ฅ๋์„ ๊ฒ๋‹ˆ๋‹ค.

Laptop { ram: 8, ssd: 256, name: 'Bab\'s MacBook Pro' }
Tablet { ram: 4, hdd: 128, network: '4G', name: 'Bab\'s iPad' }

์—ฌ๋Ÿฌ๋ถ„์ด ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด Laptop ๊ฐ์ฒด ํƒ€์ž…๊ณผ Tablet ๊ฐ์ฒด ํƒ€์ž… ๋ชจ๋‘๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ๋ถ„์€ ํ•„์š”ํ•œ ๋ช…์„ธ์— ๋”ฐ๋ผ ๋งŽ์€ gadget ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด๊ฒƒ์ด ํŒฉํ† ๋ฆฌ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ๋ฌผ๋ก  ํ›จ์”ฌ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„์ด๊ณ  ์—ฌ๋Ÿฌ๋ถ„์ด ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ƒ์„ฑ์ž ๋“ฑ์— ๋”์šฑ ์—„๊ฒฉํ•œ ๋…ผ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์˜ˆ์‹œ์—์„œ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ํ”„๋กœํ† ํƒ€์ž…์œผ๋กœ๋„ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ์ž‘์„ฑํ•  ๊ธ€์—์„œ๋Š” ์ฝ”๋“œ๋ฅผ ๋”์šฑ ํšจ์œจ์ ์œผ๋กœ ๋ฆฌํŒฉํ† ๋งํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์•„ํ‹ฐํด ์ฃผ์ œ๋Š” ์œ ๋ช…ํ•œ Publisher/Subscriber pattern์— ๋Œ€ํ•ด ๋‹ค๋ค„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์•Œ๋ฆผ์„ ๋ฐ›๊ณ  ์‹ถ์œผ์‹œ๋ฉด ์ €๋ฅผ ํŒ”๋กœ์šฐํ•˜์‹œ๊ณ , ๋งŒ์•ฝ ์ด ๊ธ€์ด ๋„์›€์ด ๋˜์…จ๋‹ค๋ฉด thumbs up์„ ๋‚จ๊ฒจ์ฃผ์„ธ์š”. ์–ธ์ œ๋‚˜ ๊ทธ๋žฌ๋“ฏ์ด ์•„๋ž˜ ์ฝ”๋ฉ˜ํŠธ์—์„œ ์—ฌ๋Ÿฌ๋ถ„๋“ค์˜ ์ƒ๊ฐ์„ ๋“ค์–ด๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์—…๋ฐ์ดํŠธ : ์ด ์‹œ๋ฆฌ์ฆˆ์˜ Part 2์—์„œ๋Š” Publisher/Subscriber pattern์— ๋Œ€ํ•ด ๋‹ค๋ฃน๋‹ˆ๋‹ค.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.