TIL

Code Review

2023년 1월 2째주 코드리뷰 진행함

링크 : https://www.notion.so/23-1-2-e96841b1c2f9435097b32b09ae5ab6dc

발표한 문제

다항식 문제: https://school.programmers.co.kr/learn/courses/30/lessons/120863

function solution(polynomial) {
   let lst = polynomial.split(" + ")
   let bs = 0
  let num = 0
  for (let idx of lst){
    idx.includes('x') ? idx.length === 1 ? bs+=1 : bs+=Number(idx.substr(0,idx.length-1))  : num += Number(idx) 
  }
  
  //변수가 없을때
  if (bs === 0){
    return num === 0 ? "0" : String(num)
  }
   // 변수가 1일때
  else if( bs === 1){
    return num === 0  ? "x" : "x" + " "+  "+" + " " + String(num)
  }
  // 1 이상일때 
  else{
    return num === 0 ? bs + "x" : bs + "x" + " " + "+" + " " + String(num)
  }
}
  • polynomial 을 “ + “ 기준으로 split해서 lst 배열을 만들고 계수와 상수항값을 저장하는 bs num 값을 선언
  • lst 의 요소만큼 반복을 실행하며 요소에 x 가 존재한다면, 숫자를 bs에 더하고, 존재하지 않을 경우에는 num 에 더한다
  • 변수가 없을때, 계수가 1일때, 혹은 1이상일때로 경우를 나눠서 그에 맞는 값을 출력함

과제 구현

back to top 버튼 구현

const flexBoxEl = document.querySelector('.flex-box')
const topBtnEl = document.querySelector('.topbtn')
const targetEl = document.querySelector('.search')
const rootElement = document.documentElement
// 검색 결과를 둘러보기위해 스크롤 해서 검색 엘리먼트가 보이지 않는 순간
// 하단에 맨 위로 이동하게 해주는 버튼이 나타남
function moveTop(entries, observer) {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      flexBoxEl.style.opacity = '0'
    } else {
      flexBoxEl.style.opacity = '1'
    }
  })
}
// 검색창 엘리먼트를 감시하는 IntersectionObserver 생성
const topObserver = new IntersectionObserver(moveTop)
topObserver.observe(targetEl)

// 버튼을 클릭하게 되면 맨위로 스크롤 된다.
function scrollToTop() {
  // 맨 위로 스크롤
  rootElement.scrollTo({
    top: 0,
    behavior: 'smooth',
  })
}

// 버튼 엘리먼트에 이벤트 추가
topBtnEl.addEventListener('click', scrollToTop)

IntersectionObserver를 사용해서 검색창입력 엘리먼트를 target으로 지정했고, 뷰포트에 보이는 동안에는 버튼을 보이지 않게 하고 스크롤을 내려서 사라지는 순간 버튼이 나타나게 설정함

왜 배경화면의 색이 전체 화면으로 적용되지 않지?

body내부에 잇는 viewpoint 섹션에 색을 적용 시켰는데 내부의 엘리먼트 만큼만 칠해져 있어서 왜이러나 싶었는데,
그냥 body 에다가 스타일 속성을 부여하니까 해결됨

왜 li 엘리먼트 클릭했는데 동작을 안하지?

여러개의 li 가 렌더링 되었기 때문에 li 엘리먼트를 선택에서 for each 문법을 사용해서 작성했더니 동작함

  const modalEl = document.querySelector('.modal')
  const list = document.querySelectorAll('.result__list__item')
  list.forEach((e) => {
    e.addEventListener('click', function () {
      modalEl.style.display = 'flex'
    })
  })

JavaScript

모듈

as를 사용해서 데이터의 이름 변경이 가능하다.

const hello = 'hello world'
const b = 123
const c = ['A', 'B', 'C']
export default hello
export { b as num, c as arr }
import hello, { num, arr } from './hello.js'

console.log(hello, num, arr)
// hello world 123 ['A', 'B', 'C']

가져오기(Imports)

import 기본데이터, {이름데이터1, 이름데이터2} from '경로'

import defData from './myModule.js'
import defData, { str, num, arr, fn } from './myModule.js'
import { str, num, arr, fn } from './myModule.js'
import { 
  str as myStr, 
  num as myNum, 
  arr as myArr, 
  fn as myFn 
} from './myModule.js'
import * as myName from './myModule.js'

import 옆에 중괄호가 있으면 기본 가져오기, 중괄호가 있으면 이름 가져오기

동적모듈 가져오기 : import 함수를 통해 동적으로 모듈을 가져올 수 있다. 이때 import 함수는 promise객체를 반환한다.

가져온 다음 바로 내보내기 : 가져온 모듈을 바로 내보낼수 있다. import 대신에 export 키워드를 사용한다.

비동기

동기? 순차적으로 코드가 실행
비동기? 순차적으로 코드가 실행되지 않는다

동기 예

console.log(1)
console.log(2)
console.log(3)
// 1
// 2
// 3

