본문 바로가기
03. 웹 표준 기술/JavaScript

[자바스크립트] 08.객체 - (2)

by moca7 2024. 8. 14.

 

 

ㅁ 

 

 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

    <h2>in과 with 키워드</h2>

    이름 : <input type="text" id="name"> <br>
    국어 : <input type="number" id="kor"> <br>
    수학 : <input type="number" id="math"> <br>
    영어 : <input type="number" id="eng"> <br><br>

    <button onclick="fnInWith();">실행확인</button>
    <div id="result2"></div>



    <script>

        function fnInWith() {

            const student = {
                name : document.getElementById("name").value,
                kor : Number(document.getElementById("kor").value), // "70" >> 70
                math : Number(document.getElementById("math").value),
                eng : Number(document.getElementById("eng").value),

                // student 객체를 화면에 출력하고 싶다면
                toString : function() {   //   객체의 속성에 저장된 함수를 메소드라고 한다.
                    return this.name + " " + this.kor + " " + this.math + " " + this.eng;
                },

                // 이 학생 객체가 가지고 있는 총점을 반환하는 메소드 정의
                getSum : function() {             //  메소드도 속성이라 연속될 때 위 마지막에 컴마 빠트리면 안 됨.
                    return this.kor + this.math + this.eng;
                },

                getAvg : function() {
                    // return (this.kor + this.math + this.eng) / 3;   이래도 되지만
                    return this.getSum() / 3;
                }
            }

            console.log(student);
            document.getElementById("result2").innerHTML = student;



        }

    </script>

   
</body>
</html>
 

 

 

 

- 사용자 입력 데이터무조건 문자열이다. value 타입 자체가 string으로 정의되어 있다.

덧셈 등의 연산을 하려면 숫자로 변환해야 한다.

 

 

- 텍스트 상자에 아무것도 입력하지 않았는데 value 값을 가져오면 빈문자열이다.

- 자바스크립트에서 빈문자열 가지고 넘버 타입으로 형변환하면 0으로 변환된다.

자바에서는 빈문자열 가지고 형변환하면 오류 난다.

 

 

 

※ 참고

- string은 기본 자료형(primitive type)으로, 문자열 데이터를 나타냅니다.

- String은 객체 타입입니다. String 객체는 문자열을 감싸는 객체다.

 

 

 

 

 

ㅁ in과 with 키워드

- in : 객체 내에 해당 속성이 있는지 확인해주는 키워드 (존재할 경우 true / 아니면 false)

- with : 객체의 속성에 접근시 객체명 제시를 생략하게 해주는 키워드

 

 

 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
 

    <h2>in과 with 키워드</h2>

    이름 : <input type="text" id="name"> <br>
    국어 : <input type="number" id="kor"> <br>
    수학 : <input type="number" id="math"> <br>
    영어 : <input type="number" id="eng"> <br><br>

    <button onclick="fnInWith();">실행확인</button>
    <div id="result2"></div>



    <script>

        function fnInWith() {

            const student = {
                name : document.getElementById("name").value,
                kor : Number(document.getElementById("kor").value), // "70" >> 70
                math : Number(document.getElementById("math").value),
                eng : Number(document.getElementById("eng").value),

                // student 객체를 화면에 출력하고 싶다면
                toString : function() { // 객체의 속성에 저장된 함수를 메소드라고 한다.
                    return this.name + " " + this.kor + " " + this.math + " " + this.eng;
                },

                // 이 학생 객체가 가지고 있는 총점을 반환하는 메소드 정의
                getSum : function() {             //  메소드도 속성이라 연속될 때 위에 컴마 필요
                    return this.kor + this.math + this.eng;
                },

                getAvg : function() {
                    // return (this.kor + this.math + this.eng) / 3;   이래도 되지만
                    return this.getSum() / 3;
                }
            }

            console.log(student);
            document.getElementById("result2").innerHTML = student;
 



            // 프로퍼티 명은 문자열로 작성    
            console.log("name" in student);    // true
            console.log("age" in student);       // false
 


            // 객체명을 전부 작성하는 방식
            console.log("학생이름 : ", student.name);
            console.log("점수 : ", student.kor, student.math, student.eng);
            console.log("총점 : ", student.getSum());
            console.log("평균 : ", student.getAvg());
 
 
            // with 구문 방식
            with(student) {              //  이 블럭 내에서는 항상 student 객체에 접근한다.
                console.log("학생이름 : ", name);
                console.log("점수 : ", kor, math, eng);
                console.log("총점 : ", getSum());
                console.log("평균 : ", getAvg());
            }
       

        }

    </script>



   
