[JavaScript] 클래스 & 프로토타입


1. Argument와 Rest Parameters 차이

arguments 객체는 함수에 전달된 인수에 해당하는 Array 형태의 객체입니다.

[arguments 객체 - JavaScriptMDN](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/arguments)

1.나머지 매개변수(Rest Parameters) 구문을 사용해야 한다 2. Array형태”란 arguments가 length 속성과 더불어 0부터 인덱스 된 다른 속성을 가지고 있지만, Array의 forEach,map과 같은 내장 메서드를 가지고 있지 않다

1): Argument

/*  Argument 출력 */
{


  function getName(name){
		/* name: argument(인자)  */
    console.log(name)
    console.log(name[0])
    console.log(name[1])
    console.log(name[2])
  }
  getName("유재석");
  getName("강호동","이수근");
}

/*
  함수로 넘어온 모든 인수의 접근
  함수 내 이용이 가능
  index/length
  Array 형태의 객체 ( 실제 배열이아님)
  배열의 내장메서드 forEach,map 등은 사용 불가능
  요즘은 많이 사용하지 않음
*/

=>결과값

// argument 출력시 string으로 출력

[Running] node "/workspaces/codespaces-blank/index.js"
유재석



강호동




[Done] exited with code=0 in 0.056 seconds


2): Rest Parameters

함수가 정해지지 않은 수의 매개변수를 배열로 받을 수 있음

[나머지 매개변수 - JavaScriptMDN](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/rest_parameters)

나머지 매개변수와 arguments`객체 사이의 세 개의 주요 차이

(1): arguments 객체는 실제 배열이 아닙니다. 그러나 나머지 매개변수는 Array 인스턴스이므로 sortmapforEachpop` 등의 메서드를 직접 적용할 수 있습니다.

(2): ...restParam은 후속 매개변수만 배열에 포함하므로 ...restParam 이전에 직접 정의한 매개변수는 포함하지 않습니다. 그러나 arguments 객체는, ...restParam의 각 항목까지 더해 모든 매개변수를 포함합니다.

(3): arguments 객체는 callee 속성과 같은 추가 기능을 포함합니다.

1. Rest Param 기본 출력

/*  Rest Parameters 데이터 출력 */
{
  function setName(...name){
    console.log(name)
  }
  setName("강호동");
  setName("강호동","유재석");
  setName("강호동","유재석","김다미");
}

=> 결과값

// Rest Param 출력시 Array로 출력

[Running] node "/workspaces/codespaces-blank/index.js"
[ '강호동' ]
[ '강호동', '유재석' ]
[ '강호동', '유재석', '김다미' ]

[Done] exited with code=0 in 0.051 seconds

3): Argument , Rest Parameters 데이터 출력 차이

1. Arguement로 forEach 출력

{
	  function sum(numbers){
	    let result = 0
	    numbers.forEach(num=>result+=num)
	    console.log(result);
		}
    sum(10,20,30,40,50)
}

=> 결과값

/* 메서드 적용이 안됌 */

[Running] node "/workspaces/codespaces-blank/index.js"
file:///workspaces/codespaces-blank/index.js:5
    numbers.forEach(num=>result+=num)
            ^

TypeError: numbers.forEach is not a function
    at sum (file:///workspaces/codespaces-blank/index.js:5:13)
    at file:///workspaces/codespaces-blank/index.js:8:5
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)

Node.js v19.7.0

[Done] exited with code=1 in 0.048 seconds

----------------------------------------------------------------------------

2. Rest Param으로 reduce 출력

{
  function add(numbers){
    let result = 0
    result=numbers.reduce((current,acc)=>current+acc);
    //reduce = 현재값 + 누적값
    console.log(result);
  }
  add(10,20,30,40,50)
}

=> 결과값

/* 메서드 적용이 안됌 */

[Running] node "/workspaces/codespaces-blank/index.js"
file:///workspaces/codespaces-blank/index.js:5
    result=numbers.reduce((current,acc)=>current+acc);
                   ^

