728x90

https://school.programmers.co.kr/learn/courses/30/lessons/148653#qna

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

탐욕Greedy 알고리즘을 사용해 풀어보자 

 

자신의 자리가 5 이상이라면 올림으로 처리하는것이 더 낫다 

e.g) 95인 경우에는 10*9 + 1*5 총 14회 보다 , 100*1 - 1*5 해서 총 6회로 나오는것이 더 적게 든다 

 

function solution(storey) {
    let ary = String(storey).split("").map(Number); 
    let carry = 0; //올림수
    let total = 0; 

    for (let i = ary.length - 1; i >= 0; i--) { 
        let current = ary[i] + carry;

        if (current > 5) {
            carry = 1;
            total += 10 - current;
        } else if (current === 5 && i > 0 && ary[i - 1] >= 5) {
            carry = 1;
            total += 5;
        } else {
           
            carry = 0;
            total += current;
        }
    }

  
    if (carry > 0) {
        total += carry;
    }

    return total;
}

 

555의 경우에는 올림을 해서 계산을 할 때와 올림을 적용하지 않았을때 둘 다 15회로 값이 동일하다 

728x90

https://react.dev/reference/react/useRef

 

useRef – React

The library for web and native user interfaces

react.dev

 

ref는 우리가 익히 알듯, 랜더링과 관계없는 값을 참조할 때 사용한다.

 

주로 js에서의 getElementById와같이 dom 요소에 직접 접근하고 싶을때 대신 사용하는것이 useRef다.

useRef를 통해 값을 변경하는 경우에는 화면이 재랜더링 되지 않으므로

 

보통 input의 focus 상태를 제어하거나, dom의 css를 직접 조작하고 싶을 때, 또는 className을 변경하고 싶을 때  사용한다.

 

예시 

function ToggleComponet() {
  const myRef = useRef(null);

  const toggleClassName = () => {
    if (myRef.current.classList.contains("second")) {
      myRef.current.classList.remove("second");
    } else {
      myRef.current.classList.add("second");
    }
  };

  return (
    <div>
      <div ref={myRef} className="first">
        test ref 
      </div>
      <button onClick={toggleClassName}>Toggle</button>
    </div>
  );
}

버튼을 클릭하는경우 "first" -> "first second" -> "first"로 변경된다.

 

 

다만 js의 돔 조작 방식처럼 내부에 새로운 요소(div등)을 추가하는 등 랜더링을 필요로 하는 작업들은 useState를 통해 처리하는것이 적절하다. 

 

createRef 는 useRef를 사용할 수 없는 클래스형 컴포넌트에서 사용된다 useRef와는 다르게 랜더링될때마다 다시 생성되어 이전의 값을 기억하지 않는다.

 

 

https://react.dev/reference/react/forwardRef

 

forwardRef – React

The library for web and native user interfaces

react.dev

forwardRef 는 기억해두는것이 좋다 ~.~ 

 

부모컴포넌트가 자식컴포넌트의 ref를 제어해야할 때 사용한다. 

보통 리액트의 데이터흐름은 자식 -> 부모 순이지만 가~끔 이렇게 부모요소가 자식요소를 제어해야하는 경우가 발생한다. 

그럴때 사용하는것이 forwardRef이다.

(위 페이지의 예제를 가져옴)

 

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
  const { label, ...otherProps } = props;
  return (
    <label>
      {label}
      <input {...otherProps} ref={ref} />
    </label>
  );
});

 

자식요소인 MyInput을 forwardRef 컴포넌트로 선언하면 

 

import { useRef } from 'react';
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <MyInput label="Enter your name:" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}

부모요소인 Form에서 선언한 ref는 부모가 아닌 자식컴포넌트인 MyInput을 가리키게된다. 

따라서 핸들클릭을 통해 이벤트가 발생하면 자식요소인 input에 focus가 발생한다. 

728x90

https://ko.vite.dev/guide/

 

Vite

Vite, 프런트엔드 개발의 새로운 기준

ko.vite.dev

 

Vite는 

성능에 집중한 번들러로

 

개발 환경에서 코드를 변경할 때 parcel, webapack에 비해 빠른 속도를 자랑한다. 

 

