# TIL: 2025-05-09 이번 주는 3일만 나가서 다행이야

heeezni·2025년 5월 10일
post-thumbnail

1. 내장객체 (Built-in Object)

  • JS 자체적으로 개발자들에게 아주 유용한 기능을 모아놓은, 이미 내장되어있는 객체

  • 별도 정의 없이 즉시 사용 가능

  • 각 객체가 보유한 속성과 메서드는 API문서 참고하여 개발에 적용

  • API 문서: 속성과 메서드의 목록과 사용법을 정리해둔 참조 문서

  • 내장 객체가 API의 구성 요소
    (API가 자판기 버튼이라면, 내장 객체는 자판기 안의 음료수)

객체 이름분류
Object기본 객체
Array배열 관련
Number숫자 관련
Math수학 관련
String문자열 관련
Date날짜 관련
JSON데이터 표현
Error예외 처리

✅ API 쉽게 설명
API는 프로그램이나 서비스가 다른 프로그램과 상호작용할 수 있도록 하는 "기능의 문을 열어주는 버튼"

비유: 자판기 예시
자판기는 우리가 음료수를 사고 싶을 때 버튼을 눌러 음료를 얻을 수 있는 기계입니다.
자판기에는 음료 목록, 가격, 버튼 등 여러 가지가 있지만, 우리는 음료를 고르고 버튼을 누르는 것만 알면 됩니다.
자판기의 내부 동작은 모르지만, 음료는 잘 나오죠. 이처럼 우리는 자판기의 복잡한 내부를 몰라도 음료를 쉽게 받을 수 있습니다.

API도 마찬가지입니다!
API는 어떤 프로그램이나 서비스가 외부와 소통할 수 있도록 만든 기능(버튼)입니다.
우리가 어떤 기능(예: 데이터를 가져오기, 계산하기 등)을 사용할 때, 그 기능을 제공하는 시스템의 복잡한 내부 동작은 몰라도 쉽게 사용할 수 있게 도와주는 인터페이스입니다.

예시: 음악 앱의 API
여러분이 좋아하는 음악을 들으려면, 음악 앱에 들어가서 곡을 선택하고 플레이해야 합니다.
하지만 이 앱은 음악을 제공하는 서버와 소통해야 해요.
여기서 API는 음악 앱과 서버 간의 대화 방법을 정의하는 역할을 합니다.
예: "이 노래를 재생해 주세요"라는 요청을 API가 서버에 전달하고, 서버는 "이 노래를 재생할 수 있습니다"라고 응답합니다.

[Date 객체]

Date 객체 : 날짜와 시간을 처리하기 위한 내장 객체 📆⏰
'Sat May 10 2025 18:01:28 GMT+0900 (한국 표준시)' 형태의 날짜와 시간 출력

    let test=function(){
        let d=new Date();
      
        console.log(d); //한국 표준시로 출력
      	console.log(d.getFullYear(),d.getMonth()+1,d.getDate(),d.getDay(),d.getHours(),d.getMinutes(),d.getSeconds()); 
        //  ⚠ 월은 0부터 시작."사람이 보는 월"로 출력하려면+1 → getMonth()+1해줘야함
        // getDay() 요일, 한 주의 시작은 0=Sunday
    }

    // setInterval의 첫번째 매개변수로 함수를 넘겨줄 때
    // 호출이 아닌 함수명 또는 함수정의가 와야함
    // 만일 함수()써서 넘겨버리면, setInterval에게 호출을 맡기는게 아니라 바로 호출이 되어버림
    setInterval(test,1000); // "setInterval아 1초마다 내가 정의한 test함수 호출해줘"

[Date 객체] 활용하여 시계 만들기 ⏰

<head>
   	<title>시계만들기</title>
    <style>
        #hour,#min,#sec{
            font-size: 80px;
            color: palevioletred;
            background-color: blanchedalmond;
            width: 120px;
            height: 120px;
            border: 2px solid gray;
            border-radius: 3px;
            display: inline-block; /* 나란히 세워주기 */
            text-align: center;
        }
    </style>
    <script src="../js_lib/common.js"></script>
    <script>
        let showTime=function(){ 
            //표현식에 의한 함수정의 (함수를 데이터처럼 변수로 받을 수 있다, 일급시민)
            let d=new Date();

            let h=d.getHours(); //시간만 추출
            let hour=document.getElementById("hour");
            hour.innerText=zeroString(h) // js_lib/common.js에서 함수꺼내쓰기

            let m=d.getMinutes(); //분만 추출
            let min=document.getElementById("min");
            min.innerText=zeroString(m) // js_lib/common.js에서 함수꺼내쓰기

            let s=d.getSeconds(); //초만 추출
            let sec=document.getElementById("sec");
            sec.innerText=s;
            if(s>=0 && s<10)sec.innerText="0"+s; // 한자리 수 앞에 0붙여주기
        }
        addEventListener("load",()=>{
            setInterval(showTime,1000);
        });
    </script>