TypeError: numbers.reduce is not a function
    at add (file:///workspaces/codespaces-blank/index.js:5:20)
    at file:///workspaces/codespaces-blank/index.js:9:3
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)

Node.js v19.7.0

[Done] exited with code=1 in 0.047 seconds

----------------------------------------------------------------------------

2. Rest Param으로 forEach 출력

{
  function sum(...numbers){
    let result = 0
    numbers.forEach(num=>result+=num)
    console.log(result);
  }
  sum(10,20,30,40,50)
}

=> 결과값

[Running] node "/workspaces/codespaces-blank/index.js"
150

[Done] exited with code=0 in 0.055 seconds

----------------------------------------------------------------------------

4. Rest Param으로 reduce 출력

{
  function add(...numbers){
    let result = 0
    result=numbers.reduce((current,acc)=>current+acc);
    //reduce = 현재값 + 누적값
    console.log(result);
  }
  add(10,20,30,40,50)
}

=> 결과값

[Running] node "/workspaces/codespaces-blank/index.js"
150

[Done] exited with code=0 in 0.055 seconds


2. JSON.stringify()

JSON.stringify()

메서드는 JavaScript 값이나 객체를 JSON 문자열로 변환합니다. 선택적으로, replacer를 함수로 전달할 경우 변환 전 값을 변형할 수 있고, 배열로 전달할 경우 지정한 속성만 결과에 포함합니다.

매개변수

value : JSON 문자열로 변환할 값.

replacer : 문자열화 동작 방식을 변경하는 함수, 혹은 JSON 문자열에 포함될 값 객체의 속성들을 선택하기 위한 화이트리스트(whitelist)로 쓰이는 String 과 Number` 객체들의 배열. 이 값이 null 이거나 제공되지 않으면, 객체의 모든 속성들이 JSON 문자열 결과에 포함된다.

space  : 가독성을 목적으로 JSON 문자열 출력에 공백을 삽입하는데 사용되는 String 또는 Number 객체. 이것이 Number 라면, 공백으로 사용되는 스페이스(space)의 수를 나타낸다; 이 수가 10 보다 크면 10 으로 제한된다. 1 보다 작은 값은 스페이스가 사용되지 않는 것을 나타낸다. 이것이 String` 이라면, 그 문자열(만약 길이가 10 보다 길다면, 첫번째 10 개의 문자)이 공백으로 사용된다. 이 매개 변수가 제공되지 않는다면(또는 null 이면), 공백이 사용되지 않는다.

C를 제외한 모든 프로그래밍 언어는 객체 지향 패러다임을 기반으로 만들어짐.

클래스 문법으로 객체를 효율적이고 안전하게 만듬.

프로그램에 필요한 요소만 사용하여 객체를 표현하는 것을 추상화라고함.

[JSON.stringify() - JavaScriptMDN](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#매개변수)

1): JSON.stringify 활용

/*  객체와 배열 조합 */
{
  /* 1. value (JSON 문자열로 변환할 값.) */

  const students = [];
  students.push({ 이름: "구름", 국어: 87, 영어: 98, 수학: 88, 과학: 90 });
  students.push({ 이름: "별이", 국어: 92, 영어: 98, 수학: 96, 과학: 88 });
  students.push({ 이름: "겨울", 국어: 76, 영어: 96, 수학: 94, 과학: 86 });
  students.push({ 이름: "바다", 국어: 98, 영어: 52, 수학: 98, 과학: 92 });

  /* 2. replacer (문자열화 동작 방식을 변경하는 함수) */

  function replacer(key, value) {
    /* 이름이 string일때 학생으로 이름 출력 */
    if (typeof value === "string") {
      return "학생";
    }
    return value;
  }

  /* 3. space (공백 스페이스 2) */

  console.log(JSON.stringify(students, replacer, 2));
}