이유는 vite의 코드 갱신 방식이 다른 번들러들과 다르기 때문인데, 다른 번들러들은 코드의 업데이트가 있을 때 전체 코드를 다시 번들링 하지만, vite는 브라우저의 요청에 따라 변경된 모듈만 전달하는 방식으로 화면을 갱신하기 때문에,

프로젝트의 코드 크기가 커질수록 갱신 속도가 느려지는 다른 번들러들에 비해, vite는 빠른 속도를 유지할 수 있다는 것이다. ~.~ 

 

또한 배포시에도 ESbuild(트랜스파일러), Rollup(트리셰이킹, 불필요한 코드를 쳐내고 번들로 합침)을 기반으로 동작하기때문에, 웹팩과 같이 증분 빌드를 지원하지는 않지만 빌드 속도 또한 매우 빠르다.

 

 

 

 

리액트 typescript 프로젝트를 vite 기반으로 생성하는 npm 명령어 

npm create vite@latest my-project-name --template react-ts

 

일할때는 webpack만을 사용해봤는데 개인적으로 공부할때 vite를 써보니 확실히 기본 설정도 간단하고 로드 속도도 빨라서 편하다고 느껴졌다. 

728x90

 

 

실행 문맥(excution context)이란 코드가 실행되는 동안 필요한 정보를 담고 있는 환경을 말한다. 

함수 선언-실행 과정에서 실행 문맥이 어떻게 생성되는지를 연관지어 생각해보면 이해하기 더 쉽다. 

 

 

이것으로 예시를 들면 

console.log(square(5));

function square(n) {
  return n * n;
}

 

1.  함수 선언 : 함수는 실행되기 전 변수 환경에 저장(메모리 할당)된다.

(square가 메모리에 할당됨)

 

2. 함수 호출 : 함수가 호출되는 이때 새로운 실행 문맥이 생성된다. (call stack에 저장) 또한 함수 내부의 지역변수와 매개변수가 변수 환경에 할당된다. 

(console.log로 호출하는 부분. 여기서는 호이스팅을 사용해 선언 전에 호출했다.)

 

 

함수 호출이 발생하면 새로운 실행 문맥이 생성되고,

이때 함수 내부에서 사용하는 변수와 매개변수가 변수 환경에 저장된다.

 

그다음 함수 내부의 코드가 실행되면서 렉시컬 환경을 기준으로 변수와 값을 검색하고 업데이트하는 과정을 거친다.

이 과정에서 함수 내부에서 필요한 변수는 현재 렉시컬 환경에서 찾고, 현재 환경에 없으면 상위 스코프로 올라가면서 값을 검색한다.

 

3. 함수 실행 종료 : 마지막으로, 함수 실행이 끝나면 생성되었던 실행 문맥이 스택에서 제거되고, 함수와 관련된 변수와 메모리도 해제된다.

 

 

즉, 함수 호출 과정에서는 실행 문맥이 생성되고, 코드 실행을 관리하며, 실행이 종료되면 사라지는 흐름이 반복된다.

~,~

 

console.log(square(5)); 

function square(n) {
  return n * n;
}

위 예제와 같이 함수를 선언전에 사용하는 것을 *호이스팅이라 하고, 이경우엔 에러가 발생하지 않는다.
그러나

console.log(square(5)); //에러 발생!

const square = (n) =>{
  return n * n ; 
}

이렇게 함수를 변수로 선언하여 사용하는 경우에는 변수만 선언되고, 함수내용은 초기화 되지 않기 때문에
선언 전에 호출하면 reference error가 발생한다.

 

만약 비동기 함수의 경우에는? 우선 콜스택에 들어간 다음(실행문맥생성) 작업을 위해 콜스택에서 제거되고 webapi로 보내진다. 작업이 끝나고 큐로 이동된 비동기 함수는 동기함수의 처리가 끝나면 다시 콜스택에 들어가고 다시 새로운 실행문맥이 생성된다. 그리고 실행이 끝나면 콜스택에서 제거된다. 

728x90

 

리액트에 최적화된 코드 스타일로 네이버 맵에서 밤섬 위에 폴리곤을 그려보자 

 

 

 

https://navermaps.github.io/maps.js.ncp/docs/tutorial-3-polygon-simple.example.html

 

