MyList 프로젝트 - 클래스 다루기

사용자 정의 데이터 타입

• 회원정보, 영화정보, 주문정보와 같은 복합 데이터는 낱개의 변수를 사용하여 다루는 것보다 별도의 타입을 정의하여 한 단위로 묶어서 다루는 것이 편하다.
‐ 복합데이터 : 여러 개의 항목으로 구성된 데이터
‐ 회원정보(번호, 이름, 이메일, 전화, 주소 등)
영화정보(영화명, 설명, 제작사, 주연배우, 개봉일 등)
• 자바에서 제공하지 않는 데이터 타입을 정의할 때 사용하는 문법이 클래스이다.

규모가 작을 때는 안 묶어도 되는데 규모가 커지면 묶는다.

C → 구조체(structure)
C++ → 클래스

점점 규모가 커지니까 많은 코드를 다루기 편하게
데이터를 묶어서 다루는 문법이 등장

백엔드 개발 실습

MyList App 실행하기

http://localhost:8080/

1단계 - 연락처 정보를 한 단위로 묶어서 다룰 새 데이터 타입을 정의한다.

com.eomcs.mylist.Contact 클래스 정의

클래스 문법

클래스는 2가지 용도로 쓴다.

① 데이터 타입 정의 (user-defined Data Type)
user → 개발자

② 메서드 분류
메서드를 묶는다.

클래스 문법이 뭐냐?
→ 데이터 타입을 정의하거나 메서드 분류하는 용도로 사용하는 문법입니다.

클래스 문법 - 데이터 타입 정의

메모리 설계도

class 데이터타입명 {
  변수 선언
  ...
}
class Contact {
  String name;
  String email;
  String tel;
  String company;
}

⇒ 메모리 설계도
new 명령을 실행하면 클래스에 정의된 대로 변수가 준비된다.

클래스를 이용하여 새 데이터 타입의 메모리 만들기

new 데이터타입명();

데이터타입명 = 클래스명

클래스 설계도에 따라 변수(메모리) 준비 ⇒ Heap 영역에 준비됨
클래스 설계도에 따라 준비한 메모리 ⇒ '인스턴스(instance)=객체(object)'라고 한다.

주소를 받을 변수

데이터타입명 주소를 받을 변수 = new 데이터타입명();
Contact c = new Contact();

Contact 인스턴스의 주소를 저장하는 변수 = 레퍼런스(reference)
인스턴스의 주소를 저장

com.eomcs.mylist.Contact.java

package com.eomcs.mylist;

public class Contact {
  String name;
  String email;
  String tel;
  String company;
}

2단계 - 연락처 목록은 Contact 클래스의 배열로 변경한다.

com.eomcs.mylist.ContactController 클래스 변경
‐ 배열 변수 변경

레퍼런스 배열

레퍼런스 : 인스턴스의 주소를 저장하는 변수
C에서는 포인터(pointer)라고 한다.

Contact 설계도에 따라 준비한 메모리 ⇒ Contact의 인스턴스 ⇒ Contact의 객체

① 배열 사용 전

② 배열 사용 후

레퍼런스는 주소를 담는 거!

레퍼런스 배열 → 레퍼런스 변수를 한 번에 만든 거

자바에는 인스턴스 배열을 만드는 문법이 없다.

클래스 정의한 거 안에 있는 인스턴스는 Heap에 만들어진다.

클래스를 정의만 해놓고 사용을 하지 않으면 메모리에 올라가지 않는 거?
⇒ Method Area에 올라간다!

인스턴스와 인스턴스는 연속된 메모리가 아니다. 보장하지 않는다.

new 라는 명령어로 만드는 모든 변수는 Heap 영역에 올라간다.

레퍼런스 배열을 만들었다고 인스턴스가 존재하는 게 아니다.

이 선언은 레퍼런스 배열만 만든 상태

Contact[] contacts = new Contact[5];

레퍼런스 배열을 만든다.

