728x90

https://school.programmers.co.kr/learn/courses/30/lessons/150368?language=javascript

 

프로그래머스

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

programmers.co.kr

 

function solution(users, emoticons) {
    let answer = [0, 0];

    function discountCombinations(discounts, numProducts) {
    
        function generateCombo(currentCombo, depth) {
            if (depth === numProducts) {
                let plus = 0, sell = 0; //플러스 가입자수, 총 판매금액 
                
                //reduce를 사용해 이모티콘 총 구매금액을 계산 
                for (let user of users) {
                    let total = emoticons.reduce((sum, price, c) => 
                        sum + (currentCombo[c] >= user[0] ? price * (1 - currentCombo                         [c] * 0.01) : 0), 0
                    );
                    //총 구매한 금액이 목표금액보다 비싼경우 구매를 취소하고 플러스 가입 
                    if (total >= user[1]) plus++;
                    else sell += total;
                }
                //그 경우의 수 마다 max값을 비교해서 최적의 결과를 answer에 넣어줌 
                if (plus > answer[0] || (plus === answer[0] && sell > answer[1])) {
                    answer = [plus, sell];
                }
                return;
            }
            //재귀
            for (let discount of discounts) {
                generateCombo([...currentCombo, discount], depth + 1);
            }
        }
        generateCombo([], 0);
        
    }

    discountCombinations([10, 20, 30, 40], emoticons.length);
    return answer;
}

 

재귀함수를 사용해서 각 이모티콘별로 할인되는 모든 경우의 수를 구하고, 그 경우의 수 중 max 값을 찾는 

무식한 방법을 사용했다 ㅎㅎ ... 

이모티콘의 갯수가 많지 않고 할인은 10 20 30 40 단 네가지의 경우의 수만 존재하기때문에 가능했던 풀이 

728x90

 

https://school.programmers.co.kr/learn/courses/30/lessons/132265

 

프로그래머스

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

programmers.co.kr

 

function solution(topping) {
    var answer = 0;
    let chul = new Map();
    topping.forEach((f)=>{
        if(chul.get(f)) chul.set(f,chul.get(f)+1);
        else chul.set(f,1);
    })
   
    let dong = new Set();
    for(let i =0; i<topping.length; i++){
        dong.add(topping[i]);
        if(chul.get(topping[i])){
            if(chul.get(topping[i])>1) chul.set(topping[i],chul.get(topping[i])-1);
            else chul.delete(topping[i])
        }
        if(chul.size ==dong.size){
            
           answer++;
            
        }
    }
    return answer;
}

 

처음에는 양쪽 다 set을 써서 풀려고 했는데

생각해보니 양쪽 다 동일한 토핑을 갖게되는 경우도 있어서 한쪽은 map을 써야한다는걸 알게되었다... 

set과 map을 써봤으면 간단히 풀 수 있는 문제군 

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

자바스크립트의 이벤트 루프에서 비동기 함수를 대기시키는 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

https://school.programmers.co.kr/learn/courses/30/lessons/70129

 

프로그래머스

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

programmers.co.kr

function solution(s) {
    let cnt=0;
    let answer = s;
    let zero = 0;
    
    while(answer!=='1'){
        let findZero = answer.split('0').length - 1
        let editNum = answer.replaceAll("0",'');
        answer = editNum.length.toString(2);
     
        cnt++;
        zero+=findZero;
    }
    return [cnt,zero];
}

 

javascript의 여러 메서드들을 연습해볼 수 있는 문제군 ~.~

728x90

+ Recent posts