클래스
#
ES6 클래스- 생성자 함수를 더 깔끔한 문법으로 정의 가능
- Syntatic Sugar prototype 기반 상속을 보다 명료하게 사용할 수 있는 문법을 제공
- 다른언어의 Class 문법과 생김새는 비슷함
- BUT 내부 동작은 다름 : prototype 기반으로 상속을 흉내냄
- 새로운 블록 스코프를 형성
Syntatic Sugar: 읽고 표현하는 것을 더 쉽게 하기 위해서 고안된 프로그래밍 언어 문법
#
Class Syntax예시
사용할 수 없는 문법
- 클래스 선언은 호이스팅됨. 그러나 선언전에 참조: reference error
#
Class 정의JS 의 Class 는 함수. 따라서, class 정의 문법
Class 선언식
Class 표현식
class
키워드- 클래스를 선언.
- JS 엔진이 class 키워드를 만나면 Class Object 를 생성.
Class Object
- JS 엔진이 class 키워드로 생성한 객체.
#
Class 선언함수 선언과 달리 클래스 선언은 uninitialized 로 초기화.
- 따라서 클래스 사용전에 미리 선언을 해야 한다.
왜 그런 차이가 발생하게 되는 것일까요? TODO
#
Class 표현식#
명명된 클래스 표현식#
익명 클래스 표현식#
일급 객체 Class함수처럼 다른 표현식 내부에서 전달, 반환, 할당 가능
조건에 따라 다른 클래스를 상속받고 싶을 때,
#
클래스 인스턴스new 연산자와 함께 생성자(constructor) 호출함.
constructor 은 new 연산자 없이 호출할 수 없다.
#
constructor- 클래스의 인스턴스 생성 & 인스턴스 프로퍼티 초기화
- 인스턴스 프로퍼티의 동적 할당 및 초기화
class User 선언 결과
#
클래스 프로퍼티클래스 body 에는 메서드
만 선언 가능.
이 문법은 현재 클래스 필드 로 바벨없이 대부분의 브라우저에서 사용가능하다.
클래스 프로퍼티의 선언과 초기화는 constructor 내부에서 해야 한다.
this
- 클래스 인스턴스를 가리킨다.
#
클래스 메서드객체 리터럴에서 사용하던 문법과 유사하다.
#
Getter, Setter 정의computed property
#
클래스 Generator 메서드#
클래스 static 메서드객체가 아닌 클래스 함수에 속한 메서드.
- 일반 메서드는 프로토타입 객체의 메서드이다.
- static method 는 생성자 함수의 메서드 이다.
개별 인스턴스에 묶이지 않는다.
클래스의 static 인스턴스에만 접근할 수 있다.
Math 객체의 메소드처럼, 애플리케이션 전역에서 사용할 유틸리티(utility) 함수를 생성할 때 주로 사용한다.
정적 메서드 내에서의 this
예시1) 인스턴스 끼리의 연산
예시2) 인스턴스 끼리 비교
예시 3) ‘팩토리’ 메서드를 구현한 코드입니다. 다양한 방법을 사용해 조건에 맞는 article 인스턴스를 만들어야 한다고 가정해 봅시다.
- 매개변수(title, date 등)를 이용해 관련 정보가 담긴 article 생성
- 오늘 날짜를 기반으로 비어있는 article 생성
- 기타 등등
- 생성자 방법 & 클래스에 정적 메서드를 만들어 구현
#
클래스 필드클래스 내부의 캡슐화된 변수
- 데이터 멤버, 멤버 변수
- 인스턴스의 (프로퍼티 & 정적 프로퍼티)가 될 수 있다.
- 자바스크립트의 생성자 함수에서 this 에 추가한 프로퍼티를 클래스 기반 객체지향 언어에서는 클래스 필드라고 부른다.
클래스 블록 안에서 할당연산자를 이용해 인스턴스 속성을 지정할 수 있는 문법
#
클래스 내의 this인스턴스 객체를 가리킨다.
#
화살표 함수를 통해 메서드 정의#
일반 클래스 메서드prototype 속성에 저장
#
클래스 필드(화살표함수)인스턴스 객체에 저장
- 화살표 함수의 this 는 항상 인스턴스 객체를 가리킴.
- 인스턴스를 생성할 때마다 새로 생성되기 때문에 메모리를 더 차지하게 된다.
- 메서드를 값으로 다루어야 할 경우 (TODO)
- 메서드를 다른 함수로 넘겨 줘야 되는 경우 (TODO)
- 브라우저 환경에서 메서드를 이벤트 리스너로 설정해야 할 때.
객체 메서드를 전달해 전혀다른 컨텍스트에서 호출
하게 되면this 는 원래 객체를 참조하지 않습니다.
이때 click 을 화살표 함수로 만들면 Button 객체마다 독립적인 함수를 만들고 함수의 this 를 해당 객체에 바인딩 해준다.
#
private, static, public 필드#
클래스 상속단일 상속
#
재사용클래스의 기능을 다른 클래스에서 재사용
Student 클래스
는 Person 클래스 의static 메서드, 필드
을 사용할 수 있다.Student 클래스 인스턴스
는 Person 클래스의메서드와, 필드
을 사용할 수 있다.
#
super서브 클래스에서 수퍼 클래스와 같은 이름의 속성을 정의하면 수퍼 클래스의 속성이 가려진다.
이 때, 수퍼 클래스의 속성에 접근하고 싶을 때, super 키워드를 사용하면 된다.
#
super 키워드 동작방식- 서브 클래스
생성자
에서super()
- 수퍼 클래스의 생성자 호출
- 서브 클래스의 생성자에서 super 를 호출하지 않으면 this 에 대한 참조에러가 발생함.
- 서브 클래스
static 메서드
에서super.속성명
- 수퍼 클래스의 static 속성 접근
- 서브 클래스
인스턴스 메서드
에서this.속성명
- 수퍼 클래스의 인스턴스 속성에 접근
#
화살표 함수 super화살표 함수는 super 을 쓸 수 없다.
화살표 함수를 써야하는 '브라우저 환경에서 메서드를 이벤트 리스너로 설정해야 할 때' 는 아래와 같이 해준다.
#
생성자 오버라이딩자체 생성자가 없는 클래스를 상속받으면 자동으로 만들어짐
상속 클래스의 생성자에서
- super 을 호출하지 않으면 에러가 발생한다
- super 를 this 를 사용하기 전에 호출하여야 한다.
상속 클래스의 생성자에서 super 를 호출하지 않으면 에러가 발생하는 이유
- 다른점 : 상속 클래스의 생성자 함수의 내부 프로퍼티
[[ConstructorKind]]:"derived"
- 일반 클래스가
new
와 함께 실행 -> 빈 객체가 만들어지고 &this
에 이 객체를 할당함 - 상속 클래스의 생성자 함수가 실행 -> 빈 객체를 만들고 &
this
에 객체를 할당하는 일은 수퍼클래스의 생성자가 처리해 줘야한다.- 상속 클래스의 생성자에서 super(...) 수퍼클래스의 생성자를 실행해 줘야 this 객체가 만들어진다.
#
extends 키워드클래스의 두 개의 프로토타입을 설정한다.
일반 메서드용
생성자함수의 'prototype' 사이정적 메서드용
생성자함수 자체 사이
#
super 의 내부 동작#
1. super 를 구현하려는 시도this.__proto__.eat.call(this);
을 주목해서 보자
체인에 객체를 하나더 추가했을 때 무한루프가 발생한다.
그 이유는 (*)
, (**)
를 보자
longEar.eat();
를 호출했을때,
this.__proto__.eat.call(this); // (**)
에서 this.__proto__
는 Rabbit 이다.
this.__proto__.eat.call(this); // (*)
에서의 맨 앞의 this 는 (**)
에 의해서 longEar 로 바인딩 되었기 때문에
역시 this.__proto__
는 Rabbit 이다.
super
는 [[HomeObject]]
를 통해 수퍼 프로토타입과 메서드를 찾는다.#
2. [[HomeObject]]
: 함수 특수 프로퍼티
- (클래스 || 객체) 메서드 함수의
[[HomeObject]]
에 해당 객체가 저장된다.
따라서 [[HomeObject]]
를 알고 있기 때문에 this
없이도 프로토타입으로부터 부모 메서드를 가져올 수 있다.
객체 메서드에서도 super 를 쓸수 있구나.
#
3. [[HomeObject]] 는 변경될 수 없다.[[HomeObject]]
는 super
내부에서만 유효하다.
(*)
:tree.sayHi
- 중복 코드를 방지하기 위해rabbit
의 메서드를 복사- 복사한 메서드의
[[HomeObject]]
는 여전히rabbit
이기 때문에animal
의sayHi
를 찾는다.
- super 가 없는 메서드는 객체간 복사가 잘 될 수 있다.
#
4. [[HomeObject]] 메서드로 정의해야 가질 수 있다.method()
Omethod: function()
X
#
정적 프로퍼티, 메서드의 상속정적 프로퍼티와 메서드는 프로토타입 체인에 의해 상속 된다.
정적 메서드 상속을 사용한 예
extends Object가 없을 때
Function.prototype
call
,bind
등의 일반함수 메서드를 가진다.- 모든 함수의 기본 프로토타입
class Rabbit | class Rabbit extends Object |
---|---|
- | 생성자에서 super() 를 만드시 호출해야함 |
Rabbit.__proto__ === Function.prototype | Rabbit.__proto__ === Object |
#
private, protected 프로퍼티와 메서드#
객체지향 프로그래밍 내부 & 외부 인터페이스복잡한 애플리케이션을 구현하려면, 내부 인터페이스와 외부 인터페이스를 구분하는 방법을 ‘반드시’ 알고 있어야 한다.
내부 인터페이스
- 동일한 클래스 내의 다른 메서드에서 접근 가능.
- 클래스 밖에서 접근할 수 없는 프로퍼티와 메서드.
외부 인터페이스
- 클래스 밖에서도 접근 가능한 프로퍼티와 메서드
#
자바스크립트의 타입public
- 외부 인터페이스 구성
private
- 내부 인터페이스 구성
- 클래스 내부에서만 접근가능
자바스크립트는 protected
를 지원하지 않지만 모방해서 만들 수 있다.
- private 과 비슷하지만 서브 클래스에서 접근 가능하다.
- 내부 인터페이스 구성
#
프로퍼티 보호하기예시) 커피 머신 클래스
public
waterAmount, power
public
waterAmount 의 값을 제한하기
#
읽기 전용 프로퍼티setter 는 만들지 않고 getter 만 만들어야 한다.
#
private 프로퍼티- 클래스 외부나 서브 클래스에서 접근할 수 없다.
this[name]
필드 보안강화를 위해 이 문법은 쓸 수 없다.
한 클래스 내에서 public 프로퍼티와 동일한 이름의 private 프로퍼티를 가질 수 있다. private 프로퍼티를 이용하려면 getter 와 setter 를 사용하는 방법이 있다.
#
private 필드와 메서드의 상속private 필드와 메서드는 상속되지 않는다.
하위 클래스에서 상위 클래스의 필드와 메소드에 접근하기 위해선
protected 라는 접근제한자를 사용합니다.
그런데 JS에는 private만 있고 protected가 없기 때문에
private으로 선언된 것은 아예 상속되지 않습니다.
#
클래스 상속과 프로토타입 상속클래스 상속은 내부적으로 프로토타입 상속을 활용한다.
클래스 상속에 대한 프로토 타입 체인이다.
- Animal 클래스 생성
- Animal Class 를 확장한 Rabbit Class 생성
run 을 찾을 때 프로토타입 체인을 따라서 Animal 에서 run 을 찾는다고 기술되어 있는데, 아래 ES5 와 ES6 를 비교하는 내용에서는
#
ES5로 Class를 구현- A: 🔗
#
ES6 Class 와 ES5 prototype 상속 의 차이#
new.target 중심으로 개편된 es6 객체 생성 시스템#
constructornew
키워드#
class 의 constructor 는 new 명령어 없이 호출할 수 없다.
class 로 만든 함수엔 특수 내부 프로퍼티 [[FunctionKind]]:"classConstructor
가 붙는다.
JS 엔진은 함수에 [[FunctionKind]]:"classConstructor
가 있을 때 new
와 함께 호출하지 않으면 에러가 발생한다.
super
& extends
키워드#
서브 클래스에서 수퍼 클래스의 생성자를 호출할 수 없다.
프로토타입 체이닝을 통한 수퍼 클래스 생성자 프로퍼티의 전달
이 되었기 때문에
hasOwnProperty('a') 의 결과는 false 이다.
만약 수퍼클래스의 프로퍼티를 전달하는 것이 아닌, 서브 클래스의 프로퍼티로 만들기 위해서는 아래와 같은 복잡한 방법을 사용해야 한다.
하지만 이 방법 또한 SubClass 에서 SuperClass 의 속성을 가지기 위해서
SuperClass 의 생성자를 호출하였기 때문에 SubClass.prototype = new SuperClass();
메모리 낭비가 있을 수 있다.
ES6 Class
서브클래스
- 수퍼클래스의 인스턴스를 상속받지 않는다.
- cf. 수퍼 클래스의 인스턴스를 상속받는 예)
SubClass.prototype = new SuperClass();
- cf. 수퍼 클래스의 인스턴스를 상속받는 예)
- 수퍼클래스의 메서드를 상속 받는다
서브 클래스의 인스턴스의 프로토타입 체인상에서도 수퍼 클래스의 constructor 의 실행결과는 존재하지 않는다.
ES5 에서 위와같은 기능을 구현하기 위해서는 프록시를 활용해야 한다.
내가 이해한 바로는 Proxy 의 prototype 속성에 임시로 SuperClass 의 인스턴스를 생성하여 할당하고. SuperClass 의 실제 프로토타입 메서드 만을 SubClass 에게 상속해 주는 역할이 아닐까 싶다.
#
Methods#
static method & method 의 상속ES5
ES6 Class
method 의 출력 결과는 서브 클래스 , 수퍼클래스 모두 같다.
프로토타입 체인에 의해 결과는 모두 같다.
그러나 static method 의 경우는 다르다.
인스턴스에서 static 메서드를 호출할 수 없는 것은 당연하다.
static 은 인스턴스의 메서드가 아니라 생성자의 메서드 이기 때문이다.
ES5, static method 는 수퍼 클래스에서만 호출이 가능하다.
그 이유는 생성자는 프로토타입 체인으로 연결되어 있지 않았고, static 메서드는 생성자의 메서드 이기 때문이라고 생각한다.
ES6, static method 는 수퍼 클래스와 서브클래스 모두에서 호출 가능하다.
그렇다면 ES5 에서 ES6 와 같은 결과를 얻기 위해서는 다음과 같이 method 들을 모두 복사해 주면 된다.
Sub['super_' + static] = Super[static];
은 서브클래스의 중복된 메서드명을 피하기 위해 접두사를 붙여 주었다.
#
생성자 함수ES5
- static method, Method 는 함수이기 때문에 생성자 함수로 사용할 수 있다.
ES6 Class
- static method, Method 는 생성자 함수로 사용될 수 없다
- ES6 static method
- arguments, caller 값이 노출되지 않는다.
- name 이 자동으로 지정된다.
- prototype 이 없다.
- ES6 의 shorthand method
- function 에서 많은 기능이 제한되어 오직 method 로서만 사용할 수 있는 특수 함수.
#
superClass 메서드 차용ES5
'super sub sub' 의 결과가 나온 이유
인스턴스에서 method를 호출하면 proto에 위치한 메소드를 마치 인스턴스 자신의 것처럼 사용하기 때문에, 위 메소드에는 최초 실행시 this에는 ‘obj’가 할당되었다가, 재귀적으로 SubClass.prototype가 할당되었다가, 다시 SuperClass.prototype이 할당되기 때문에, 본래 의도한 ‘super sub’라는 결과 대신 ‘ sub’가 한 번 더 출력되고 말았습니다.
이해가 잘 안된다.
단계를 쪼개어서 디버그를 돌려보았다.
문제의 코드이다.
const callSuper = Object.getPrototypeOf(this).method();
코드 실행순서를 보면
this.method
(this: SubClass, SubClass.prototype.method) 을 먼저 호출- this 가
Super
클래스인SubClass.prototype.method
메서드가 다시 호출
const df = 1;
코드를 통해서 재 호출 된 것임을 영상을 통해 확인할 수 있다.
this.method
(this: SuperClass, SuperClass.prototype.method)를 성공적으로 마친후에const result = super sub;
가 된 것을 확인할 수 있었다.return 된 result 는 문맥(this)이 SuperClass 에서 SubClass 으로 전환되면서
const callSuper = 'super sub';
부터 다시 실행 되었다.
~~
처음 예상했을 때는 SuperClass.method
를 바로 호출할 거라고 생각했었다.
이런 코드의 흐름을 갖게된 원인이 무엇일까?
getPrototypeOf
this
에 있는걸까?
this 가 getPrototypeOf 에게 wrapper 되기 전에 실행이 된걸까? 비동기적인 문제의 영향도 있는걸까?
이런식의 콜백이 발생했다는 것은 알게 되었는데 왜 이런식의 콜백을 발생시키는 코드는 어떻게 생겼는지 알수가 없다.
자바스크립트의 이런 엉뚱한 측면은 흥미롭다.
this 를 사용할 경우 ES6 의 클래스에서도 똑같이 확인된다.
ES6 의 super 키워드는 this 활용시의 문제점을 피해갈 수 있다.
super 키워드는 상위 클래스만을 가리키므로 재귀적으로 여러번 호출될 염려가 없다.
#
enumerable 열거형클래스 메서드는 열거할 수 없다. enumerable: false
for..in
으로 순회할 때, 메서드는 순회 대상에서 제외하고 멤버 변수만 순회할 수 있다.
#
hoisting#
ReferenceErrorES5
ES6 : Uncaught ReferenceError
#
Block ScopeES5 : 엄격모드에서만 block scope 영향을 받는다.
ES6 : 항상 block scope 에 종속된다.
#
엄격모드클래스는 항상 엄격 모드로 실행 된다.
#
타입 확인#
instanceof 로 클래스 확인하기- 객체가 특정 클래스에 속하는지 확인 상속 관계 확인
obj instanceof Class
: true- obj 가 Class 에 속할 때
- Class 를 상속받는 클래스에 속할 때
new Class() instanceof Class
#
프로토타입 체인과 instanceof보통, 프로토타입 체인을 거슬러 올라가며 인스턴스 여부나 상속 여부를 확인한다.
#
instanceof 알고리즘Symbol.hasInstance
구현여부 확인#
1. 클래스에 정적메서드 obj instanceof Class
문이 실행될 때, Class[Symbol.hasInstance](obj)
가 호출된다.
- 호출 결과는 boolean 이다.
- 직접 확인 로직을 설정할 수 있다.
- 대부분의 클래스엔 구현되어 있지 않다.
canEat 프로퍼티가 있으면 animal 이라고 판단할 수 있도록 instanceOf 의 로직을 직접 설정합니다.
#
2. Class.prototype 이 obj 프로토타입 체인 상의 프로토토타입 중 하나와 일치하는지 확인- true : 이 중 하나라도 true
- false: 그렇지 않고 체인의 끝에 도달
🔗#
objA.isPrototypeOf(objB)- objA가 objB의 프로토타입 체인 상 어딘가에 있으면 true 를 반환해주는 메서드
- instanceof 연산자와 다른점
- "object instanceof AFunction"
- object 의 프로토타입 체인을 AFunction 자체가 아니라 AFunction.prototype 에 대해 확인 한다.
- Class 생성자를 제외하고 포함 여부를 검사 한다는 것이다. (?)
- "object instanceof AFunction"
문제에서 a.proto == B.prototype 이므로, instanceof 는 true 를 반환.
#
Object.prototype.toString타입 확인을 위한 Object.prototype.toString
일반 객체를 문자열로 변환했을 때 [object Object]
가 출력되는 이유
- toString 의 구현방식 때문
- typeof, instanceof 의 대안을 만들 수 있다.
- 숫자형 – [object Number]
- 불린형 – [object Boolean]
- null – [object Null]
- undefined – [object Undefined]
- 배열 – [object Array]
- 그외 – 커스터마이징 가능
#
Symbol.toStringTag- 특수 객체 프로퍼티
toString
커스터마이징
특정 호스트 환경의 객체와 클래스에 구현된 toStringTag
- | 동작 대상 | 반환값 |
---|---|---|
typeof | 원시형 | 문자열 |
{}.toString | 원시형, 내장 객체, Symbol.toStringTag 가 있는 객체 | 문자열 |
instanceof | 객체, 계층 구조를 가진 클래스를 다룰 때, 클래스의 상속 여부를 확인 | true/false |
#
믹스인다른 클래스를 상속받을 필요 없이, 이들 클래스에 구현되어있는 메서드를 담고 있는 클래스.
자바스크립트는 다중 상속을 지원하지 않지만 믹스인을 사용하면 메서드를 복사해 프로토타입에 구현할 수 있다.
그러나, 믹스인이 실수로 기존 클래스 메서드를 덮어쓰는 일이 없도록 해야한다.
- 특정 행동을 실행해주는 메서드를 제공
- 단독으로 쓰이지 않고 다른 클래스에 행동을 더해주는 용도.
#
믹스인 사용법믹스인
#
믹스인 안에서 믹스인 상속#
이벤트 믹스인클래스나 객체에 이벤트 관련 함수를 쉽게 추가할 수 있는 믹스인
#
용도1- 사용자 로그인에서, 객체
user
가login
이벤트 생성 calendar
는user
가 생성한login
이벤트를 듣고 사용자에게 맞는 달력을 제공
#
용도2- 메뉴의 항목을 선택했을 때 객체
menu
가select
라는 이벤트를 생성 - 어떤 객체가
select
에 반응하는 이벤트 핸들러 할당
#
사용법믹스인