JS___1

HJ·2022년 5월 13일
1

Javascript__

목록 보기
1/2
post-thumbnail

5.13(금)

실습환경 만들기

개발환경 세팅 !
React - Node.js를 이용한 VSCode JS 실행하기 :

Node.js 설치
먼저, 아래 사이트에서 최신 버전 Node.js를 다운로드 한다
https://nodejs.org/ko/

VS Code (Visual Studio Code) 설치
다음으로는 Node.js의 가장 많이 사용되는 개발 툴인 VS Code를 설치합니다.
MS사에서 만든 오픈소스 IDE로 설치도 간편하고 가볍고 사용이 편리합니다.
아래의 공식 사이트에서 자신의 OS에 맞는 설치 파일을 다운로드합니다.
https://code.visualstudio.com/download


Node.js 프로젝트 생성 및 실행


VS Code 프로그램으로 가서 상단 메뉴에 File > Open Folder를 선택하여, 방금 생성한 폴더를 선택합니다.


아래와 같이 Explorer 탭이 오픈이 되고, 방금 내가 오픈한 폴더가 리스트에 있는 것을 확인하실 수 있습니다.


상단 메뉴바에서 View > Terminal을 눌러서 터미널을 오픈해줍니다.
아래와 같이 하단에 터미널이 오픈이 됩니다.
이렇게 터미널을 보면서 VS CODE 내에서 진행을 하는 것이 창이동 없이 더 편합니다.


터미널 오픈 화면

이제 Node.js를 설치할 때 자동으로 설치되는 자바 패키지 관리 모듈인 NPM을 이용해서 프로젝트의 package.json 파일을 생성합니다.
package.json 파일은 Node.js의 프로젝트 기본 정보, 의존성 정보 등을 저장하는 json 파일로 JAVA Maven 프로젝트의 pom.xml과 유사한 역할이라고 생각하시면 됩니다.

하단 터미널 창에 NPM init이라는 명령을 치면, 프로젝트의 기본정보를 작성하도록 여러 항목들이 나옵니다. 실제로 작성을 하셔도 되고, 엔터를 계속 클릭하셔서 Default 값으로 세팅된 파일을 만들도록 해도 됩니다.

다 작성이 되면 프로젝트 폴더에 package.json 파일이 생성됩니다.


npm init


프로젝트 최초 실행 자바스크립트 파일인 index.js 파일을 생성


생성된 index.js을 열어서 아래와 같이 콘솔 로그를 찍도록 간단히 코드를 작성
console.log("노드js 프로젝트 시작!!")


우측 Run and Debug 탭으로 이동을 하면, VS code에서 프로젝트 실행에 필요한 launch.json 파일이 아직 없기 때문에, 아래와 같이 create a launch.json file이라는 버튼이 보입니다.
이 버튼을 클릭하여 launch.json을 생성합니다


그러면 아래와 같이 Launch Type을 선택하도록 되어 있는데, 당연히 Node.js를 선택합니다. 그러면 launch.json 파일이 생성되는 것을 확인할 수 있습니다.


이제 VS code에서 프로젝트 실행은 Run and Debug 탭으로 이동하여 해당 Launch name을 선택 후 F5 버튼 혹은 아래 화살표 버튼을 클릭하면 Node.js 프로젝트가 정상적으로 실행이 되는 것을 확인할 수 있습니다.

JavaScript 실습 (코딩문제 풀기)

문제1) 두 개의 정수 n, m을 입력, 별(*)문자를 이용해 가로길이 n, 세로길이 m인 직사각형 형태를 출력하기

process.stdin.setEncoding('utf8');
process.stdin.on('data', data => { 
    const n = data.split(" "); // 입력값에 공백으로 구분
    
    const a = Number(n[0]); // 입력값 5
    const b = Number(n[1]); // 입력값 3
    
    const star = "*".repeat(a) // a 입력값만큼 *을 반복
    
    for(let i = 0; i < b; i++){
        console.log(star)
    }
});

실행 결과

  • "*".repeat(a) 메서드 : 주어진 횟수만큼 반복해 새로운 문자열 반환 !

문제2) 정수num이 짝수일 경우 "Even"을 반환, 홀수인 경우 "Odd"를 반환하는 함수 작성하기