Contact[] arr = new Contact[size];

  @RequestMapping("/contact/list")
  public Object list() {
    Contact[] arr = new Contact[size]; // 배열에 저장된 값만 복사할 새 배열을 만든다.
    for (int i = 0; i < size; i++) {
      arr[i] = contacts[i]; // 전에 배열에서 값이 들어 있는 항목만 복사한다.
    }
    return arr; // 복사한 항목들을 담고 있는 새 배열을 리턴한다.
  };

3단계 - REST API에 Contact 클래스를 적용한다.

com.eomcs.mylist.ContactController 클래스 변경
‐ list() 변경 ⇒ 웹 브라우저로 응답 결과 확인

public Object add(Contact contact)

  @RequestMapping("/contact/add")
  public Object add(Contact contact) {
    System.out.printf("%s,%s,%s,%s\n", contact,name, contact.email, contact.tel, contact.company);
    /*
    if (size == contacts.length) {   // 배열이 꽉 찼다면,
      contacts = grow(); // 메서드 이름에서 해당 코드에 대한 설명을 짐작할 수 있다.
    }
    contacts[size++] = createCSV(name, email, tel, company);
    */
    return size;
  }

http://localhost:8080/contact/add?name=aaa&email=aaa@test.com&tel=010-0000-0000&company=abc

null 나옴

com.eomcs.mylist.Contact.java 가서
오른쪽 마우스 클릭 - Source - Generate Getters and Setters... 클릭

Select All 클릭 - Generate 클릭
Select All → 모든 변수에 대해서 다 게터 세터를 만들겠다

실무에서는 롬복이라고 불리는 api가 있음
롬복을 쓰면 게터 세터 만들 필요가 없는데 아직 그걸 사용할 때가 아님

package com.eomcs.mylist;

public class Contact {
  String name;
  String email;
  String tel;
  String company;

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getEmail() {
    return email;
  }
  public void setEmail(String email) {
    this.email = email;
  }
  public String getTel() {
    return tel;
  }
  public void setTel(String tel) {
    this.tel = tel;
  }
  public String getCompany() {
    return company;
  }
  public void setCompany(String company) {
    this.company = company;
  }
}
  @RequestMapping("/contact/add")
  public Object add(Contact contact) {

    System.out.println("%s,%s,%s,%s", contact.name, contact.email, contact.tel, contact.company);

    /*
    if (size == contacts.length) {   // 배열이 꽉 찼다면,
      contacts = grow(); // 메서드 이름에서 해당 코드에 대한 설명을 짐작할 수 있다.
    }
    contacts[size++] = createCSV(name, email, tel, company);
     */

    return size;
  }

이게 스프링 부트의 최소 조건..

Generate toString()

Generate 클릭

toString()
이 안에 있는 변수를 한 줄의 문자열로 만들어서 리턴해주는 메소드
설계도에 따라서 만든 인스턴스 변수의 값을 한 줄의 문자열로 만들어서 리턴해주는 메소드

toString()을 사용하면 메모리 안에 어떤 이름, 어떤 이메일 등이 들어있는지 꺼내 보기가 편함

package com.eomcs.mylist;

public class Contact {
  String name;
  String email;
  String tel;
  String company;

  @Override
  public String toString() {
    return "Contact [name=" + name + ", email=" + email + ", tel=" + tel + ", company=" + company
        + "]";
  }
  
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getEmail() {
    return email;
  }
  public void setEmail(String email) {
    this.email = email;
  }
  public String getTel() {
    return tel;
  }
  public void setTel(String tel) {
    this.tel = tel;
  }
  public String getCompany() {
    return company;
  }
  public void setCompany(String company) {
    this.company = company;
  }
}

System.out.println(contact.toString());

  @RequestMapping("/contact/add")
  public Object add(Contact contact) {

    System.out.println(contact.toString());

    /*
    if (size == contacts.length) {   // 배열이 꽉 찼다면,
      contacts = grow(); // 메서드 이름에서 해당 코드에 대한 설명을 짐작할 수 있다.
    }
    contacts[size++] = createCSV(name, email, tel, company);
     */

    return size;
  }

toString() 메서드가 한 줄의 문자열로 만들어준 걸 리턴