</head>
<body>
    <div id="hour"></div>
    <div id="min"></div>
    <div id="sec"></div>
</body>

js_lib/common.js

//한 자리 수 숫자 n 앞에 0을 붙여주기
function zeroString(n){
    let str=n;
    if(n>=0 && n<10)str="0"+n;
    return str;
} 

[Date 객체] 활용하여 달력 만들기 📆


달력이 이따구...지만 일단 로직이 중요하니까 ^^

border 줬을 때 Cell 크기와 전체 틀의 크기가 안 맞아서
어긋나는 현상 개선
➡️ CSS의 boxSizing="border-box" (안쪽으로 살찌우기)
다이어리

js_lib/common.js

자주 쓸 함수들은 라이브러리에 정의해두자

// 해당 월의 '시작 요일' 구하기
// API 사용 예) 2025년 5월 → getStartDay(2025,4)
function getStartDay(yy,mm){
    let d = new Date(yy,mm,1); // 1일
    return d.getDay(); // 요일을 반환  
}
/*-----------------------------------------------------------------*/
// 영어 또는 한국어로 요일을 변환하여 반환하기
// API 사용 예) convertDay(2,"eng")
function convertDay(n,lang){
    let korArray=["일요일","월요일","화요일","수요일","목요일","금요일","토요일"];
    let engArray=["Sun","Mon","Tue","Wed","Thur","Fri","Sat"];

    //어떤 요일을 선책할 지 결정
    let day=(lang=="kor")? korArray[n]:engArray[n];
    return day;
} 
/*-----------------------------------------------------------------*/
// 해당 월의 "마지막 날" 구하기 (= 다음 달의 시작 일 하루 전)
// API 사용 예) getLastDate(원하는 연도, 원하는 월-1)
function getLastDate(yy,mm){
    let d = new Date(yy,mm+1,0); 
    return d.getDate();
}

