From 8111b5e00b0c15b1ae767d895e1ee43d1cad4996 Mon Sep 17 00:00:00 2001 From: zoeyourlife <201814112@office.skhu.ac.kr> Date: Wed, 6 Sep 2023 10:19:31 +0900 Subject: [PATCH] =?UTF-8?q?=EC=B5=9C=EC=9E=AC=ED=9B=88=207=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 클래스 정리 --- .../\354\265\234\354\236\254\355\233\210.md" | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 "7_\355\201\264\353\236\230\354\212\244/\354\265\234\354\236\254\355\233\210.md" diff --git "a/7_\355\201\264\353\236\230\354\212\244/\354\265\234\354\236\254\355\233\210.md" "b/7_\355\201\264\353\236\230\354\212\244/\354\265\234\354\236\254\355\233\210.md" new file mode 100644 index 0000000..1ecef6f --- /dev/null +++ "b/7_\355\201\264\353\236\230\354\212\244/\354\265\234\354\236\254\355\233\210.md" @@ -0,0 +1,158 @@ +# 코어 자바스크립트 Note + +## 07. 클래스 + +자바스크립트는 프로토타입 기반 언어이기에 '상속'이라는 개념이 존재하지 않는다. + +클래스 기반의 다른 언어에 익숙한 개발자들에겐 혼란, + +그래서, 클래스와 비슷하게 동작하게끔 흉내 내는 여러 기법들이 탄생했다. + +ES6에는 클래스 문법이 추가되었지만 일정 부분은 프로토타입을 활용 + +즉, ES5 체제 하에서 클래스를 흉내내기 위한 구현 방식을 학습. + +### 01. 클래스와 인스턴스의 개념 이해 + +- 어떤 클래스의 속성을 지니는, 실존하는 개체를 일컬어 인스턴스(instance)라고 한다. + + - 어떤 조건에 부합하는 구체적인 예시, 조건은 곧 클래스를 의미, 어떤 클래스에 속한 개체는 그 클래스의 조건을 모두 만족하므로 그 클래스의 구체적인 예시, 즉 인스턴스가 될 것이다. + +- 현실세계에서는 개체들이 이미 존재하는 상태에서 이들을 구분짓기 위해 클래스를 도입한다. + + - 이 때문에 하나의 개체가 같은 레벨에 있는 서로 다른 여러 클래스의 인스턴스일 수 있다. + - 예를 들어, 필자는 남성이면서 회사원이고 한국인이라는 여러 분류에 속하고 + - 남성, 회사원, 한국인의 각 분류는 서로 밀접한 관련이 없는 별개의 분류체제 + +- 반면 프로그래밍 언어상에서는 접근 방식이 정반대임! + - 컴퓨터는 위와 같은 구분법을 알지 못하므로, 사용자가 직접 여러 가지 클래스를 정의해야 하고, 클래스를 바탕으로 인스턴스를 만들 때 비로서 어떤 개체가 클래스의 속성을 지니게 된다. + - 또한 한 인스턴스 하나의 클래스만을 바탕으로 만들어진다 + - 어떤 인스턴스가 다양한 클래스에 속할 수는 있지만 이 클래스들은 모두 인스턴스 입장에서는 '직계존속'이다. + - 다중상속을 지원하는 언어든 그렇지 않은 언어든 결국 인스턴스를 생성할 때 호출할 수 있는 클래스는 오직 하나뿐일 수밖에 없기 때문이다. +- 클래스는 '공통 요소를 지니는 집단을 분류하기 위한 개념'이라는 측면에서는 일치하지만 인스턴스들로부터 공통점을 발견해서 클래스를 정의하는 현실과 달리, 클래스가 먼저 정의돼야만 그로부터 공통적인 요소를 지니는 개체들을 생성할 수 있다. + - 현실세계에서의 클래스는 추상적인 개념이지만, 프로그래밍 언어에서의 클래스는 사용하기에 따라 추상적일 수도 있고 구체적인 개체가 될 수도 있다. + +### 02. 자바스크립트의 클래스 + +- 생성자 함수 Array를 new 연산자와 함께 호출하면 인스턴스가 생성된다. + + - Array를 일종의 class라고 하면, Array의 prototype 객체 내부 요소들이 인스턴스에 '상속'된다. + - 엄밀히는 상속이 아닌 프로토타입 체이닝에 의한 '참조'지만, 결과적으론 동일하게 동작. + - Array 내부 프로퍼티들 중 prototype 프로퍼티를 제외한 나머지는 인스턴스에 상속되지 않음. + +- 인스턴스에 상속되는지 여부에 따라 스태틱 멤버와 인스턴스 멤버로 나뉨. + - '인스턴스 메서드'라는 명칭은 프로토타입에 정의한 메서드를 지칭하는 것인지 인스턴스에 정의한 메서드를 지칭하는 것인지 혼란. + - 즉, 프로토타입 메서드라고 부르자! + +```js +// 생성자 +var Rectangle = function (width, height) { + this.width = width; + this.height = height; +}; +// (프로토타입) 메서드 +Rectangle.prototype.getArea = function () { + return this.width + this.height; +}; +// 스태틱 메서드 +Rectangle.isRectangle = function (instance) { + return ( + instance instanceof Rectange && instance.width > 0 && instance.height > 0 + ); +}; + +var rect1 = new Rectangle(3, 4); +console.log(rect1.getArea()); // 12 (0) +console.log(rect1.isRectangle(rect1)); // Error(X) +console.log(Rectangle.isRectangle(rect1)); // true +``` + +- rect1 인스턴스에서 isRectangle이라는 메서드에 접근해보자. + - rect1에 해당 메서드가 있는지 검색했는데 없고, rect1.**proto**에도 없고, 그 뒤에도 없다. + - 결국, undefined를 실행하라는 명령이므로 typeError를 띄운다. + - 이렇게 인스턴스에서 직접 접근할 수 없는 메서드를 '스태틱 메서드'라고 한다. + - 이것은 생성자 함수를 this로 해야만 호출할 수 있다. 아래의 Rectangle.isRectangle(rect1)처럼. + +### 03. 클래스 상속 + +자바스크립트에서 클래스 상속을 구현했다는 것은 결국 프로토타입 체이닝을 잘 연결한 것. + +#### 7-3-1. 기본 구현 + +- 프로토타입 체인을 활용해 클래스 상속을 구현하고 최대한 전통적인 객체지향 언어에서의 클래스와 비슷한 형태로까지 발전 +- ES5까지의 자바스크립트엣는 클래스가 없다. ES6에서 클래스가 도입됐지만 역시나 prototype을 기반으로 한 것으로 기본적으로는 결국 프로토타입 체이닝을 잘 연결한 것으로 이해한다. + + - 다만 '기본적으로' 그렇다는 것이고, 세부적으로 완벽하게 superclass와 subclass의 구현이 이루어진 것은 아니다. + - Grade 예제에서 length 프로퍼티가 configurable(삭제 가능)하다는 점과, Grade.protoype에 빈 배열을 참조시켰다는 점이 그렇다. + + ```js + g.push(90); + console.log(g): // Grade {0: 100, 1: 80, 2: 90, legnth : 3} + + delete g.length; + g.push(70); + console.log(g); // Grade { 0: 70, 1:80, 2:90, length:1} + ``` + +- legnth 프로퍼티를 삭제하고 다시 push를 했떠니, push한 값이 0번쨰 인덱스에 들어갔고, legnth가 1이 됐다. + + - 내장객체인 배열 인스턴스의 length 프로퍼티는 configurable 속성이 false라서 삭제가 불가능하지만, Grade 클래스의 인스턴스는 배열 메서드를 상속하지만 기본적으로는 일반 객체의 성지를 그대로 지니므로 삭제가 가능해서 문제가 된다. + - 저렇게 된 이유는? + - 바로 g.**proto **, 즉 Grade.prototype이 빈 배열을 가리키고 있기 떄문이다. + - push 명령에 의해 엔진이 g.legnth를 읽고자 하는데 g.length가 없으므로 프로토타입 체이닝을 타고 g.**proto **.length를 읽어온 것 + - 빈 배열의 legnth가 0이므로 여기에 값을 할당하고 legnth는 1만큼 증가시키라는 명령이 문제 없이 동작할 수 있었던 이유! + - 그럼 만약 Grade.prototype에 요소를 포함하는 배열을 매칭시켰다면? + + ```js + Grade.prototype = ['a', 'b', 'c', 'd']; + var g= new Grade(100, 80); + + g.push(90); + conols.log(g); / Grade {0: 100, 1: 80, 2:90, legnth:3} + + delete g.length; + g.push(70); + console.log(g); // Grade {0:100, 1: 80, 2: 90, __ 4:70, legnth:5} + ``` + + - g.length가 없으니 g.**proto **.legnth를 찾고, 값이 4이므로 인덱스 4에 70을 넣고, 다시 g.length에 5를 부여하는 순서로 동작한 것 + - 이처럼 클래스에 있는 값이 인스턴스의 동작에 영향을 주면 안된다! + - 이런 영향을 줄 수 있다는 것 자체가 이미 클래스의 추상성을 해치는 것이다. + +#### 7-3-2. 구체적인 데이터를 지니지 않게 하는 방법 + +다양한 방식이 존재하지만 + +1. 인스턴스 생성 후 프로퍼티 제거하는 방법 + +2. 빈 함수를 이용하는 방법 + +3. Object.create를 활용하는 방법 + +같은 접근 방식이 있다. + +결국, SubClass.prototype의 **proto**가 SuperClass.prototype를 참조하고 +SubClass.prototype에는 불필요한 인스턴스 프로퍼티가 남아있지 않게 된다. + +#### 7-3-3. consturctor 복구하기 + +프로토타입 체인상에 가장 먼저 등장하는 SuperClass.prototype의 constructor에서 가리키는 대상, 즉 SuperClass. + +### 07-5. 정리 + +- 자바스크립트는 프로토타입 기반 언어라서 클래스 및 상속 개념은 존재하지 않지만 프로토타입을 기반으로 클래스와 비슷하게 동작하게끔 하는 다양한 기법들이 도입됨! +- 클래스는 어떤 사물의 공통 속성을 모아 정의한 추상적인 개념이고, 인스턴스는 클래스의 속성을 지니는 구체적인 사례! +- 상위 클래스의 조건을 충족하면서 더욱 구체적인 조건이 추가된 것을 하위 클래스라고 한다. + +- 클래스의 prototype 내부에 정의된 메서드를 프로토타입 메서드라고 하며, + + - 이들은 인스턴스가 마치 자신의 것처럼 호출할 수 있다. + +- 한편 클래스(생성자 함수)에 직접 정의한 메서드를 스태틱 메서드라고 하며, 이들은 인스터스가 직접 호출할 수 없고 클래스(생성자 함수)에 의해서만 호출할 수 있다. + +- 클래스 상속을 흉내내기 위한 3가지 방법 + + - SubClass.prototype에 SuperClass의 인스턴스를 할당한 다음 프로퍼티를 모두 삭제하는 방법, 빈 함수(Bridege)를 활용하는 방법, Object.create를 이용하는 방법. + - 세 방법 모두 constructor 프로퍼티가 원래의 생성자 함수를 바라보도록 조정해야 한다. + +- 상위 클래스에 접근할 수 있는 수단인 super를 구현함