PCR 검사 받고 오라고 하면 굳이 말 안 해도 어떻게 해야 되는지 알고 있음
얘가 그래요
println한테 contact.toString() 메서드 호출해서 contact이 가리키는 메모리에 들어 있는 각각의 변수 값을 꺼내서 문자열을 리턴 받아서 println에 넘기는데
굳이 얘기 안 해도 됨. toString() 지우기.

굳이 얘기 안 해도 println은 객체 주소를 넘겨주면 알아서 toString() 메소드를 호출해서 그 메소드가 리턴한 값을 화면에 뿌린다. 그러므로 굳이 직접 toString() 할 필요가 없다.
내부적으로 toString() 호출

System.out.println(contact.toString());System.out.println(contact);

인스턴스 안에 있는 값을 출력하고 싶으면 그냥 println 하고 인스턴스의 주소를 주면 됨
다른 작업 필요 없이 주소만 주면 됨

  @RequestMapping("/contact/add")
  public Object add(Contact contact) {

    System.out.println(contact);

    /*
    if (size == contacts.length) {   // 배열이 꽉 찼다면,
      contacts = grow(); // 메서드 이름에서 해당 코드에 대한 설명을 짐작할 수 있다.
    }
    contacts[size++] = createCSV(name, email, tel, company);
     */

    return size;
  }

잘 나옴

인스턴스 안에 있는 값을 출력하고 싶으면 그냥 println 하고 인스턴스의 주소를 주면 됨
다른 작업 필요 없이 주소만 주면 됨

Spring Boot와 인스턴스 파라미터

  1. 클래스 사용법 1

Spring Boot와 클래스 파라미터

① add?name=aaa&email=aaa@test.com&tel=010-0000-0000&company=abc
웹 브라우저에서 스프링 부트에게 요청을 보내는데
add?name=aaa&email=aaa@test.com&tel=010-0000-0000&company=abc
이렇게 값을 넘긴다

② 인스턴스 생성 → 요청 파라미터 값 저장
그러면 스프링 부트가 ContactController에 대해서 여기 있는 메소드 중에서 add 라는 메소드를 호출한다
이때 add 라는 메소드를 호출할 때 이렇게 함
new Contact() 인스턴스를 생성한다
파라미터가 Contact이기 때문
이름과 일치하는 거 찾아서 값을 저장함
변수가 아니라 세터 메소드를 찾아서 저장

③ add() 호출
바로 이 부분
Spring Boot는 페이지 컨트롤러의 요청핸들러를 호출하기 전에
add()에 선언된 클래스 인스턴스를 만든다.
요청 파라미터의 값을 그 인스턴스의 각 변수에 저장한다.
요청 파라미터 이름과 인스턴스의 세터 메서드명이 같아야 한다.
요청 파라미터 이름이 name이라면 인스턴스의 세터 메서드명은 setName()이어야 한다.

변수 이름과 일치하는 게 아니라 세터 메서드 이름과 일치해야 되는 거

게터 세터 지우고 다시 해보기

package com.eomcs.mylist;

public class Contact {
  String name;
  String email;
  String tel;
  String company;

  @Override
  public String toString() {
    return "Contact [name=" + name + ", email=" + email + ", tel=" + tel + ", company=" + company
        + "]";
  }

}

null로 나옴
변수명은 상관 없는 거

쿼리 스트링과 요청 핸들러의 파라미터

?name=aaa&email=aaa@test.com&tel=010-0000-0000&company=비트캠프

Object add(String name, String email, String tel, String company) {...}

?name=aaa&email=aaa@test.com&tel=010-0000-0000&company=비트캠프

Object add(Contact contact) {...}
Contact 인스턴스 만든 후에 값 저장한 후에 파라미터에 집어 넣는다

쿼리 스트링의 파라미터 이름과 세터 메서드 이름의 관계

?name=aaa&email=aaa@test.com&tel=010-0000-0000&company=비트캠프

 파라미터          세터 메서드
  name      ⟶     setName()
  email     ⟶     setEmail()
  tel       ⟶     setTel()
  company   ⟶     setCompany()
  basicAddr   ⟶   setBasicAddr()
  firstName   ⟶   setFirstName()

변수명은 쿼리 스트링의 파라미터와 상관없다!