디자인 좀 망해서 스크립트 로직만 보자

    <script src="../js_lib/common.js"></script> //자주 쓸 함수 모아놓은 라이브러리 파일
    <script src="./js/Cell.js"></script> //달력을 이루는 하나의 셀 정의한 클래스
    <script>
        let cellWidth=100; //각 셀의 너비
        let cellHeight=100; //각 셀의 높이
        let border=1; //셀의 보더 두께
        let currentYear; //유저가 현재 보게 될 연도 , 로드 시에도 할당, 다음, 이전 버튼 누를 때도 할당
        let currentMonth; //유저가 현재 보게 될 월
        let cellArray=[]; //셀 생성 후 제어하려면 이름 필요->변수 필요하다
        //하지만 변수명 일일이 다르게 주면 규칙 없으므로 배열로 가자

        function createCell(){
            // 위의 크기정보로 wrapper의 크기를 동적으로 계산할 수 있다! (전에 고민했던 부분

            wrapper.style.width=(cellWidth+(border*3))*7+"px"; //안먹혀서 일단 border*3
            wrapper.style.height=(cellHeight+(border*2))*6+40+50+"px";

            //요일 영역 출력
            for(let i=0; i<7; i++){
                let cell=new Cell(document.getElementById("days"),cellWidth,40,"yellow",1,"black",convertDay(i,"kor"));
            }

            for(let a=0; a<6; a++){ //6층 (최대6줄 필요함)
                for(let i=0; i<7; i++){ //7호수 (일주일)
                    let cell=new Cell(document.getElementById("section"),cellWidth,cellHeight,"white",border,"black","");
                    cellArray.push(cell);
                }
            }
        }
        
        //모든 셀의 innerText스트링을 지워버리자
        function clearDate(){
            let index=0;

            for(let a=0; a<6; a++){
                for(let i=0; i<7; i++){
                    cellArray[index++].div.innerText="";
                }
            }
        }

        // 이미 생성된 셀에 날짜를 출력한다 (날짜 출력 전용 함수)
        // 주의) 다음,이전 버튼을 누르면 기존에 셀에 출력된 날짜는 지우고, 새로운 날짜를 출력
        function printDate(){
            let count=0; //셀의 인덱스, 박스의 순번 (날짜 아님!)
            let n=0; //유저가 보게될 달력의 날짜

            for(let a=0; a<6; a++){
                for(let i=0; i<7; i++){
                    let cell=cellArray[count]; //셀 하나 꺼내기

                    if(count >= getStartDay(currentYear, currentMonth) && n < getLastDate(currentYear,currentMonth)){
                        // (n <= getLastDate())하면 마지막 날 다음 숫자까지 출력됨 (오류 발생)                                          
                        n++; //1씩 증가를 count가 해당월의 시작일을 만나는 순간부터 하자 
                        cell.div.innerText=n;
                    }
                    count++;
                }
            }

        }
        // 현재 날짜 얻어오기
        function getCurrentDate(){
            let d=new Date();
            currentYear=d.getFullYear();
            currentMonth=d.getMonth();
        }

        // 헤더 영역에 현재 보고있는 날짜 출력 (년,월)
        function printTitle(yy,mm){ 
            //다음,이전 버튼 누를 때 마다 호출할 것이므로 년,월 매개변수로 설정
            let d=new Date(yy,mm);
            currentYear=d.getFullYear();
            currentMonth=d.getMonth();

            let h2=document.querySelector("#header h2");
            h2.innerText=`${currentYear}${currentMonth+1}`
        }

        // 참고) 이벤트 리스너의 두번째 매개변수로 들어가야하는 함수는
        // 정의를 해야하지 호출해서는 안된다.
        // 두번째 매개변수에 등록되는 함수는 개발자가 호출하는 함수가 아니라
        // 브라우저가 load이벤트 발생시 거꾸로 호출을 해주는 역할을 하므로
        // callback함수라 부른다.
        addEventListener("load", function(){
            
            //현재 날짜를 제목에 출력부터 해주자
            getCurrentDate(); // 직접적으로 화면에 뭘 보여주진 않음
			// 하지만 화면에 보여줄 정보를 준비하는 역할
            createCell();
            printTitle(currentYear,currentMonth);
            printDate(currentYear,currentMonth);

            //현재 보고있는 월의 시작요일을 조사해보자
            getStartDay(currentYear,currentMonth);

            //달력의 제목을 이전,다음 버튼으로 바꾸자
            let bt_prev=document.querySelector("#header :nth-child(1)");
            let bt_next=document.querySelector("#header :nth-child(3)");
            
            bt_prev.addEventListener("click",function(){
                currentMonth--;//이전 월로 설정
                printTitle(currentYear,currentMonth); //년도 계산 필요x Date내장객체가 알아서 계산함
                clearDate();
                printDate(currentYear,currentMonth);

            });
            bt_next.addEventListener("click",function(){
                currentMonth++;//이전 월로 설정
                printTitle(currentYear,currentMonth); //년도 계산 필요x Date내장객체가 알아서 계산함
                clearDate();
                printDate(currentYear,currentMonth);
            });
        });
    </script>

달력 예제의 흐름

  1. 초기 실행 (window load 시점)
    getCurrentDate() → 오늘 날짜(연, 월)를 전역 변수 currentYear, currentMonth에 저장
    createCell() → 요일과 날짜 셀을 동적으로 생성해서 DOM에 추가 (cellArray에 저장)
    printTitle(currentYear, currentMonth) → 현재 연/월을 상단 제목에 출력
    printDate(currentYear, currentMonth) → 셀에 해당 월의 날짜를 출력

  2. 셀 생성 (createCell)
    wrapper의 크기 동적으로 설정
    요일 셀 7개 출력 (라이브러리에 만들어둔convertDay(i,"kor") 이용)
    날짜 셀 6x7=42개 생성 → cellArray에 저장

  3. 날짜 출력 (printDate)
    날짜는 몇 번째 셀부터 출력할지 getStartDay(연, 월)로 확인 (이건 요일값 return)
    그 다음부터 날짜 n을 1씩 증가시켜 출력
    마지막 날짜는 getLastDate(연, 월)로 확인 (이건 날짜값 return)

  4. 이전/다음 버튼 클릭 시 흐름
    currentMonth를 증가 또는 감소
    printTitle()로 새로운 년/월을 헤더에 출력 (내장 Date 객체가 자동 계산)
    clearDate()로 기존 셀의 날짜 제거(innerText스트링=" "로 제거)
    printDate()로 새 날짜 출력

  5. 기타 보조 함수들
    getCurrentDate() → 현재 날짜 정보 가져옴
    printTitle(yy, mm) → 헤더의 h2 태그에 년 월 출력
    clearDate() → cellArray의 innerText를 전부 ""로 초기화