3. 객체 생성 활용

장점

1): 오탈자 위험 감소

2): 코드 입력 양이 줄어듦

3): 속성과 메소드를 한 함수 내부에서 관리할 수 있으므로 객체를 더 손쉽게 유지보수 가능

/*  객체를 생성하는 함수 */

{

  function createStudent(이름,국어,영어,수학,과학){
    return {
        //속성 선언
        이름: 이름,
        국어: 국어,
        영어: 영어,
        수학: 수학,
        과학: 과학,
        //메소드를 선언
        getSum(){
            return this.국어 + this.영어 + this.영어 + this.수학 + this.과학
        },
        getAverage(){
            return this.getSum()/4
        },
        toString(){
            return `${this.이름}\t${this.getSum()}점\t${this.getAverage()}점\n`
        }
    }
}
    //객체 선언
    const students =[]
    students.push(createStudent('구름',87,98,88,90))
    students.push(createStudent('별이',92,98,96,88))
    students.push(createStudent('겨울',76,96,94,86))
    students.push(createStudent('바다',98,52,98,92))

    console.log(students)
}

=> 결과값

[Running] node "/workspaces/codespaces-blank/index.js"
[
  {
    '이름': '구름',
    '국어': 87,
    '영어': 98,
    '수학': 88,
    '과학': 90,
    getSum: [Function: getSum],
    getAverage: [Function: getAverage],
    toString: [Function: toString]
  },
  {
    '이름': '별이',
    '국어': 92,
    '영어': 98,
    '수학': 96,
    '과학': 88,
    getSum: [Function: getSum],
    getAverage: [Function: getAverage],
    toString: [Function: toString]
  },
  {
    '이름': '겨울',
    '국어': 76,
    '영어': 96,
    '수학': 94,
    '과학': 86,
    getSum: [Function: getSum],
    getAverage: [Function: getAverage],
    toString: [Function: toString]
  },
  {
    '이름': '바다',
    '국어': 98,
    '영어': 52,
    '수학': 98,
    '과학': 92,
    getSum: [Function: getSum],
    getAverage: [Function: getAverage],
    toString: [Function: toString]
  }
]

[Done] exited with code=0 in 0.054 seconds

4. 객체 지향 프로그래밍

객체들을 정의 , 객체를 활용해서 프로그램을 만드는것을 객체 지향 프로그래밍이라고 함 크게 클래스,프로토타입이라는 두가지 문법으로 객체를 효율적으로 만들 수 있게 함

실제 세계를 모델링하여 소프트웨어를 개발하는 방법

  1. 캡슐화
  • 캡슐화란 관련된 데이터와 알고리즘(코드)이 하나의 묶음으로 정리된 것으로써 개발자가 만들었으며, 관련된 코드와 데이터가 묶여있고 오류가 없어 사용이 편리합니다. 데이터를 감추고 외부 세계와의 상호작용은 메소드를 통하는 방법인데, 라이브러리로 만들어 업그레이드하면 쉽게 바꿀 수 있습니다.
    • 메소드: 메시지에 따라 실행시킬 프로시저로서 객체지향 언어에서 사용되는 것. 객체지향 언어에서는 메시지를 보내 메소드를 수행시킴으로써 통신(communication)을 수행
  1. 추상성
  2. 상속
  • 상속은 이미 작성된 클래스를 이어 받아서 새로운 클래스를 생성하는 기법으로 위에서 말한 기존 코드를 재활용해서 사용하는 것을 의미합니다. 객체지향 방법의 큰 장점중 하나입니다.
  1. 다형성
  • 다형성이란 하나의 이름(방법)으로 많은 상황에 대처하는 기법입니다. 개념적으로 동일한 작업을 하는 함수들에 똑같은 이름을 부여할 수 있으므로 코드가 더 간단해지는 효과가 있습니다.

장점

  • 코드의 재활용성이 높음
  • 코딩이 절차지향보다 간편함
  • 디버깅이 쉬움