세터 메서드는 쿼리 스트링의 파라미터와 관련있다.

세터 메서드 이름이 같아야 스프링 부트가 자동으로 꽂아주는 거

3교시 시작

전체 명령 코드는 Method Area 영역에 들어간다
그 중에서 설계 도면을 보고 여기 나와 있는 명령어대로 Heap 영역에 메모리를 만든다.
레퍼런스 변수 ← 인스턴스 주소를 받는다
레퍼런스 변수는 메서드를 호출한 쪽에서 넘겨줌
메서드를 누가 호출한다? 스프링 부트가 호출한다.
스프링 부트가 Contact 클래스의 인스턴스를 만들고 그 인스턴스 주소를 넘겨준다.
웹 브라우저가 스프링 부트에게 add 해달라고 요청한다. 쿼리 스트링으로 값을 넘긴다.
스프링 부트는 ContactController에 add 라는 메서드를 호출하려고 하는데 add 메서드가 요구하는 게 Contact 인스턴스의 주소다. 스프링 부트가 Contact 인스턴스를 만든다. 만든 후에 세터를 통해서 클라이언트가 보낸 값들을 인스턴스의 각 변수에 담는다. 담은 다음에 그 인스턴스의 주소를 넘겨준다.
println에 인스턴스 주소를 주면 내부적으로 toString()을 호출해서 인스턴스 값을 꺼낸 다음에 출력한다.

레퍼런스 배열을 늘리는 거

Contact 배열이라고 하지 Contact 레퍼런스 배열이라고 안 함

package com.eomcs.mylist;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController 
// 이 클래스가 클라이언트 요청 처리 담당자임을 표시한다.
// 이 표시(애노테이션)가 붙어있어야만 스프링 부트가 인식한다.
public class ContactController {

  Contact[] contacts = new Contact[5];
  int size = 0;

  @RequestMapping("/contact/list")
  public Object list() {
    Contact[] arr = new Contact[size]; // 배열에 저장된 값만 복사할 새 배열을 만든다.
    for (int i = 0; i < size; i++) {
      arr[i] = contacts[i]; // 전에 배열에서 값이 들어 있는 항목만 복사한다.
    }
    return arr; // 복사한 항목들을 담고 있는 새 배열을 리턴한다.
  };


  @RequestMapping("/contact/add")
  public Object add(Contact contact) {

    System.out.println(contact);


    if (size == contacts.length) {   // 배열이 꽉 찼다면,
      contacts = grow(); // 메서드 이름에서 해당 코드에 대한 설명을 짐작할 수 있다.
    }

    /*
    contacts[size++] = createCSV(name, email, tel, company);
     */

    return size;
  }

  /*
  @RequestMapping("/contact/get")
  public Object get(String email) {
    int index = indexOf(email);
    if (index == -1) {
      return "";
    } 

    return contacts[index];

  }

  @RequestMapping("/contact/update")
  public Object update(String name, String email, String tel, String company) {
    int index = indexOf(email);
    if (index == -1) {
      return 0;
    }

    contacts[index] = createCSV(name, email, tel, company);
    return 1;
  }

  @RequestMapping("/contact/delete")
  public Object delete(String email) {
    int index = indexOf(email);
    if (index == -1) {
      return 0;
    }

    remove(index);  // 메서드 이름으로 코드의 의미를 짐작할 수 있다. 이것이 메서드로 분리하는 이유이다.
    return 1;

  }

  // 기능:
  // - 입력 받은 파라미터 값을 가지고 CSV 형식으로 문자열을 만들어 준다.
  String createCSV(String name, String email, String tel, String company) {
    return name + "," + email + "," + tel + "," + company;
  }

  // 기능:
  // - 이메일로 연락처 정보를 찾는다.
  // - 찾은 연락처의 배열 인덱스를 리턴한다.
  //
  int indexOf(String email) {
    for (int i = 0; i < size; i++) {
      if (contacts[i].split(",")[1].equals(email)) {
        return i;
      }
    }
    return -1;
  }

  // 기능:
  // - 배열에서 지정한 항목을 삭제한다.
  // 
  String remove(int index) {
    String old = contacts[index];
    for (int i = index + 1; i < size; i++) {
      contacts[i-1] = contacts[i]; // 한 칸씩 앞으로 당긴다
    }
    size--;
    return old;
  }
   */