비동기 예시 :

console.log("햄버거 주세요")
setTimeout(() => console.log("아참 감자튀김 빼구요"), 1000)
console.log("메뉴 나왔습니다.") 
//햄버거 주세요
//메뉴 나왔습니다.
//아참 감자튀김 빼구요... 이미 늦었다. 메뉴가 나와버렸다.

콜백 패턴

function a(callback) {
  setTimeout(() => {
    console.log('A')
    callback()
  })
}

function b() {
  console.log('B')
}

a(() => {
  b()
})
//A
//B

setTimeout 같은 비동기 함수를 사용하면 당연히 나중에 나타나겠지만, 그럼에도 불구하고 비동기 함수가 호출된 다음에 다음으로 넘어가게 하고 싶다면 이렇게 작성한다.

인수로 함수 데이터를 받아와서 해당 함수(b)가 호출되기 전에 (a)가 먼저 호출되고 그다음에 (b)가 호출됨!

function add(a, b, callback) {
  setTimeout(() => {
    const result = a + b
    callback(result)
  }, 1000)
}

add(2, 7, (result) => {
  console.log(result) // 1초 뒤에 9가 나타남
})

계산하는데 시간이 좀 걸리는데 한 1초뒤에 나오는 결과값 뽑아주세요~

이거랑 비슷한건 이전에 봤었다. 바로 addEventListener!


const h1El = document.querySelector('h1')
h1El.addEventListener('click', (event) => {
  console.log(event)
})

시간이 얼마나 걸리는지는 모르겠는데 h1 dom 클릭하면 해당 이벤트에대한 내용을 뽑아주세요~

그런데 이런 비동기에대한 내용을 콜백 패턴으로만 작성하면 한두개정도는 괜찮을지 몰라도 프로세스가 길어지면

const a = callback => {
  setTimeout(() => {
    console.log(1)
    callback()
  }, 1000)
}
const b = callback => {
  setTimeout(() => {
    console.log(2)
    callback()
  }, 1000)
}
const c = callback => {
  setTimeout(() => {
    console.log(3)
    callback()
  }, 1000)
}
const d = callback => {
  setTimeout(() => {
    console.log(4)
    callback()
  }, 1000)
}
// ...

a(() => {
  b(() => {
    c(() => {
      d(() => {
        // ...
      })
    })
  })
})

이렇게 지옥이 펼쳐진다.

다른 방법은 없을까?

Promise

const add = (a, b) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      const result = a + b
      resolve(result)
    }, 1000)
  })
}

const res = await add(2, 7)
console.log(res) // 1초 뒤에 9

에이 뭐야 아까랑 비슷하잖아?

const a = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(1)
      resolve()
    }, 1000)
  })
}
const b = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(2)
      resolve()
    }, 1000)
  })
}
const c = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(3)
      resolve()
    }, 1000)
  })
}
const d = () => console.log(4)



a()
	.then(b)
	.then(c)
	.then(d)

이래도 차이가 없어보이는가?

a(() => {
  b(() => {
    c(() => {
      d(() => {
        // ...
      })
    })
  })
})

------------------------
a()
	.then(b)
	.then(c)
	.then(d)

이렇게 Promise로 구현된 비동기 함수는 Promise 객체를 반환하며, 이로 구현된 비동기 함수를 호출하는 측에서 후속 처리 메서드(then)을 통해 비동기 처리 결과를 처리하게 된다.

async/await

const a = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(1)
      resolve()
    }, 1000)
  })
}
const b = () => console.log(2)

// a().then(() => b())

const wrap = async () => {
  await a()
  b()
}
wrap()

이렇게 async와 await를 사용해서 작성도 가능하다.

이미지 로딩

function loadImage(src) {
  return new Promise((resolve) => {
    const imgEl = document.createElement('img')
    imgEl.src = src
    imgEl.addEventListener('load', () => {
      resolve(imgEl)
    })
  })
}

resolve안에 imgEl을 넣었기 때문에 다른 곳에서 imgEl을 사용할수 있게된다.

import { loadImage } from './loadImage.js'

const src = 'https://picsum.photos/2000'
const imgEl = await loadImage(src)
document.body.innerHTML = ''
document.body.append(imgEl)
// document.body.innerHTML = `<img src="${src}" />`
console.log('Loaded!')

위의 내용은 laodImage를 모듈화 해서 다른 곳에서 불러와 사용하는 모습이다. imgEl이 loadImage 비동기 함수로 인해 발생한 결과물이기 때문에 이를 사용해서 렌더링을 하는 모습이다.

fetch()

첫번째 인자로 URL, 두번째 인자로 옵션 객체를 받고, Promise 타입의 객체를 반환한다.

const res = await fetch('https://omdbapi.com/?apikey=7035c60c&s=frozen')

const json = await res.json
console.log(json)

이런 타입의 내용은 과제를 진행해보면서 봤었다.

profile
개발자 꿈나무

0개의 댓글