</body>
</html>
 

 

- 특정 속성이 특정 객체에 있는지 확인. 조건식으로도 사용 가능.

- with 키워드는 특정 객체의 속성에 반복적으로 접근할 때 코드의 가독성을 높이기 위해 사용됩니다. (근데 비추천)

 

 

 

 

ㅁ 구조 분해 할당 Destructuring Assignment

- 객체와 함께 쓸 수 있는 표현식

- 객체가 가지고 있는 각 property 값들을 개별 변수에 쉽게 할당할 수 있는 표현식

- 단, 객체의 프로퍼티명과 개별 변수명을 동일하게 맞춰야 함.

 

- 특정 함수 호출시 객체를 반환하는 경우가 있다.

반환되어 돌아오는 객체에 각각의 프로퍼티값을 내가 원하는 변수에 대입시키고자 할 때 구조 분해 할당을 사용하면 좋다.

 

 

 

키워드 { 변수1, 변수2, .. } = 객체;

 

 

 

 

(1) 직접 대입 방식

 

 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

    <h2>구조 분해 할당</h2>
    <button onclick="fnDestructuring1();">구조분해할당1</button>


    <script>

      function fnDestructuring1() {

        // 테스트를 위해 객체 하나 생성
        const car = {
            maker : 'bmw',
            model : 'x6',
            year : 2024
        }

        // 객체 car의 각 property값을 각각의 변수에 직접 대입
        let maker = car.maker;
        let model = car.model;
        let year = car.year;

        console.log(maker, model, year);
       

      }


    </script>


   
</body>
</html>
 

 

 

 

 

(2) 구조 분해 할당 방식

 

 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

    <h2>구조 분해 할당</h2>
    <button onclick="fnDestructuring1();">구조분해할당1</button>


    <script>

      function fnDestructuring1() {

        // 테스트를 위해 객체 하나 생성
        const car = {
            maker : 'bmw',
            model : 'x6',
            year : 2024
        }


       
        // 구조 분해 할당 방법
        // (1) 변수 선언과 동시에 초기화.
        var { maker, model, year } = car;

        console.log(maker, model, year);
 

        // (2) 선언 후 할당.
        var maker, model, year;                // 선언 후
        ( { maker, model, year } = car );    // 대입하고자 할 경우 반드시 ( )로 묶어야 함.
       
        console.log(maker, model, year);


      }


    </script>

 
</body>
</html>
 

 

 

- 키워드 하나로 여러 변수를 한번에 선언하는 것이 가능하다.

- 선언 후 할당하는 경우 이미 선언되었으므로 키워드를 또 붙이지 않아도 된다.

그러나 그냥 중괄호만 쓰면 구조 분해 할당으로 인식하지 않아서 전체를 괄호로 감싸주고 콜론을 써야한다.

 

 

 

 

(3) 구조 분해 할당 방식 - 변수명과 프로퍼티명이 다른 경우

 

 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

    <h2>구조 분해 할당</h2>
    <button onclick="fnDestructuring2();">구조분해할당2</button>


    <script>

        function fnDestructuring2() {

            const qna = {
                q : '한국의 수도는?',
                a : '서울'
            }


            // var { question, answer } = qna;    값이 대입되지 않음. question과 answer는 undefined
            // var { q, a } = qna;                         이건 잘 됨.


            // 프로퍼티명과 이름이 다른 변수에 대입하고자 하는 경우
            var { q : question, a : answer } = qna;

            console.log(question, answer);
           

        }



    </script>

   
</body>
</html>
 

 

 

 

- qna 객체가 가지고 있는 q라는 프로퍼티값이랑 a라는 프로퍼티값을 각각의 변수에 담는다.

- 변수명이 프로퍼티명과 다르면 변수에 값이 대입되지 않는다. 콘솔에 undefined가 출력된다.

 