  // 기능:
  // - 배열의 크기를 늘린다.
  // - 기존 배열의 값을 복사해온다.
  //
  Contact[] grow() {
    Contact[] arr = new Contact[newLength()];
    copy(contacts, arr);
    return arr;
  }


  // 기능:
  // - 주어진 배열에 대해 50% 증가시킨 새 배열의 길이를 알려준다.
  int newLength() {
    return contacts.length + (contacts.length >> 1);
  }


  // 기능:
  // - 배열을 복사한다.
  //
  void copy(Contact[] source, Contact[] target) {
    // 개발자가 잘못 사용할 것을 대비하여 다음 코드를 추가한다.
    // 즉 target 배열이 source 배열보다 작을 경우 target 배열 크기만큼만 복사한다.
    int length = source.length;
    if (target.length < source.length) {
      length = target.length;
    }
    for (int i = 0; i < length; i++) {
      target[i] = source[i];
    }
  }
}
  @RequestMapping("/contact/add")
  public Object add(Contact contact) {

    System.out.println(contact);

    if (size == contacts.length) {   // 배열이 꽉 찼다면,
      contacts = grow(); // 메서드 이름에서 해당 코드에 대한 설명을 짐작할 수 있다.
    }

    contacts[size++] = contact;

    return size;
  }

CreateCSV() 필요 없어져서 삭제

스프링 부트가 인스턴스를 만들고 인스턴스 주소를 넘긴다

  // 기능:
  // - 이메일로 연락처 정보를 찾는다.
  // - 찾은 연락처의 배열 인덱스를 리턴한다.
  //
  int indexOf(String email) {
    for (int i = 0; i < size; i++) {
      Contact contact = contacts[i];
      if (contact.email.equals(email)) {
        return i;
      }
    }
    return -1;
  }

레퍼런스와 인스턴스 변수

① 인스턴스 변수에 값 저장

인스턴스 주소를 알고 있는 레퍼런스.인스턴스 변수
c.name
c.email

② 인스턴스 변경

c = new Contact();

기존의 200번지에서 300번지로 바뀜

c.name = "임꺽정";

기존 인스턴스의 주소를 알고 있는 레퍼런스가 한 개도 없으면 "Garbage"가 된다.

레퍼런스는 언제든지 다른 인스턴스의 주소를 가질 수 있다.

  @RequestMapping("/contact/get")
  public Object get(String email) {
    int index = indexOf(email);
    if (index == -1) {
      return "";
    } 

    return contacts[index];

  }
  int indexOf(String email) {
    for (int i = 0; i < size; i++) {
      Contact contact = contacts[i];
      if (contact.email.equals(email)) {
        return i;
      }
    }
    return -1;
  }

자바 객체를 JSON 문자열로 바꾼 거

백엔드 개발자는 UI 없어도 이렇게 테스트할 수 있어야 함

  @RequestMapping("/contact/update")
  public Object update(Contact contact) {
    int index = indexOf(contact.email);
    if (index == -1) {
      return 0;
    }

    contacts[index] = contact;
    return 1;
  }

낱개로 데이터를 다루는 게 아니라 클래스를 사용해서 변수들을 묶어서 한 단위로 다룬다.

http://localhost:8080/contact/update?name=a2xx&email=a2@test.com&tel=010-0000-0000xx&company=비트캠프xx

리스트에 없는 거라서 0 나옴

  // 기능:
  // - 배열에서 지정한 항목을 삭제한다.
  // 
  Contact remove(int index) {
    Contact old = contacts[index];
    for (int i = index + 1; i < size; i++) {
      contacts[i-1] = contacts[i]; // 한 칸씩 앞으로 당긴다
    }
    size--;
    return old;
  }

리턴한 거 꼭 써야 됩니까?
쓸 사람은 쓰라고 리턴하라고

이미 지운 거 또 지우라고 해보면 0 나옴