로드될 때

└ getCurrentDate() → createCell() → printTitle() → printDate()

버튼 클릭 시

└ currentMonth 조정 → printTitle() → clearDate() → printDate()

궁금한 점

getCurrentDate()printTitle() 둘 다 currentYear, currentMonth 값을 바꾸고 있음.
같은 변수 두 번 바꾸는 거면 중복 아닌가?

❕ 중복되는 건 맞지만, "의도된 중복"임.
각 함수가 다른 타이밍에 같은 전역 상태값을 관리해야 하기 때문

함수 이름언제 실행됨currentYear, currentMonth
getCurrentDate()시작할 때"지금 기준"으로 달력 정보 설정
printTitle()버튼 눌렀을 때"유저가 보고 있는 기준"으로 달력 정보 설정

변수 이름은 같지만,
상황에 따라 다른 의미로 쓰이니까, 사실상 "다른 역할"
단지 변수 이름을 바꾸지 않고 계속 재활용하고 있는 것.


<더 알아보기>

객체 vs 클래스 vs 인스턴스

용어설명
클래스객체를 만들기 위한 설계도
객체클래스에 따라 만들어진 실체 (데이터 + 기능)
인스턴스어떤 클래스에서 실제로 만들어진 객체 → "객체 = 인스턴스"

→ 즉, 객체 = 인스턴스지만, 인스턴스라는 말은 클래스와의 관계를 강조할 때 씀

  • 클래스는 메모리에 안 올라온 원본 틀
  • 인스턴스는 메모리에 올라옴

2. Oracle - 제약조건 중 Foreign Key

FOREIGN KEY (외래키)

  • 다른 테이블의 PRIMARY KEY를 참조하는 컬럼
    (부모를 참조하기 위한 단서)
  • 테이블 간 관계를 맺기 위한 연결 고리 역할

원본(기준 데이터)을 가진 쪽 → 부모 테이블
참조하는 쪽 → 자식 테이블
부모 테이블의 PRIMARY KEY를 자식 테이블이 FOREIGN KEY로 가짐

-- 부모: 부서
CREATE TABLE DEPT (
    DEPTNO NUMBER PRIMARY KEY,
    DNAME VARCHAR2(20)
);

-- 자식: 사원
CREATE TABLE EMP (
    EMPNO NUMBER PRIMARY KEY,
    ENAME VARCHAR2(20),
    DEPTNO NUMBER,
    FOREIGN KEY (DEPTNO) REFERENCES DEPT(DEPTNO)
);
--JOIN 예제: 사원 이름과 그 사원이 속한 부서 이름 출력

--ANSI JOIN 문법
SELECT ENAME, DNAME
FROM EMP E
JOIN DEPT D ON E.DEPTNO = D.DEPTNO;

--ORACLE에서 많이 쓰이던 옛날 JOIN 방식
SELECT ENAME, DNAME
FROM EMP E, DEPT D
WHERE E.DEPTNO=D.DEPTNO

EMP.DEPTNO→ DEPT.DEPTNO 가 FOREIGN KEY 관계

  • FOREIGN KEY는 테이블 설계(DDL)에서 선언되고,
    JOIN 쿼리에서는 그 관계를 "활용"하는 것일 뿐 직접 쿼리 안에 쓰이지 않음

JOIN + 서브쿼리

--SCOTT이 근무하는 부서와 같은 부서에 근무하는 사원의 이름,급여,부서명,부서위치 출력
SELECT ENAME, SAL, DNAME, LOC
FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO
AND E.DEPTNO = (SELECT DEPTNO FROM EMP WHERE ENAME = 'SCOTT');

<참고>
SQL*PLUS 자체명령 중 한 라인에 들어갈 글자 수 늘리기 : SET LINE 600


느낀 점

API나 쿼리, 프로그래밍 개념을 배우기 전에는 그냥 강사님이 하라고 하니까 따라 하기만 했는데, 이렇게 하나하나 개념을 확실히 잡고 나니 훨씬 더 효율적이고 이해도 높은 작업을 할 수 있게 되는 것 같다.
처음에는 "그냥 이렇게 하면 된다" 라고 해서 똑같이 따라가기 급급했던 것들이, 개념을 제대로 이해하고 나면 왜 이렇게 써야 하는지, 무엇을 더 고려해야 하는지까지 알게 되면서 한 단계 성장한 느낌이 부쩍 드는 요즘이다.

profile
아이들의 가능성을 믿었던 마음 그대로, 이제는 나의 가능성을 믿고 나아가는 중입니다.🌱

0개의 댓글