단점

  • 처리속도가 절차지향보다 느림
  • 설계에 많은 시간소요가 들어감

5. 클래스

ES6 버전부터 신규로 추가된 객체 설계 문법으로 Prototype이 발전된 형태로 이해하면 됨.

ES5까지의 Javascript는 프로토타입 기반 객체지향 언어에 해당한다.

JSON 형식의 객체와 차이

class나 prototype을 통해 new로 생성된 객체는 구조는 동일하지만 각각 독립적인 값을 갖는다.

클래스의 작성 패턴

  • 변수만 정의
  • 메서드만 정의
  • 변수와 메서드를 함께 정의
  1. 변수만 정의한 클래스
  • 생성자 함수를 정의하고 생성자 함수 안에서 this키워드를 통해 객체 안에 탑제될 변수값들을 생성한다.
  • 생성자 함수는 constructor로 이름이 미리 약속되어져 있다.
  1. 메서드만 정의한 클래스
  • 용도나 목적이 같은 메서드들을 별도의 클래스로 묶어둔다.
  1. 메서드와 멤버변수를 함께 갖는 클래스
  • 멤버변수의 스코프는 클래스 내의 모든 메서드에서 식별 가능하다. 결국 멤버변수는 모든 메서드가 공유하는 전역 변수의 개념이 된다.
  • 같은 클래스에 속한 멤버변수나 함수끼리는 예약어 this를 통해서만 접근 가능하다.

클래스: 객체를 만들 때 수 많은 지원을 하는 대신 많은 제한을 검

[Classes - JavaScriptMDN](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes)

프로토타입: 제한을 많이하지만 지원도 별도로 하지 않음