package com.eomcs.mylist;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController 
// 이 클래스가 클라이언트 요청 처리 담당자임을 표시한다.
// 이 표시(애노테이션)가 붙어있어야만 스프링 부트가 인식한다.
public class ContactController {

  Contact[] contacts = new Contact[5];
  int size = 0;

  @RequestMapping("/contact/list")
  public Object list() {
    Contact[] arr = new Contact[size]; // 배열에 저장된 값만 복사할 새 배열을 만든다.
    for (int i = 0; i < size; i++) {
      arr[i] = contacts[i]; // 전에 배열에서 값이 들어 있는 항목만 복사한다.
    }
    return arr; // 복사한 항목들을 담고 있는 새 배열을 리턴한다.
  };


  @RequestMapping("/contact/add")
  public Object add(Contact contact) {

    System.out.println(contact);

    if (size == contacts.length) {   // 배열이 꽉 찼다면,
      contacts = grow(); // 메서드 이름에서 해당 코드에 대한 설명을 짐작할 수 있다.
    }

    contacts[size++] = contact;

    return size;
  }


  @RequestMapping("/contact/get")
  public Object get(String email) {
    int index = indexOf(email);
    if (index == -1) {
      return "";
    } 

    return contacts[index];

  }


  @RequestMapping("/contact/update")
  public Object update(Contact contact) {
    int index = indexOf(contact.email);
    if (index == -1) {
      return 0;
    }

    contacts[index] = contact;
    return 1;
  }


  @RequestMapping("/contact/delete")
  public Object delete(String email) {
    int index = indexOf(email);
    if (index == -1) {
      return 0;
    }

    remove(index);  // 메서드 이름으로 코드의 의미를 짐작할 수 있다. 이것이 메서드로 분리하는 이유이다.
    return 1;

  }


  // 기능:
  // - 이메일로 연락처 정보를 찾는다.
  // - 찾은 연락처의 배열 인덱스를 리턴한다.
  //
  int indexOf(String email) {
    for (int i = 0; i < size; i++) {
      Contact contact = contacts[i];
      if (contact.email.equals(email)) {
        return i;
      }
    }
    return -1;
  }


  // 기능:
  // - 배열에서 지정한 항목을 삭제한다.
  // 
  Contact remove(int index) {
    Contact old = contacts[index];
    for (int i = index + 1; i < size; i++) {
      contacts[i-1] = contacts[i]; // 한 칸씩 앞으로 당긴다
    }
    size--;
    return old;
  }


  // 기능:
  // - 배열의 크기를 늘린다.
  // - 기존 배열의 값을 복사해온다.
  //
  Contact[] grow() {
    Contact[] arr = new Contact[newLength()];
    copy(contacts, arr);
    return arr;
  }


  // 기능:
  // - 주어진 배열에 대해 50% 증가시킨 새 배열의 길이를 알려준다.
  int newLength() {
    return contacts.length + (contacts.length >> 1);
  }


  // 기능:
  // - 배열을 복사한다.
  //
  void copy(Contact[] source, Contact[] target) {
    // 개발자가 잘못 사용할 것을 대비하여 다음 코드를 추가한다.
    // 즉 target 배열이 source 배열보다 작을 경우 target 배열 크기만큼만 복사한다.
    int length = source.length;
    if (target.length < source.length) {
      length = target.length;
    }
    for (int i = 0; i < length; i++) {
      target[i] = source[i];
    }
  }

}

프론트 엔드 개발 실습

1단계 - 서버에서 받은 JSON 형식의 문자열을 자바스크립트 객체로 전환하여 다룬다.

‐ /contact/index.html 변경
‐ /contact/view.html 변경

개발자들에게 자바스크립트 객체로 이쁘게 보여준 거

이 문자열을 가지고 자바스크립트 객체를 만든다

JSON에서 모든 문자열은 반드시 더블 쿼테이션

  fetch("/contact/list")
    .then(function(response) {
      return response.json();
    })
    .then(function(contacts) {
      console.log(contacts);
      for (var contact of contacts) {
        var tr = document.createElement("tr");
        tr.innerHTML = `<td><a href="view.html?email=${contact.email}">${contact.name}</a></td>
        <td>${contact.email}</td>
        <td>${contact.tel}</td>
        <td>${contact.company}</td>`;
        tbody.appendChild(tr);
      }
    });