- 프로퍼티명과 이름이 다른 변수에 대입하고자 하는 경우

콜론 앞에는 프로퍼티명을 쓰고,  콜론 뒤에는 변수명 작성.

 

 

 

 

 

ㅁ 객체 배열

- 다수의 객체들을 배열에 담아서 관리해야 할 때가 있다.

 

 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

    <h2>객체 배열</h2>
    <button onclick="fnObjectArray();">객체 배열</button>


    <script>

        function fnObjectArray() {

            const students = [              //   배열 선언
                {
                    name : '유니',            //   0번 인덱스에 첫번째 객체 담기
                    java : 100,
                    oracle : 80,                //    후행 쉼표
                },
                {
                    name : '칸나',
                    java : 80,
                    oracle : 70,
                },
                {
                    name : '리제',
                    java : 60,
                    oracle : 100,
                },                                    // 또 객체가 들어올 수도 있으니 후행 쉼표.   배열도 후행 쉼표 지원함.
            ] ;
 

            students.push( {
                name : '시로',
                java : 70,
                oracle : 40,
            } )
     
            console.log(students);
            console.log(students[0]);
            console.log(students[0].name);      //    .을 통해서 객체의 프로퍼티에 접근
       

        }


    </script>

   
</body>
</html>
 

 

 

 

- 대괄호로 감싸져 있으니 배열이다. 그 안에는 중괄호로 감싸져 있으니 객체다. 

펼쳐보면 각각의 인덱스에 어떤 객체가 담겨있는지 볼 수 있다.

- 0번 인덱스가 객체이므로 또 펼쳐서 객체의 속성에 접근해볼 수 있다.

 

 

 

- 나중에 웹개발 하면 응답 데이터로 ArrayList를 받는다.

ArrayList에는 주로 vo객체가 담겨 있다.

그걸 자바스크립트에서 출력해보면 이렇게 나온다.

 

 

 

 

객체 배열로 다수의 객체를 배열에 담아둔 이유는 관리의 편리성 때문이다.

- 반복문 사용 가능 (배열에 for 문, for in 문, for of문 다 가능)

 

 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

    <h2>객체 배열</h2>
    <button onclick="fnObjectArray();">객체 배열</button>


    <script>

        function fnObjectArray() {

            const students = [          // 배열 선언
                {
                    name : '유니',      // 0번 인덱스에 첫번째 객체 담기
                    java : 100,
                    oracle : 80,        //  후행 쉼표
                },
                {
                    name : '칸나',
                    java : 80,
                    oracle : 70,
                },
                {
                    name : '리제',
                    java : 60,
                    oracle : 100,
                },                       // 또 다른 객체가 들어올 수도 있으니 후행 쉼표. 배열도 후행 쉼표 지원함.
            ] ;

            students.push( {
                name : '시로',
                java : 70,
                oracle : 40,
            } )
 

     
            // for of 문으로 배열의 각 인덱스에 담겨있는 객체에 접근하기
            for(let stu of students) {      // {}, {}, {}, {}
                console.log(stu);
            }
            console.log("==================");

           
            // 각 객체에 속성을 일괄적으로 추가하기
            for(let stu of students) {      
                stu.front = 100;
 
                stu.getSum = function() {
                    return this.java + this.oracle + this.front;
                }
                stu.getAvg = function() {
                    return this.getSum() / 3 ;
                }
 
            }
            console.log(students);
            console.log("==================");

        }


    </script>

   
</body>
</html>
 

 

 

 

- 그런데 지금 students라는 배열 내에 담긴 객체를 보면 모든 객체가 다 동일한 속성을 가지고 있다. 

- 객체들을 direct로 중괄호 블록을 사용하여 생성하면 다 동일한 프로퍼티임에도 불구하고

매번 저 프로퍼티들을 기술해줘야 한다. 

이럴 때 아예 new라는 키워드로 객체를 생성하면 저 프로퍼티들을 가진 채로 만들어지게 설정할 수있다.

그게 생성자 함수.

 

 

 

 

 

 

ㅁ 생성자 함수

- 함수긴 한데 마치 생성자처럼 쓸 수 있는 함수를 만들 수 있다.