[프로토타입 기반 프로그래밍 - MDN Web Docs 용어 사전: 웹 용어 정의MDN](https://developer.mozilla.org/ko/docs/Glossary/Prototype-based_programming)

인스턴스: 객체를 만드는 함수

/*  클래스를 선언 후 인스턴스 생성 */
{
    class User { // 클래스 첫글자는 대문자로 지정
        //constructor => 객체를 만들어 주는 생성자
    constructor(name,age){
			/* 속성을 만드는 부분 */
        this.name = name
        this.age = age
	   }
			/* 메서드를 만드는 부분 */
        run(){
            if(this.name=='김다미'){
                return(`${this.name}는 오늘도 달린다`)
            }else{
                return(`${this.name}는 오늘은 쉰다`)
            }
        }
    }
    const profile = new User("김다미",20)


    console.log(profile);

    console.log(profile.run());
}

=> 결과값

[Running] node "/workspaces/codespaces-blank/index.js"
User { name: '김다미', age: 20 }
김다미는 오늘도 달린다

[Done] exited with code=0 in 5.732 seconds

/*  클래스를 선언 후 인스턴스 생성 */
{
    class Students { // 클래스 첫글자는 대문자로 지정
        constructor(이름,국어,영어,수학,과학){
        /* 속성을 만드는 부분 */
            this.이름 = 이름
            this.국어 = 국어
            this.영어 = 영어
            this.수학 = 수학
            this.과학 = 과학
        }
        /* 메서드를 만드는 부분 */
        getSum(){
            return this.국어 + this.영어 + this.수학 + this.과학
        }
        getAverage(){
            return this.getSum()/4
        }
    }
    /* 학생을 선언 */
    const students = [
        new Students('구름',87,98,88,90),   // 인스턴스
        new Students('별이',92,98,96,88),   // 인스턴스
        new Students('겨울',76,96,94,86),   // 인스턴스
        new Students('바다',98,52,98,92)   // 인스턴스
    ]

    /* 이름,총점,평균 구하기 */
    console.log(students)
    let output = '이름\t총점\t평균\n'
    for (const s of students) {
        output += `${s.이름}\t${s.getSum()}점\t${s.getAverage()}점\n`
    }
    console.log(output)
}

=> 결과값

[Done] exited with code=0 in 0.054 seconds

[Running] node "/workspaces/codespaces-blank/index.js"
이름	총점	평균
구름	363	90.75
별이	374	93.5
겨울	352	88
바다	340	85

[Done] exited with code=0 in 0.055 seconds

6. 클래스 고급

  1. 사각형 클래스
/*  사각형 클래스 */
{
    class Rectangle{
        constructor(width,height){
            this.width=width
            this.height=height
        }

        //사각형 둘레 구하는 메소드
        getPerimeter(){
            return 2*(this.width+this.height)
        }
        getArea(){
            return this.width*this.height
        }
    }
    //클래스 사용
    const square = new Rectangle(10,20) // 사각형 (가로 10cm , 세로 20cm)
    console.log(`정사각형 둘레: ${square.getPerimeter()}cm`)
    console.log(`정사각형 넓이: ${square.getArea()}cm`)
}

=> 결과값

[Running] node "/workspaces/codespaces-blank/index.js"
정사각형 둘레: 60cm
정사각형 넓이: 200cm

[Done] exited with code=0 in 0.059 seconds
  1. 정사각형 클래스 (private 속성)

private 속성 : 클래스를 더 안전하게 사용하기 위함

/*  정사각형 클래스 */
{
class Square{
        #length // private 속성
        static #counter =0 //만들어진 Square 객체의 개수를 알고 싶을 때
        static get counter(){
            return Square.#counter
        }

        constructor(length){
           this.length=length
           Square.#counter +=1
        }
        static perimeterOf(length){
            return length *4
        }
        static areaOf(length){
            return length * length
        }
        get length(){return this.#length}
        get Perimeter(){return 4 * this.#length}
        get Area(){return this.#length * this.#length}

        set length(length){
            if(length <=0){
                throw '길이는 0보다 커야함'
            }
            this.#length =length
        }
    }
    //클래스 사용
    const squareA = new Square(10)
    const squareB = new Square(20)
    const squareC = new Square(30)
    console.log(`지금까지 생성된 Square 인스턴스는 ${Square.counter}개입니다.`)

    //static 메소드 사용
    console.log(`한 변의 길이가 20인 정사각형의 둘레는 ${Square.perimeterOf(20)}입니다`)
    console.log(`한 변의 길이가 30인 정사각형의 둘레는 ${Square.areaOf(30)}입니다`)
}

=>결과값

[Running] node "/workspaces/codespaces-blank/index.js"
정사각형 둘레: 40cm
정사각형 넓이: 100cm

[Done] exited with code=0 in 0.053 seconds
  1. 정사각형 클래스 응용 (static 속성)
[static - JavaScriptMDN](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes/static)

static 속성 : 클래스의 정적 메서드를 정의

class 클래스 이름 {
   static 속성 = 값
   static 메소드 (){}
}
/*  정사각형 클래스 */
{
		class Square{
        #length // private 속성
        static #counter =0 //만들어진 Square 객체의 개수를 알고 싶을 때
        static get counter(){
            return Square.#counter
        }

        constructor(length){
           this.length=length
           Square.#counter +=1
        }
        static perimeterOf(length){
            return length *4
        }
        static areaOf(length){
            return length * length
        }
        get length(){return this.#length}
        get Perimeter(){return 4 * this.#length}
        get Area(){return this.#length * this.#length}

        set length(length){
            if(length <=0){
                throw '길이는 0보다 커야함'
            }
            this.#length =length
        }
    }
    //클래스 사용
    const squareA = new Square(10)
    const squareB = new Square(20)
    const squareC = new Square(30)
    console.log(`지금까지 생성된 Square 인스턴스는 ${Square.counter}개입니다.`)

    //static 메소드 사용
    console.log(`한 변의 길이가 20인 정사각형의 둘레는 ${Square.perimeterOf(20)}입니다`)
    console.log(`한 변의 길이가 30인 정사각형의 둘레는 ${Square.areaOf(30)}입니다`)
}

=>결과값

[Running] node "/workspaces/codespaces-blank/index.js"
지금까지 생성된 Square 인스턴스는 3개입니다.
 변의 길이가 20 정사각형의 둘레는 80입니다
 변의 길이가 30 정사각형의 둘레는 900입니다

[Done] exited with code=0 in 0.057 seconds

7. 상속 및 오버라이드

  1. 상속: 어떤 클래스의 기능을 다른 클래스에 상속시킨 후 추가적인 기능을 명시하여 원래의 기능을 확장하는 방법.
  • 기능의 확장으로서의 상속
  • 여러 클래스간의 공통 기능을 모아 놓는 의미로서의 상속
extends는 클래스를 상속받을수있음

 /*
   ...생략
   constructor(...args){
       super(...args)
       부모
   }
 */
  1. extends를 이용하여 클래스 상속하기
/* 부모에 있던 내용 가져오기 */
{
  class LifeStyle {
    call() {
      this.a();
      this.b();
      this.c();
    }
    a() {
      console.log("a() 메소드를 호출");
    }
    b() {
      console.log("b() 메소드를 호출");
    }
    c() {
      console.log("c() 메소드를 호출");
    }
  }
  class Child extends LifeStyle {
    a() {
      super.a();
      console.log("자식의 a()메소드");
    }
  }
  new Child().call();
}
  1. 메서드 오버라이드(Override)

클래스 간에 부모-자식 관계가 형성되었을 때 자식 클래스에서 부모 클래스가 갖는 메서드와 동일한 이름의 메서드를 정의하는 기법.

super 키워드

Override 이전의 원본 기능 호출하기

  • this 키워드가 현재 클래스나 부모로부터 상속 받은 자원을 가리키는 예약어인 반면, super 키워드는 부모의 메서드를 Override 하고 있는 자식 클래스 안에서 부모의 원래 기능을 호출하고자 하는 경우에 사용한다.

부모 클래스의 생성자

  • super 키워드를 메서드처럼 사용할 경우 부모 클래스의 생성자를 의미한다.
  • 자신의 생성자를 통해 전달받은 파라미터와 추가적으로 가공된 파라미터를 부모의 생성자로 전달하여 객체를 생성하는 방법에 변화를 주고자 할 경우 사용한다.
/* 부모 클래스 ,슈퍼 클래스 , 자식클래스 ,서브 클래스 */

{
    // 부모 클래스 ,슈퍼 클래스
    class Rectangle{
        constructor(width,height){
            this.width=width
            this.height=height
        }

        //사각형 둘레 구하는 메소드
        getPerimeter(){
            return 2*(this.width+this.height)
        }
        getArea(){
            return this.width*this.height
        }
    }
    //자식클래스 ,서브 클래스
    //** 상속 기본문법 **
    class Square extends Rectangle {
        constructor (width){ // 속성 변경하는 법
            super(width,width)
            this.width = width
            this.height = width
            }
            // super로 생성자 정의를 하면 아래 코드는 안써도 됌
            /*
            }
            constructor(width){
                this.width=width
            }
            getPerimeter(){
                return 4*this.width
            }
            getArea(){
                return this.width*this.width
            }
        */
        }
        //클래스 사용
        const rect = new Rectangle(20,10)
        console.log(`사각형 둘레: ${rect.getPerimeter()}`)
        console.log(`사각형 넓이: ${rect.getArea()}`)
        const square = new Square(10,10)
        console.log(`사각형 둘레: ${square.getPerimeter()}`)
        console.log(`사각형 넓이: ${square.getArea()}`)

}

=>결과값

[Running] node "/workspaces/codespaces-blank/index.js"
사각형 둘레: 60
사각형 넓이: 200
사각형 둘레: 40
사각형 넓이: 100

[Done] exited with code=0 in 0.055 seconds