view.html

  // 3) 서버에서 데이터 가져오기
  fetch(`/contact/get?email=${email}`)
    .then(function(response) {
      return response.json();
    })
    .then(function(contact) {
      var values = contact.split(",");

response 객체에서
response.json() 파싱해서 자바스크립트 객체로 만들어서 객체 주소를 넘김
response.json() 이거 실행하는 데 시간이 걸림
등록해두고 진짜 응답오면 얘가 호출이 될 것이고
지금은 호출될 함수를 등록하는 거
이 함수가 실행이 완료된 후에 얘를 실행해줘
then

웹 브라우저에서 함수 호출

  // 3) 서버에서 데이터 가져오기
  fetch(`/contact/get?email=${email}`)
    .then(function(response) {
      return response.json();
    })
    .then(function(contact) {
      // 4) 연락처 상세 정보를 화면에 출력한다.
      xName.value = contact.name;
      xEmail.value = contact.email;
      xTel.value = contact.tel;
      xCompany.value = contact.company;
    })

1단계 - 서버에서 받은 JSON 형식의 문자열을 자바스크립트 객체로 전환하여 다룬다.
‐ /contact/index.html 변경
‐ /contact/view.html 변경

자바스크립트 - eomcs.web.ex04

http://localhost:8080/javascript/ex04/exam01.html

최소 Object 라는
toString ← 자바에 있는 toString과 똑같다
생성자를 호출하지 않았기 때문에 아무것도 없다
이 방법은 자바스크립트 라이브러리
라이브러리: 다른 개발자가 쓰라고 만드는 거
나 뿐만 아니라 다른 개발자가 사용할 유용한

보통 3번 방법과 4번 방법을 쓸 거임

가장 많이 쓰는 게 4번 방법
단축 코드

자바스크립트 객체를 만드는 데 설계도가 따로 없다

빈 객체가 아니라 기본 객체

객체 생성

51-자바스크립트 / 19 페이지

객체를 초기화 시키는 함수를 "생성자(constructor)"라 부른다.
객체를 초기화 시킨다는 의미는?
객체가 주어진 역할을 하는 데 필요한 변수나 함수를 준비하는 것
프로토타입 : 객체를 초기화시킨 생성자를 가리킨다.

prototype: 원형 객체

Object()처럼 빈 객체를 초기화시키는 함수를 "생성자 함수(constructor)"라 부른다.

var obj = new Object();

① 빈 객체 생성 ← new
② Object() 호출 → 기본 변수, 함수 추가

obj도 레퍼런스

console.log(obj.toString());

[object Object] ← 객체인데 Object가 초기화 시킨 객체예요

console.log(obj.valueOf());

값 출력

console.log(obj.hasOwnProperty("toString")); // false

hasOwnProperty()는 기본 객체를 생성한 이후에 개발자가 추가한 프로퍼티인지 검사한다.

프로퍼티명이 변수명

퉁쳐서 프로퍼티라고 한다.

hasOwnProperty

console.log(obj.hasOwnProperty("title"));  // true
console.log(obj.hasOwnProperty("content")); // true
console.log(obj.hasOwnProperty("viewCount")); // true
console.log(obj.hasOwnProperty("plus1")); // true
console.log(obj.hasOwnProperty("plus2")); // true
console.log(obj.hasOwnProperty("plus3")); // true

나중에 추가한 건 true

함수명은 그 자체가 함수 객체의 주소를 갖고 있는 변수이다.

익명 함수를 바로 넣을 수도 있고
화살표 함수를 바로 넣어도 됨

obj.plus1(100, 200);
obj["plus2"](100, 200);
obj['plus3'](100, 200);

global 객체

함수 객체도 객체

프로퍼티의 값으로 다른 객체의 주소를 저장할 수 있다.

객체를 포함할 순 없음

실제로는 품고 있는 게 아니라 그 주소를 갖고 있는 거

obj.other.v4();
객체 선(연결) 그래프를 따라가는 경로를 표기한 문법
Object Graph Navigation Language => OGNL 표기법
객체에 접근하기 위한 언어

따라 들어가는 거

객체와 객체를 따라가는 거

graph 선형 그래프

값을 꺼내고 세팅할 때 표기법

객체가 다른 객체를 담는다는 것은 객체의 주소를 갖고 있는 거

참조변수 this

같은 방에 들어있으면 this 라고 해줘야 됨

자바에서는 println()에 객체 주소를 주면
println()에서 내부적으로 해당 객체의 toString() 호출한다.
그리고 그 리턴 값을 출력한다.
그러나 자바스크립트의 console.log()는
자바와 달리 toString()의 리턴 값을 출력하지 않는다.

자기가 소속된 객체를 가리키는 게 this

toString()은 이미 객체에 들어 있는 함수이다.
다음은 기존 함수를 덮어 쓴다.

{}은 기본 객체를 생성하는 단축 문법이다.

자바스크립트에서 프로퍼티는 변수도 프로퍼티라고 부르고

자바에서 프로퍼티는 게터 세터 이것들을 프로퍼티라고 한다.

Object 생성 코드와 JSON

프로퍼티 이름은 다음 3가지 형태로 작성 가능

문자열은 "", '' 사용 가능

자바스크립트 객체 생성 코드를 참고해서 만든 데이터 표현 형식
JavaScript Object Notation => JSON
프로퍼티 이름은 반드시 문자열로 표현해야 한다.
반드시 더블 쿼테이션
문자열은 반드시 더블 쿼테이션""을 사용해야 한다.

JSON은 데이터 표현 형식

앞에 function 쓰면 에러!!

	sum() {
	    return this.kor + this.eng + this.math; 
	},

this는 obj랑 주소가 같다

arrow function에서 this는 소속된 객체가 아니라 window 객체를 가리킨다.

exam10-2.html
레퍼런스 배열
반복문을 돌릴 수 있어서 좋다

// 배열을 이용하여 여러 개의 객체를 다루기
var scores = []; //new Array();

window : 최상위 글로벌 객체

자바스크립트도 객체에 배열을 만들 방법이 없음
레퍼런스 배열이고
객체는 new Object() 아니면 {} 이걸로 만드는 방법 밖에 없음

exam10-3.html

아직 부족한 점!
=> 특정 과목의 점수가 바뀌면 다시 합계와 평균을 계산해야 한다.

sum은 더 이상 변수가 아니라 함수

obj.sum = kor + eng + math;
obj.sum = function() {
  return this.kor + this.eng + this.math;
};

함수로 바꿨기 때문에 출력할 때도

함수 객체 주소를 저장하는 거

함수 추가한다고 짤막하게 표현

exam10-5.html
객체를 리턴하는 거 = 객체 주소를 리턴하는 거

객체 넘겨
객체 받아

new 뒤에 오는 함수는 생성자로서의 역할을 한다

앞에 아무것도 없으면 Object()로 초기화시킨 객체

앞에 이름이 있으면 아 이 객체는 이 함수로 초기화시킨 객체구나

이 함수가 생성자 함수 용도인지
자기가 만든 거니까
다른 개발자는 이 메소드 이름만 보더라도 얘가 생성자로서 역할을 하는지
생성자 함수는 자바의 클래스처럼 대문자로 시작한다!

new를 썼을 때만 this.Object(); 이게 제일 먼저 실행된다.

https://velog.io/@banana/2021-12-15목-6주차-4일

이때 this 변수에는 new 명령으로 만든 객체의 주소가 들어 있다.

생성자 호출 과정과 객체 초기화

new creatScore();

① 빈 객체 생성 ← new
creatScore() 호출
this.Object() 호출 → 기본 프로퍼티 추가
creatScore()의 프로퍼티 추가 (있으면)

this.Object();가 없어도 자동으로 수행된다.

instanceof를 사용하면 그 객체를 초기화시킨 생성자를 확인할 수 있다.

createScore() 내부에서 Object() 생성자를 호출한다.

ex04 - exam01 부터 exam10-7 까지 복습하기

2개의 댓글

comment-user-thumbnail
2021년 12월 21일

ohola !

1개의 답글