- new 키워드를 통해 객체 생성을 진행시킬 수 있는 함수다.

- 함수명의 첫글자는 대문자로 작성

 

- 화살표 함수로 작성 불가능

- 프로퍼티를 함수 내에 this.프로퍼티로 정의

 

 

- function 대문자로시작하는함수명 ( param1, param2, ... ) {

 

    // 일반 속성

    this.prop1 = param1;

    this.prop2 = param2;

    ...

 

    // 메소드 속성

    this.methodProp = function( ) {

        메소드내용

    }

 

}

 

new 대문자로시작하는함수명 (1, 2, ..);       //     저 값들이 프로퍼티에 대입된 채로 호출이 진행된다.

 

 

 

 

 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>


        <script>

            function Student(name, java, oracle, front) {   //   함수명 첫글자는 대문자로 작성

                // 일반 속성
                this.name = name;
                this.java = java;
                this.oracle = oracle;
                this.front = front;

                // 메소드 속성
                this.getSum = function() {
                    return this.java + this.oracle + this.front;
                }
                this.getAvg = function() {
                    return this.getSum() / 3;
                }


            }


            function fnConstructorTest() {
                const students = [     //    배열 정의
                    new Student('온앤온', 100, 70, 50),
                    new Student('정망개', 80, 90, 100),
                    new Student('금사향', 100, 60, 70)
                ];

                students.push(new Student('마마뫄', 60, 10, 70));

                console.log(students);
            }



        </script>


   
        <h2>생성자함수</h2>
        <button onclick="fnConstructorTest();">생성자함수확인</button>


</body>
</html>
 

 

 

- 직접 중괄호 블록을 썼을 때랑 생성자 함수를 썼을 때랑 살짝 다르다.

콘솔 출력된 것을 확인해보니 배열이긴 한데 각각의 인덱스에 Student가 담겨있다.

이 Student도 객체다.

 

 

 

 

- 확장해서 보면 0번 인덱스에 중괄호 블록의 객체, 1번 인덱스에 중괄호 블록의 객체, ...를 볼 수 있다.

- 중괄호 블럭으로 생성했을 때와 살짝 다르긴 한데 제어하는 방식과 접근하는 방식은 동일하다. 

다만, 객체를 중괄호 블럭이 아닌 생성자함수로 생성했다면 중괄호 앞에 생성자 함수명(Student)이 보여진다.

 

 

- 객체들이 가지고 있는 프로퍼티는 동일하다. 

이 Student 객체들도 확장해 보면 어떤 속성을 가지고 있는지 확인할 수 있다.

- 자주 생성시킬 객체의 형태는 생성자 함수를 정의해 두고 활용하면 편리하다.

미리 프로퍼티를 정의해 둔다면 이렇게 프로퍼티를 가지는 객체의 형태로 만들 수 있다.

 

 

 

 

 
                console.log(students);
                console.log(students[0]);
                console.log(students[0].name);
 

 

 

 

 

 

ㅁ 예제

 

 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

        <script>
            function fnPractice() {

                let cars = [
                    { model: 'K3', },   // 중괄호 블럭 하나하나가 객체다. maker 속성 추가 예정
                    { model: 'K5', },
                    { model: 'K7', },
                    { model: 'G70', },
                    { model: 'GV80', },
                    { model: 'G90', },          // 후행쉼표
                ];


                // cars 배열 내의 객체들 중
                // model 값이 'K'로 시작할 경우 maker: 'Kia'가 추가 되고
                // model 값이 'G'로 시작할 경우 maker: 'Genesis'가 추가되게끔
                // (생성자 함수랑은 상관 없음)

                for(let i=0; i<cars.length; i++) {

                    if( cars[i].model.startsWith('K') ) {
                        cars[i].maker = 'Kia';
                    }
                    else {
                        cars[i].maker = 'Genesis';
                    }

                }

                /* [답]
                for(let car of cars) { // {}, {}, {}
                    if( car.model.startsWith('K') ) {
                        car.maker = 'Kia';
                    }
                    else if( car.model.startsWith('G') ){
                        car.maker = 'Genesis';
                    }
                }
                */


                console.log(cars);

            }


        </script>

        <button onclick="fnPractice();">버튼</button>
 

</body>
</html>