NAVER Maps API v3

NAVER Maps API v3로 여러분의 지도를 만들어 보세요. 유용한 기술문서와 다양한 예제 코드를 제공합니다.

navermaps.github.io

 

공식 문서에서 제공하는 폴리곤 예제를 리액트에서 쓰기 좋게 작성했다 ~,~ 

 

 

 

**useLoadMap은 네이버 지도를 초기화하고(mapRef) map 객체(mapObject)를 리턴하기 위해 제가 따로 만든 커스텀 훅 입니다.**

이 포스트에서는 useLoadMap지도 초기화 코드를 생략했으며 추후 포스트할 예정임.

 

 

 

네이버 지도 api를 사용해 한강에 있는 밤섬위에 폴리곤을 그려봤다. 

위도 경도는 대충 찍어온거라 모양이 엄청나게 찌그러져 있는 점 양해바람... 

 

참고로 폴리곤 좌표 리스트는 아래와 같이 이중 배열로 넣어줘야한다

오류 없이 작성했는데도 지도에 폴리곤이 안 뜨는 분들은 이 부분을 체크해보시길! 

 

import { useEffect } from "react";
// 해당 코드 만으로 네이버 지도를 로드할 수 없습니다 지도 호출 부분은 따로 작성해야함(useLoadMap)
const MapWithPolygon = () => {
  const { mapObject , mapRef } = useLoadMap();
  //맵 초기화 & 호출 코드는 해당 포스트에 포함되어있지 않습니다


  const bamsumCoordinates = [
    { lat: 37.540295400459776, lng: 126.92257594754014 },
    { lat: 37.54137410126921, lng: 126.92688464861735 },
    { lat: 37.53956037883299, lng: 126.9306783655637 },
    { lat: 37.53801885028395, lng: 126.93339919890408 },
    { lat: 37.53569458673736, lng: 126.93388843434408 },
    { lat: 37.53810052232298, lng: 126.921175 },
    { lat: 37.540295400459776, lng: 126.92257594754014 },
  ]; //지도 위에 그려질 폴리곤 좌표 리스트. 굳이 처음과 끝을 맞추지 않아도 네이버 지도 api가 알아서 잘 그려줌
  
  useEffect(() => {
    if (!mapObject) return;

    const polygon = new naver.maps.Polygon({
      map: mapObject, //지도 객체
      paths: [bamsumCoordinates], //위도 경도 좌표 리스트
      fillColor: "#ff7d19", //배경 색
      fillOpacity: 0.3, //배경 투명도
      strokeColor: "#ff7d19", //테두리 색
      strokeOpacity: 0.6,
      strokeWeight: 3,
    });

    return () => {
      polygon.setMap(null);
    };
  }, [bamsumCoordinates, mapObject]);
  return (
      <div ref={mapRef} className="map"></div>
      //ref를 통해 div요소에 접근 -> 지도 초기화.
  );
};
export default MapWithPolygon;

 

리액트에서는 getElementbyId 등을 사용해 돔 요소를 직접 조작하는 것보다는 ref를 통해 접근하는것을 권장한다. 

물론 리액트에서도 직접 조작해서 접근하는것이 불가능한 것은 아니지만,

 

가상 DOM을 사용하는 리액트에서 DOM 요소를 직접 조작할 경우, 가상 돔과 실제 돔 사이에 불일치가 발생해 의도치 않은 결과가 초래될 수 있으므로 Ref를 사용하는 것이 좋다! 

 

728x90

자바스크립트의 이벤트 루프에서 비동기 함수를 대기시키는 task queue. 
이 task queue에는 대표적으로 마이크로 테스크 큐(microtask queue), 매크로테스트 큐(macrotask queue)가 있다. 
 
마이크로테스트 큐의 대표적인 예로는 자바스크립트 코드를 작성할때 비동기 처리를 돕는 프로미스(Promise)가 있고,
 
매크로테스크 큐의 예로는 setTimeout고 setInterval이 있다. 
 