function solution(num) {
    var answer = '';
    if(num % 2 == 0){
        return answer = "Even"
    } else {
        return answer = "Odd"
    }
}

  • num % 2 == 0 : 나머지 값을 구하는 산술 연산 !

문제3) 단어 s의 가운데 글자를 반환하는 함수, solution을 만들기
단어의 길이가 짝수라면 가운데 두글자를 반환

function solution(s) {
    var answer = '';
    if(s.length % 2 == 0) { 
        answer = s[s.length / 2 -1] + s[s.length / 2];
    } else { 
        answer = s[Math.floor(s.length / 2)]
    }
    return answer;
}

  • % 연산으로 홀수/짝수 구분 !
  • 짝수 == 반으로 나눈 값과 그 값의 -1인덱스값을 함께 출력 ! ( 4 : 1,2 )
  • 홀수 == Math.floor를 사용해 반으로 나눈 값의 소수점을 반내림한다. ( 3 : 1 )

문제4) 두 정수 a, b가 주어졌을 때 a와 b 사이에 속한 모든 정수의 합을 리턴하는 함수 완성하기
예를 들어 a = 3, b = 5인 경우, 3 + 4 + 5 = 12이므로 12를 리턴합니다.

function solution(a, b) {
    var sum = 0;
    if(a < b){
        for(let i = a; i <= b; i++){ // 입력값a ~~ 입력값b 까지 반복 
            sum = sum + i; // a ~ b 값 sum에 더하기
        }
    } else if(a > b) { // 입력값b ~~ 입력값a 까지 반복
        for(let i = b; i <= a; i++){
            sum = sum + i; // a ~ b 값 sum에 더하기
        }
    } else {
        sum = a; // 같은 경우 a 출력
    }
    return sum;
}

  • 간단하게 if문 안에 for문을 넣어 작성했다.

문제5) 문자열 s를 숫자로 변환하는 함수 작성하기

function solution(s) {
    var answer = 0;
    var answer = Number(s);
    return answer;
}


문제6) 없는 숫자 더하기

0부터 9까지의 숫자 중 일부가 들어있는 정수 배열 numbers가 매개변수로 주어집니다. numbers에서 찾을 수 없는 0부터 9까지의 숫자를 모두 찾아 더한 수를 return 하도록 solution 함수를 완성해주세요.

function solution(numbers) {
    var sum = 0;
    
    for(let i =0; i<=9; i++){
        if(!numbers.includes(i)) {  // numbers.includes(a) = numbers 안에 a가 포함되어 있는지 체크
            sum = sum + i;
        }
    }
    return sum;
}

  • .includes() = 괄호 안의 값을 포함하는지 확인한다 true , false 반환

5.14(토)

문제7) 음양 더하기

어떤 정수들이 있습니다. 이 정수들의 절댓값을 차례대로 담은 정수 배열 absolutes와 이 정수들의 부호를 차례대로 담은 불리언 배열 signs가 매개변수로 주어집니다. 실제 정수들의 합을 구하여 return 하도록 solution 함수를 완성해주세요.

function solution(absolutes, signs) {
    var answer;
    var sum = 0;
    for(let i =0; i < absolutes.length; i++) { // absolutes의 값 읽기
        if(signs[i] == true) { // signs[index] 가 true이면
            sum = sum + absolutes[i]; // 변수 sum에 absolutes[index] 더하기
        } else { // false이면
            sum = sum - absolutes[i]; // 변수 sum에 absolutes[index] 빼기 
        }
    }
    return sum;
}

  • 입력값이 가지는 타입을 정확히 파악하기

문제8) 평균 구하기
정수를 담고 있는 배열 arr의 평균값을 return하는 함수, solution을 완성해보세요.

function solution(arr) {
var answer = 0;
let sum = 0;
let avg = 0;
for(let i =0; i<arr.length; i++){
sum = sum + arr[i]
}
avg = sum / arr.length;
return avg;
}


문제9) 핸드폰 번호 가리기

프로그래머스 모바일은 개인정보 보호를 위해 고지서를 보낼 때
고객들의 전화번호의 일부를 가립니다.
전화번호가 문자열 phone_number로 주어졌을 때,
전화번호의 뒷 4자리를 제외한 나머지 숫자를 전부 *으로 가린 문자열을 리턴하는 함수, solution을 완성해주세요.

