본문 바로가기

웹개발 수업/JavaScript

[Day +59 / Java Script]기초(8. 객체)

210914 화

 

1) 배열 뒷부분

 

2) 객체

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>08_객체</title>
</head>

<body>
    <h1>객체</h1>
    <p>
        다른 자료형은 오직 하나의 데이터만 담을 수 있는 원시형(primitive type)이지만
        객체는 다양한 데이터를 담을 수 있음
    </p>

    <h3>1. 객체 선언 및 호출</h3>
    <p>
        객체는 프로퍼티(키-값 쌍)를 저장하며 키 값을 사용하여 속성을 식별한다<br>
        키는 문자열이며 속성에는 모든 자료형이 올 수 있다<br>
        객체 생성자 또는 중괄호 {}를 사용하여 객체를 생성한다
    </p>

    <script>
        function test1() {
            // 방법1) 객체 생성자 호출
            let obj = new Object();
            // 방법2) 객체 리터럴 선언
            let obj2 = {};

            let product = {
                // 키값 : value값
                // 키와 값 쌍으로 구성된 프로퍼티
                pName: 'Dry Mango',
                origin: 'Philippines',
                price: 10000,
                ingredient: ['mango', 'sugar']
            };

            console.log("===== product ======")
            console.log(product);
            // ingredient: (2) ['mango', 'sugar']
            // origin: "Philippines"
            // pName: "Dry Mango"
            // price: 10000

            // 방법1) 속성에 접근하는 방법
            console.log("객체명.속성명으로 접근")
            console.log("product.pName : " + product.pName);
            console.log("product.origin : " + product.origin);
            console.log("product.price : " + product.price);
            console.log("product.ingredient : " + product.ingredient);
            // product.pName : Dry Mango
            // product.origin : Philippines
            // product.price : 10000
            // product.ingredient : mango,sugar

            // 방법2) 속성에 접근하는 방법
            console.log("객체명['속성명']으로 접근");
            console.log("product['pName'] : " + product['pName']);
            console.log("product['origin'] : " + product['origin']);
            console.log("product['price'] : " + product['price']);
            console.log("product['ingredient'] : " + product['ingredient']);
            //  product['pName'] : Dry Mango
            //  product['origin'] : Philippines
            //  product['price'] : 10000
            //  product['ingredient'] : mango,sugar


            // 방법1) ingredient의 mango, sugar에 직접 접근하는 방법
            console.log("product.ingredient[0] : " + product.ingredient[0]);
            // 답 : product.ingredient[0] : mango
            console.log("product.ingredient[1] : " + product.ingredient[1]);
            // 답 : product.ingredient[1] : sugar


            // 방법2) ingredient의 mango, sugar에 직접 접근하는 방법
            console.log("product['ingredient'][0] : " + product['ingredient'][0]);
            // product['ingredient'][0] : mango
            console.log("product['ingredient'][1] : " + product['ingredient'][1]);
            // product['ingredient'][1] : sugar


            // **보통 1번 방법을 자주 사용하지만 1번을 못 쓰는 특수한 상황이 있다. 
            // ** 밑에서 2번을 사용하는 상황을 알아보자

        }
        // test1();
    </script>


    <h3>2. 객체의 키 식별자 테스트</h3>
    <p>
        객체의 키는 모든 문자열을 사용할 수 있다<br>
        단, 식별자로 사용할 수 없는 단어를 키로 사용하거나 변수를 키로 사용하는 경우<br>
        무조건 대괄호를 사용해야 객체의 요소에 접근할 수 있다
    </p>
    <script>
        function test2() {
            let objTest = {
                // 띄어쓰기를 쓰면 오류가 발생함 => 따라서 ''로 감싸줘야 함
                'hello world': 'Hello World!!!',
                '!@#$%^&*()': 1234567890,
                test: true
            };

            // 변수에 담긴 key 값
            let key = "test";


            console.log("===== objTest=====")
            console.log(objTest);
            // 답 : {hello world: 'Hello World!!!', !@#$%^&*(): 1234567890}

            console.log("객체명.속성명으로 접근 불가");
            // console.log(objTest.'hello world'); => 오류
            // => 위에서는 문제 없었는데 console에서 확인하려고 하면 오류남
            // console.log(objTest.'!@#$%^&*()'); => 오류남
            console.log(objTest.key);
            // 답 : undefined 

            console.log("객체명['속성명']으로 접근 가능");
            console.log(objTest['hello world']);
            // Hello World!!! => 잘 출력됨
            console.log(objTest['!@#$%^&*()']);
            // 1234567890 => 잘 출력됨
            console.log(objTest[key]);
            // 답 : true

        }

        // test2();
    </script>


    <h3>3. 상수 객체는 수정 가능</h3>
    <p>
        상수 배열/객체의 속성은 변경가능하나 상수 배열/객체를 다시 할당할 수는 없음
    </p>
    <script>
        // 상수 : 바뀌는 않는 값
        function test3() {
            const student = { name: '우별림', age: 20 };
            console.log(student);
            // 답 : {name: '우별림', age: 20}
            student.age = 30;
            console.log(student);
            // 답 : {name: '우별림', age: 30}

            //  student = {name : '우별림', age : 40}; 
            // console.log(student);
            // => 상수는 재할당 불가하기 때문에 오류 발생
        }
        // test3();
    </script>


    <h3>
        4. 객체의 속성 추가와 제거
    </h3>
    <p>
        처음 객체 생성 이후 속성을 추가하거나 제거하는 것을 동적으로 속성을 추가한다
        혹은 제거한다라고 한다
    </p>
    <script>
        function test4() {
            // 빈 객체 선언
            let student = {};

            // 객체에 속성을 추가
            student.name = '홍길동';
            student.hobby = '게임';
            student.strength = '프로그래밍';
            student.dream = '개발자';

            console.log(student);
            // 답 : {name: '홍길동', hobby: '게임', strength: '프로그래밍', dream : '개발자'}

            delete (student.dream);
            console.log(student);
            // 답 : {name: '홍길동', hobby: '게임', strength: '프로그래밍'}
        }

        // test4();
    </script>


    <h3>5. 함수를 활용한 객체 생성</h3>
    <script>
        // 방법1) 
        // function makeStudent(name, score){
        //     let student = {
        //         name : name,
        //         score : score
        //     };
        //     return student;
        // }

        // 방법2) 
        function makeStudent(name, score) {
            return {
                name,   // name : name과 같음
                score   // age : age와 같음
                // => 단축 프로퍼티
            };
        }

        // console.log(makeStudent('우별림', 100));
        // 답 : {name: '우별림', score: 100}
        // console.log(makeStudent('김영희', 90));
        // 답 : {name: '김영희', score: 90}
        // console.log(makeStudent('박영희', 80));
        // 답 : {name: '박영희', score: 80}

    </script>


    <h3>6. in 키워드</h3>
    <p>
        in : 객체 내부에 해당 속성이 있는지 확인하는 키워드
    </p>

    <script>
        function test5() {
            let student = {
                name: '우별림',
                kor: 100,
                eng: 80,
                math: 90,
                test: undefined
            };

            console.log('studnet 객체에 name 속성이 있는지 확인 : ' + ('name' in student));
            // 답 
            // studnet 객체에 name 속성이 있는지 확인 : true
            // => true 값으로 돌려줌
            console.log('studnet 객체에 kor 속성이 있는지 확인 : ' + ('kor' in student));
            console.log('studnet 객체에 eng 속성이 있는지 확인 : ' + ('eng' in student));
            console.log('studnet 객체에 math 속성이 있는지 확인 : ' + ('math' in student));
            // 세 값 모두 true

            console.log('studnet 객체에 sum 속성이 있는지 확인 : ' + ('sum' in student));
            // studnet 객체에 sum 속성이 있는지 확인 : false

            console.log('studnet 객체에 test 속성이 있는지 확인 : ' + ('test' in student));
            // student 객체에 test 속성이 있는지 확인 : true
            // **test 값 잘 이해하기!!!


            // **값이 undefined인 속성은 in 연산자로 확인하는 것이 정확함
            // 값 자체가 undefined일 경우와 값을 찾을 수 없어서 undifined의 경우를
            // 구분하기 어렵기 때문
            console.log('student.name : ' + student.name);
            // 답 student.name : 우별림
            console.log('student.sum : ' + student.sum);
            // 답 student.sum : undefined
            console.log('student.sum : ' + student.test);
            // 답 student.sum : undefined



        }

        // test5();
    </script>


    <h3>7. 객체와 반복문</h3>
    <p>
        객체의 속성을 살펴볼 때에는 단순 for문으로는 사용 불가능하고,
        for in문을 사용해야 한다<br>
        for in문 : 객체의 속성에 순차적으로 접근
    </p>

    <script>
        function test6() {
            let game = {
                title: 'DIABLO 3',
                price: '35,000원',
                language: '한국어 지원',
                supportOS: 'windows 32/64',
                service: true
            };
            // for(let 변수명 in 객체명)
            for (let key in game) {
                console.log(key + " : " + game[key]);
            }
            // 답
            // title : DIABLO 3
            // price : 35,000원
            // language : 한국어 지원
            // supportOS : windows 32/64
            // service : true
        }
        // test6();
    </script>


    <h3>8. 객체의 메소드 속성</h3>
    <p>
        객체의 속성에 저장된 함수를 메소드라고 하며 객체명.메소드()와 같은 형식으로 사용한다<br>
        메소드는 this로 객체를 참조한다
    </p>
    <script>
        function test7() {
            let name = '뽀삐';
            let dog = { name: '복실이' };

            // 함수 표현식으로 함수를 만드고
            // 객체 속성 dog.eat에 할당 (메소드로 등록)
            dog.eat = function (food) {
                console.log(name + '가 ' + food + '를 먹고 있네요 멍멍');
                // 답 : 뽀삐가 고구마를 먹고 있네요 멍멍
                // Q. let name = '뽀삐'를 지우면? 
                // A. 가 고구마를 먹고 있네요 멍멍으로 나옴. dog객체를 참조하는 것이 아님

                // 객체 내에서 자신의 속성을 호출할 때는 반드시 this를 사용해야 함
                console.log(this.name + '가 ' + food + '를 먹고 있네요 멍멍');
                // 복실이가 고구마를 먹고 있네요 멍멍
            };

            // 메소드 호출
            dog.eat('고구마');


            // 선언 된 함수 메소드로 등록, 동적인 방식으로 속성 추가
            dog.walk = walk;

            // 메소드 호출
            dog.walk('테헤란로');

            //  선언된 함수
            function walk(place) {
                console.log(this.name + '가 ' + place + '를 산책하고 있네요 멍멍');
                // 복실이가 테헤란로를 산책하고 있네요 멍멍



                let human = {
                    name: '부승관',
                    // this 사용
                    eat(food) {// 메소드 단축 구문 원래는 eat : function(){}
                        console.log(this.name + "이 " + food + "를 먹고 있어요 냠냠");

                        // this를 사용하지 않고 외부 변수를 참조해 객체에 접근하는 것도 가능
                        // 하지만 외부 변수 참조시 발생할 수 있는 문제가 있음(지금 상황 말하는거 아님)
                        console.log(human.name + "이 " + food + "를 먹고 있어요 냠냠냠");
                        // 답 : 부승관이 닭가슴살 샐러드를 먹고 있어요 냠냠냠
                    }
                };

                // 메소드 호출
                human.eat('닭가슴살 샐러드');
                // 부승관이 닭가슴살 샐러드를 먹고 있어요 냠냠


                // 외부 변수 참조시 발생할 수 있는 문제
                let person = human;
                human = null;
                person.eat('비빔밥');
                // 1) this.name의 경우 : 부승관이 비빔밥를 먹고 있어요 냠냠
                // 2) human.name의 경우 : 
                // Uncaught TypeError: Cannot read properties of null (reading 'name')
                // 이 오류 발생
                // Why? human.name이 person으로 바뀌었기 때문
                // 따라서 외부변수보다 this를 참조하는 것이 나음
            }
        }
        // test7();
    </script>



    <h3>9. 생성자 함수</h3>
    <p>
        유사한 객체를 여러 개 만들어야 할 때 생성자 함수를 사용한다<br>
        생성자 함수와 일반 함수는 기술적으로 다르지 않지만
        함수 이름의 첫 글자는 대문자로 시작하고 new 연산자를 붙여 실행한다는 규칙이 있다
    </p>

    <script>
        // 생성자 함수 정의
        function Student(name, java, oracle, html5, css3, javascript) {
            // new 연산자와 함께 호출했을 경우
            // this = {}; 빈 객체가 암시적으로 만들어짐

            // 속성 정의
            this.name = name;
            // 전달받은 매개변수를 속성 안에 대입한다는 의미
            this.java = java;
            this.oracle = oracle;
            this.html5 = html5;
            this.css3 = css3;
            this.javascript = javascript;

            // 메소드 정의
            this.getSum = function () {
                return this.java + this.oracle + this.html5 + this.css3 + this.javascript;
            };

            this.getAvg = function () {
                return this.getSum() / 5;
            };

            // new 연산자와 함께 호출했을 경우
            // return this; this가 암시적으로 반환됨
        }
        // 객체 생성1
        function test8() {
            let student1 = new Student('홍길동', 100, 50, 80, 70, 80);
            console.log(student1);
            // 답 Student {name: '홍길동', java: 100, oracle: 50, html5: 80, css3: 70, …}
            console.log("student1 점수 합계 : " + student1.getSum);
            // 답 student1 점수 합계 : function () {
            //     return this.java + this.oracle + this.html5 + this.css3 + this.javascript;
            // }
            console.log("student1 점수 합계 : " + student1.getAvg);
            // 답 student1 점수 합계 : function () {
            //     return this.getSum() / 5;
            // }


            // 객체 생성2
            let student2 = new Student(prompt('이름 입력'),
                Number(prompt('자바 점수 입력')),
                Number(prompt('오라클 점수 입력')),
                Number(prompt('html5 점수 입력')),
                Number(prompt('css3 점수 입력')),
                Number(prompt('javascript 점수 입력')));

            console.log(student2);
            // 답 : Student {name: '부승관', java: 100, oracle: 80, html5: 80, css3: 70, …}

            // 배열 선언
            let students = [];

            // 배열에 객체 담기
            students.push(student1);
            students.push(student2);

            // 객체 배열
            console.log(students);
            // 0: Student {name: '홍길동', java: 100, oracle: 50, html5: 80, css3: 70, …}
            // 1: Student {name: '부승관', java: 10, oracle: 10, html5: 10, css3: 10, …}
            // length: 2

        }
        // test8();

    </script>



    <h3>10. find와 findIndex</h3>
    <p>
        객체 배열을 대상으로 특정 조건에 부합하는 객체를 배열 내에서 검색할 수 있다<br>
        배열 요소를 대상으로 함수가 순차적으로 호출된다<br>

        let 변수 = 배열명.find/findIndex(function(item, index, array){
        // true가 반환되면 반복이 멈추고 해당 요소를 반환/해당 요소의 인덱스를 반환
        // 조건에 해당하는 요소가 없으면 undefined를 반환
        });
    </p>

    <h3>11. filter</h3>
    <p>
        find/findIndex는 처음 true가 반환된 하나의 요소만 반환 가능하므로
        조건을 충족하는 요소개 여러개라면 filter 메소드를 사용한다<br>
        문법은 유사하지만 조건에 맞는 요소 전체를 담은 배열을 반환한다.
    </p>

    <script>



        function test9() {
            let students = 
            [new Student('수지', 100, 90, 95, 85, 80), //0번 인덱스
            new Student('제니', 70, 80, 90, 75, 64), // 1번 인덱스
            new Student('유아', 80, 65, 55, 95, 90, 90)]; //2번 인덱스

            // 제니라는 이름을 가진 학생 찾기
            let jennie = students.find(item=> item.name == '제니');
            console.log(jennie);
            // 답 : Student {name: '제니', java: 70, oracle: 80, html5: 90, css3: 75...

            // 승관이라는 이름을 가진 학생 찾기 => 찾지 못해서 undefined
            let seungguan = students.find(item => item.name == '승관');
            console.log(seungguan);
            // 답 : undefined

            // java 점수가 90점 이상인 학생 인덱스 찾기
            let java = students.findIndex(item => item.java >= 90);
            console.log(java);
            // 답 : 0

            // oracle 점수가 60점 미만인 학생 인덱스 찾기
            let oracle = students.findIndex(item => item.oracle < 60);
            console.log(oracle);
            // 답 : -1(찾는 값이 없을 때는 -1로 출력된다)


            // 평균 점수가 70점 대인 학생 인덱스 찾기
            // 2명이 해당한다면 findIndex는 처음 true가 반환된 요소만 반환 가능(고유값에 사용)
            // filler를 이용하여 해당하는 모든 요소를 배열로 리턴 받기

            // let avg70 = students.findIndex(item => item.getAvg() >= 70 && item.getAvg() < 80);
            // 답 : 1
            // 만약 제니가 지워져도 1이라는 숫자 반환. 맨 처음에 찾은 요소를 가져옴(유아라는 뜻)


            let avg70 = students.filter(item => item.getAvg() >= 70 &&
                item.getAvg() < 80);
            console.log(avg70);
            // 답
            // 0: Student {name: '제니', java: 70, oracle: 80, html5: 90, css3: 75, …}
            // 1: Student {name: '유아', java: 80, oracle: 65, html5: 55, css3: 95, …}
            // length: 2
        }
        test9();



    </script>

</body>

</html>