그리고 두 테스크 큐의 실행 순서는 마이크로 테스크 큐 > 매크로테스크 큐 이다. 
 
 
Promise의 .then()은 마이크로태스크 큐에 등록되므로, 내부 작업이 아주 오래걸리는 작업이고, setTimeout의 딜레이는 0인 상황이더라도, 
자바스크립트는 Promise를 먼저 처리하고, 그 다음 setTimeout을 실행한다는 것이다. 
 
 
그렇다면 생각나는 것이 하나 있다. 
 
async/await의 경우에는 ? 
 
async/await은 Promise를 동기 함수처럼 작성할 수 있도록 도와주는 ES7에서 등장한 문법이다. async 함수는 항상 Promise를 반환하며, await은 해당 Promise가 해결될 때까지 기다린다.

await 뒤에 오는 작업은 Promise와 동일하게 마이크로태스크 큐로 전달된다.
 
따라서, Promise와 async/await은 우선순위가 동일하다.

둘 다 마이크로태스크 큐에 등록되므로, 매크로태스크 큐보다 항상 먼저 실행된다.

728x90

자바스크립트의 이벤트루프란, 

스택이 비었을때 콜백 큐(callback queue)에 존재하는 작업(함수)를 스택으로 옮기는것을 말한다. 여기서 쓰이는 스택을 콜 스택(call stack)이라고 한다. 

 

자바스크립트가 싱글 스레드 논 블록킹 언어라는 개념과 헷갈릴 수 있는데 함께 정리해보면 이해가 될 것이다.! 

( 논 블로킹: 하나의 오래 걸리는 작업이 수행되는 동안에도 다른 작업들을 처리 대기 상태에 두고, 완료된 작업을 나중에 처리할 수 있는 방식 )

 

우선 우리가 일반적으로 사용하는 계산이나 조건문, 반복문 등을 동기함수라고 부르는데, 

이런 함수들은 자바스크립트가 만나는 즉시 콜 스택으로 보내며 동기적으로 작업을 처리한다. 그러다 Settimeout, Promise, Http요청과 같은 비동기 함수를 만나게 되면, 이들을 웹api로 전달한 다음,  작업이 끝나면 콜백 큐로 보내 대기하도록 한다.

콜 스택에서 모든 동기 함수를 처리하는 작업이 끝나면, 그다음 자바스크립트는 큐에 있던 비동기 함수를 스택으로 보내 처리한다. 

 

이해하는데 도움되는 예제도 함께 첨부하겠다

 

console.log("1. 콘솔 "); // 동기 -> 콜 스택에서 즉시 처리 됨.

if (true) {
  console.log("2. 조건문 "); // 동기 -> 콜 스택에서 즉시 처리됨.
}

setTimeout(() => {
  console.log("5. setTimeout "); // 비동기 -> 매크로태스크 큐 보냄.
}, 0);

Promise.resolve().then(() => {
  console.log("4. Promise "); // 비동기 -> 마이크로태스크 큐 보냄. 
});

console.log("3. 콘솔 "); // 동기 -> 콜 스택에서 즉시 처리됨.

 

코드상에서는 콘솔 - 조건문 - setTimeout- Promise - 콘솔 순으로 선언되었지만,

실제로 자바스크립트 상에서는 콘솔 - 조건문 - 콘솔 - Promise - setTimeout 순으로 출력될 것이다.  

 

예제에 나와있다시피 비동기 함수 사이에도 처리하는 우선순위가 존재한다. 

마이크로테스크 큐(Promise) 먼저, 그다음 매크로테스크 큐(setTimeout)가 처리된다. 애니메이션 프레임 큐 라는 것도 있는데 이것은 랜더링 주기에 맞춰 실행되므로 앞의 둘과 실행 시점이 다르다.  이것에대해서는 다음 글에서 다시 정리해보겠다! 

 

 

728x90

Queue
FIFO구조. 자바스트립트의 이벤트 루프에서 비동기 작업을 처리하는데 사용됨.

자바스크립트에서는 Microtask Queue, Macrotask Queue, Animation frame Queue가 있으며 이들 각각의 역할이 존재한다.
(추후 추가예정)


Heap
자바스크립트에서 객체를 선언할때 힙에 할당. 참조로 관리한다

Stack
LIFO구조. 함수호출 or 코드를 순차적으로 처리할때 사용된다.


다음 글에서는 자바스크립트의 이벤트 루프에 대해 장리해야겠다~.~

728x90

+ Recent posts