function solution(phone_number) {
    var answer='';
    for(let i = 0; i < phone_number.length; i++){
        if(answer.length < phone_number.length-4){
            answer = answer + "*";
        }
        else {
            answer = answer + phone_number[i];
        }
    }
    return answer;
}

  • 길이를 -연산으로 구분하여 영역 나누기 / + repeat함수 사용 가능 ( * )

문제10) 행렬의 덧셈

행렬의 덧셈은 행과 열의 크기가 같은 두 행렬의 같은 행, 같은 열의 값을 서로 더한 결과가 됩니다.
2개의 행렬 arr1과 arr2를 입력받아, 행렬 덧셈의 결과를 반환하는 함수, solution을 완성해주세요.

function solution(arr1, arr2) {
var answer = [];
for(let i =0; i<arr1.length; i++){ // [1,2][2,3]
let sum = []; // 값을 합할 배열 생성
for(let j=0; j<arr1[i].length; j++) { // [1,2]
sum.push(arr1[i][j]+arr2[i][j]) // [1,2] + [3,4]
}
answer.push(sum)
}
return answer;
}

  • 행과 열을 잘 구분하여 헷갈리지 않기 !

문제11) x만큼 간격이 있는 n개의 숫자

함수 solution은 정수 x와 자연수 n을 입력 받아, x부터 시작해 x씩 증가하는 숫자를 n개 지니는 리스트를 리턴해야 합니다. 다음 제한 조건을 보고, 조건을 만족하는 함수, solution을 완성해주세요.

function solution(x, n) {
    var answer = [];
    for(let i = 1; i<=n; i++){
        answer.push(x*i);
    }
    return answer;
}

  • .push() : 괄호 안의 값을 배열에 추가

문제12) 부족한 금액 계산하기

새로 생긴 놀이기구는 인기가 매우 많아 줄이 끊이질 않습니다.
이 놀이기구의 원래 이용료는 price원 인데,
놀이기구를 N 번 째 이용한다면 원래 이용료의 N배를 받기로 하였습니다.
즉, 처음 이용료가 100이었다면 2번째에는 200, 3번째에는 300으로 요금이 인상됩니다.

놀이기구를 count번 타게텍스트 되면 현재 자신이 가지고 있는 금액에서 얼마가 모자라는지를

return 하도록 solution 함수를 완성하세요.
단, 금액이 부족하지 않으면 0을 return 하세요

function solution(price, money, count) {
    var result = 0;
    var price_sum = 0;
    for(let i = 1; i <= count; i++){
        price_sum = price_sum + i * price;
    }
    if(price_sum > money) {
        result = price_sum - money;
        return result;
    }

    return result;
}

  • 입력값 구분, 계산, 결과값 정리해서 풀기

5/16(월)

문제14) 나누어 떨어지는 숫자 배열

array의 각 element 중 divisor로 나누어 떨어지는 값을 오름차순으로 정렬한 배열을 반환하는 함수, solution을 작성해주세요.
divisor로 나누어 떨어지는 element가 하나도 없다면 배열에 -1을 담아 반환하세요.

function solution(arr, divisor) {
    var answer = [];
    for(let i = 0; i < arr.length; i++){
        if(arr[i] % divisor == 0){ // 나눈 값의 나머지가 0이면 배열에 넣기
            answer.push(arr[i]);
        }
    }
    if(answer.length == 0) { // 배열에 값이 없다면 -1 넣기
        answer.push(-1);
    }
    answer.sort((a,b) => a - b); // answer 배열 오름차순 
    return answer;
}

  • .push()
  • .sort((a,b) => a - b) 오름차순 정렬

문제15) 내적

길이가 같은 두 1차원 정수 배열 a, b가 매개변수로 주어집니다.
a와 b의 내적을 return 하도록 solution 함수를 완성해주세요.

이때, a와 b의 내적은 a[0]b[0] + a[1]b[1] + ... + a[n-1]*b[n-1] 입니다. (n은 a, b의 길이)

function solution(a, b) {
    var answer = 0;
    for(let i = 0; i < a.length; i++){
        answer = answer + a[i] * b[i] // a[i] * b[i] --> answer에 누적
    }
    return answer;
}

  • 각 배열의 인덱스 값을 곱하여 더하기 a[0] b[0] + a[1] b[1]

문제16) 문자열 내 p와 y의 개수

대문자와 소문자가 섞여있는 문자열 s가 주어집니다.
s에 'p'의 개수와 'y'의 개수를 비교해 같으면 True, 다르면 False를 return 하는 solution를 완성하세요.
'p', 'y' 모두 하나도 없는 경우는 항상 True를 리턴합니다.
단, 개수를 비교할 때 대문자와 소문자는 구별하지 않습니다.

예를 들어 s가 "pPoooyY"면 true를 return하고 "Pyy"라면 false를 return합니다.

function solution(s){
    var answer = true;
    var p = 0;
    var y = 0;
    for(let i = 0; i < s.length; i++) {
        if(s[i] == 'p' || s[i] == 'P') {
            p = p + 1;
        }
        else if(s[i] == 'y' || s[i] == 'Y') {
            y = y + 1;
        }
    }
    return (p == y) ? true : false;
}

  • for문을 이용해서 p,P y,Y 값 변수에 담아주기
  • ( p == y ) ? true : false :: [조건] ? [true] : [false]

문제17) 문자열 다루기 기본

문자열 s의 길이가 4 혹은 6이고, 숫자로만 구성돼있는지 확인해주는 함수, solution을 완성하세요.
예를 들어 s가 "a234"이면 False를 리턴하고 "1234"라면 True를 리턴하면 됩니다.

function solution(s) {
    var answer = parseInt(s);
    
    if((s.length == 4 || s.length == 6) && s == answer) {
        return true;
    } else {
        return false;
    }
    return answer;
}

  • parseInt(s) : 문자열을 파싱하여 문자열에 포함된 숫자를 찾아서 number로 형변환,
    문자열이 숫자로 시작한다면 숫자로 리턴,
    숫자로 시작하거나, 숫자를 포함하지 않는 문자열의 경우는 NaN으로 반환

문제18) 서울에서 김서방 찾기

String형 배열 seoul의 element중 "Kim"의 위치 x를 찾아, "김서방은 x에 있다"는 String을 반환하는 함수, solution을 완성하세요. seoul에 "Kim"은 오직 한 번만 나타나며 잘못된 값이 입력되는 경우는 없습니다.

function solution(seoul) {
    let kim = 0;
    for(let i = 0; i < seoul.length; i++){
        if(seoul[i] == "Kim"){
            kim = kim + i;
        }
    }
    var answer = '김서방은 ' + kim + '에 있다';
    return answer;
}

  • "kim" 문자를 찾는다면 해당 인덱스값을 변수에 저장
  • 간결하게 하려면 indexOf() 사용할 것
  • indexOf() : 특정 문자 위치 찾기

5.17(화)

Javascript 기초

입력 및 메세지

console.log(name);
alert(age);
prompt('생년월일 입력하세요.');
confirm('삭제 하시겠습니까?);

조건문

if(user.name && user.age > 19){
	console.log('성인 입니다');
    } else {
    	return false;
}

반복문

for(let i = 0; i < 10; i++){
   console.log(i);
}

함수

function add(num1, num2) {
	console.log(num1+num2);
}

Object

const user = {
	name : 'Mike',
    age : 30,
}

배열

const users = ['Mike', 'Jane'];

함수 표현식

let showError = function() {
  console.log('error');
}

함수 선언문

function showError() {
   console.log('error');
}

화살표 함수

let showError = () => {
   console.log('error');
}

변수의 생성과정

  1. 선언 단계
  2. 초기화 단계
  3. 할당 단계

var ( 함수 스코프 - function-scoped )
1. 선언 및 초기화 단계
2. 할당 단계

let ( 블록 스코프 - block=scoped )
1. 선언 단계
2. 초기화 단계
3. 할당 단계

const ( 블록 스코프 - block=scoped )
1. 선언 + 초기화 + 할당

코드 블록
함수, if문, for문, while문, try/catch 문 등 안에서만 사용 가능 ( 지역변수 )

let = "변하는 변수"
const = "상수" ( 대문자로 표현할 것 )
prompt = "값을 입력받을 때 사용" prompt( "예약일을 입력하세요" , "2020-10-" ) default 값 입력가능
입력 없이 취소할 경우 null 값을 반환
confirm = "뭔가 확인 받을 때 사용" // 확인(true) 취소(false) 메세지박스

호이스팅 : 스코프 내부 어디서든 변수 선언은 최상위에 선언된 것처럼 행동


5.18(수)

null, undefined

undefined - 아무 값도 할당받지 않은 상태
null - 비어잇는, 존재하지 않는 값 ( 값의 부재 )

객체, 함수

함수(Function) - 여러 개의 프로그램 명령들을 모아 놓은 것
객체(Object) - 프로그램이 실행 중 사용하는 데이터,
객체의 크기와 종류는 다양하다. 한편으론 값이 들어있는 즉 공간을 말하기도 한다.

함수에 return 값을 주면 값을 반환하여 그 값을
다른 코드에서 사용할 수 있다.

const caculator = {
    add: function(a,b){
        console.log(a+b);
    },
    minus: function(a,b){
        console.log(a-b);
    },
    times: function(a,b){
        console.log(a*b);
    },
    divide: function(a,b){
        console.log(a/b);
    },
    power: function(a,b){
        console.log(a**b);
    }
};
caculator.power(3,9);
caculator.divide(10,3);
caculator.add(4,5);

const plusResult = caculator.add(2,3); // 5
const minusResult = caculator.minus(plusResult, 3); // 5 - 3
const powerResult = caculator.power(plusResult, 2); // 5 * 5
const timesResult = caculator.times(minusResult, powerResult); // 2 * 25
console.log(plusResult, minusResult, powerResult, timesResult);

객체 안의 함수를 호출

console.log()
player.msg()
caculator.add(1,2)

함수와 메서드의 차이

함수(function)라는 것은 어떠한 기능을 수행하는 친구이다.
각 함수마다 나름의 기능을 가지고 있다.
지금도 누군가 함수를 만들고 있기 때문에, 함수의 수는 절대 셀 수 없다.
메소드(method)는 함수처럼 어떠한 기능을 수행하는 친구이다.
하지만 메서드클래스 및 객체(object)와 연관되어 있는 함수이다.
클래스 내에 선언되어 있는 함수가 바로 메소드이다.

  • 클래스 및 객체와 연관되어 있는 것이라면 메소드, 그것들과 상관없이 독립적으로
    존재하는 것은 함수이다.

    함수가 메소드보다 더 큰 개념이라고 생각할 수 있다.

This

Javascript 예약어

  • 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수이다.
  • this를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있다.
  • this는 Javascript 엔진에 의해 암묵적으로 생성된다.
  • this는 코드 어디서는 참조할 수 있다.
  • 하지만 this는 객체의 프로퍼티나 메서드를 참조하기 위한 자기 참조 변수이므로
    일반적으로 객체의 메서드 내부 또는 생성자 함수 내부에서만 의미가 있다.
  • 함수를 호출하면 인자와 this가 암묵적으로 함수 내부에 전달된다.
  • 함수 내부에서 인자를 지역 변수처럼 사용할 수 있는 것처럼, this도 지역 변수처럼 사용할 수 있다.
  • 단, this가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.
  • 크게 전역에서 사용할 때함수안에서 사용할 때로 나눌 수 있다.

👉 바인딩이란?

  • 식별자와 값을 연결하는 과정을 말한다.
  • 변수선언은 변수 이름과 확보된 메모리 공간의 주소를 바인딩하는 것이다.
  • this 바인딩은 this(키워드로 분류되지만 식별자의 역할을 한다)와 this가 가리킬 객체를 바인딩하는 것이다.

❗️this를 전역에서 사용한 경우

  • 브라우저라는 Javascript 런타임의 경우에 this는 항상 window라는 전역 객체를 참조한다.
  • 전역 객체란 전역 범위에 항상 존재하는 객체를 의미한다. (Node.js에서 전역 객체는 global)
  • 브라우저라는 Javascript 런타임에서 모든 변수, 함수는 window라는 객체의 프로퍼티와 메소드이다.

❗️this를 함수 내부에서 사용한 경우

  • 함수는 전역에 선언된 일반 함수객체 안에 메소드로 크게 구분할 수 있다.
  • 객체안에 선언된 함수를 전역에 선언된 함수와 구분하기 위해 메소드라고 한다.
  • 그런데 전역에 선언된 일반 함수도 결국 window 전역 객체의 메소드다.
  • 즉, 모든 함수는 객체 내부에 있다.
  • 이때 this는 현재 함수를 실행하고 있는 그 객체를 참조한다.
  • 정리하면 함수 내부에서 this의 값은 함수를 호출하는 방법에 의해 바뀐다.
  • 그리고 또한 엄격 모드 여부에 따라 참조 값이 달라진다.
  • 엄격 모드에서 일반 함수 내부의 this는 undefinded 가 바인딩 된다.

⚡️ this의 사용

❗️전역에 선언된 함수에서 this

function myFn () {
	return this;
}

myFn(); // window 객체 출력

  • new 연산자를 사용해서 생성자 함수방식으로 인스턴스를 생성한 경우
  • 생성자 함수 MyFn가 빈 객체를 만들고 이 생성자 함수에서 this가 이 빈 객체를 가리키도록 설정
    function MyFn() {
      this.title = 'Hello World!';
      return this;
    }
    // new 연산자를 이용해서 새로운 객체를 얻는다.
    const myfn = new MyFn();
    myfn // MyFn {title: 'Hello World!'}
    

❗️객체의 메소드 함수에서 this

  • method → obj 인 경우이다.

  • showTitle() 메소드는 fn 객체의 메소드이기 때문에 this는 fn 객체를 참조

    const fn = {
      title: 'Hello World!',
      showTitle() {
        console.log(this.title);
      }
    };
    fn.showTitle(); // 'Hello World!'
    
  • 고차 함수의 콜백함수 안에서 this는 콜백함수가 일반 함수이기 때문에 전역 객체를 참조

    const fn = {
      title: 'Hello World!',
      tags: [1, 2, 3, 4],
      showTags() {
        this.tags.forEach(function(tag) {
          console.log(tag);
          console.log(this); // window
        });
      }
    }
    fn.showTags();
    // 1
    // window 객체 출력
    // 2
    // window 객체 출력
    // 3
    // window 객체 출력
    // 4
    // window 객체 출력
    
  • 콜백함수 다음 인자로 참조할 객체를 전달

    const fn = {
      title: 'Hello World!',
      tags: [1, 2, 3, 4],
      showTags() {
        this.tags.forEach(function(tag) {
          console.log(tag);
          console.log(this); // fn
        }, this); // 여기는 일반 함수 바깥, fn 객체를 참조할 수 있다.
      }
    }
    fn.showTags();
    // 1
    // fn 객체 출력
    // 2
    // fn 객체 출력
    // 3
    // fn 객체 출력
    // 4
    // fn 객체 출력
    
  • function 키워드로 생성한 일반함수화살표 함수가장 큰 차이점이 바로 this이다.

  • 이를 Lexical this(렉시컬 this) 라고 한다.

  • 화살표 함수 안에서 this는 언제나 상위 스코프의 this를 가리킨다.

  • 일반 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되지 않고, 함수를 호출 할 때 함수가 어떻게 호출 되는지에 따라 this에 바인딩할 객체가 동적으로 결정된다.

  • 화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정된다.

  • 화살표 함수의 this 바인딩 객체 결정 방식은 함수의 상위 스코프를 결정하는 방식인 렉시컬 스코프와 유사하다.

  • 화살표 함수는 call, apply, bind 메소드를 사용하여 this를 변경할 수 없다.

const fn = {
  title: 'Hello World!',
  tags: [1, 2, 3, 4],
  showTags() {
    this.tags.forEach((tag) => {
      console.log(tag);
      console.log(this); // fn
    });
  }
}
fn.showTags();
// 1
// fn 객체 출력
// 2
// fn 객체 출력
// 3
// fn 객체 출력
// 4
// fn 객체 출력

⚡️ 결론

  • this는 이처럼 어떤 위치에 있느냐, 어디에서 호출하느냐, 어떤 함수에 있느냐에 따라
    참조 값이 달라지는 특성이 있다.
  • 그래서 사용할 때 주의해야 한다.
profile
Development log

0개의 댓글