ES5 방식
// ES5
function Person1(name) {
this.name = name;
}
// prototype method
Person1.prototype.getName = function(){
return this.name;
}
// static method, intance 에서는 호출 불가
Person1.isPerson = function (obj){
return obj instanceof this
}
const k = new Person1('kang') // instance 생성
console.log(k.getName()) // kang
console.log(Person1.isPerson(k)) // true
// instance
// person.getName() // (o)
// person.isPerson() // (x)
// Person1.getName() // (x)
// Person1.isPerson() // (o)
ES6 Class
class Person2 {
constructor (name) { this.name = name }
getName () { return this.name }
static isPerson (obj) { return obj instanceof this } // static method
}
const k2 = new Person2('kang2')
console.log(k2.getName()) // kang
console.log(Person2.isPerson(k2)) // true
선언 방식
// 클래스 리터럴 , 클래스는 식 or 값.
class Person1 { }
console.log(Person1.name) // Person1
// 기명 클래스 표현식
const Person2 = class Person22 { }
console.log(Person2.name) // Person22
// 익명 클래스 표현식
const Person3 = class { }
console.log(Person3.name) // Person3
기존 방식과의 차이점
if(true) {
class A {}
const a = new A() // o
if(true) {
// 변수 A만 호이스팅 되고, 할당은 x -> TDZ
const b = new A() // TDZ Error
class A {}
}
}
const c = new A() // referenceError, A는 if
class 내부는 strict mode가 강제된다.
모든 메소드는 열거할 수 없다.
class A {
a () {}
b () {}
static c () {}
}
for(let p in A.prototype){
console.log(p) // undefined , class 내부 메소드들이 열거 안됨.
}
class A {
constructor () {}
a () {}
static c () {}
}
const a = new A.prototype.constructor() // A {}
const b = new A.prototype.a() // Uncaught TypeError: A.prototype.a is not a constructor
const c = new A.prototype.c() // Uncaught TypeError: A.prototype.c is not a constructor
A.prototype.constructor === A // true
A의 constructor는 자기 자신(A)과 같다.
A 클래스 자체에는 prototype 있기 때문에 new로 호출이 가능하다.
A 클래스의 constructor()에는 prototype이 있기 때문에 마찬가지로 new로 호출이 가능하다.
반면에 A클래스의 a () 메소드에는 prototype이 없기 때문에 new로 호출이 불가능하다.
class A {}
new A() // A {}
A() // Uncaught TypeError: Class constructor A cannot be invoked without 'new'
// 기존 방식은 생성자, 함수로 사용 가능
function AA () {}
new AA() // AA () {}
AA() // AA () {}
// 익명 클래스 표현식
let A = class {
constructor () { A = 'A' }
}
const a = new A()
console.log(A) // 'A' 변경됨
// 클래스 선언문 방식,
class C {
constructor () { C = 'C' }
}
const c = new C() // Uncaught TypeError: Assignment to constant variable.
// 내부에서 C를 변경할려는 경우 C는 상수로 취급하기 때문에 수정 불가
C = '20' // 20
// 외부에서 C를 변경하는 경우 C는 let으로 취급하여 수정 가능
class A {
a () {}
}
// prototype 전체를 덮어 씌우기 시도 -> 변화 없음
A.prototype = {
b() {console.log(1)}
}
// prototype의 메소드 하나 하나는 수정이 가능
a.a() // undefined
A.prototype.a = function() { console.log(2)}
a.a() // 2
반면에 기존 방식에서는 prototype 전체 수정이 가능했다.
function B () {}
B.prototype = {
a() { console.log(1)}
}
식, 값이기 때문에 class를 다른 함수에 인자로 넘길 수 있다.
const instanceGenerator = (className, ...params) => new className(...params)
class Person {
constructor (name) { this.name = name }
getName () { console.log(this.name)}
}
// class를 인자 값으로 전달 함.
const k = instanceGenerator(Person, 'kang')
k.getName(); // kang
객체 리터럴 표기법의 객체 속성 이름을 동적으로 설정이 가능, 계산된 프로퍼티 이름 설정이 가능
const method1 = 'sayName';
const fullNameGetter = 'fullName'
class Person {
constructor (name) { this.name = name }
// 메소드 이름을 동적으로 설정
[method1] () { console.log(this.name) }
get [fullNameGetter + 123] () { return this.name + 'sang'}
}
const k = new Person('kang')
k.sayName() // kang
k.fullName123 // "kangsang"
class A {
// 객체와 마찬가지로 *을 앞에 적음
*gene () {
yield 1;
yield 2;
}
}
const a = new A();
const iter = a.gene();
console.log(...iter) // 1 2
iter.next() // {value: 1, done: false}
iter.next() // {value: 2, done: false}
class Products {
constructor () {
this.items = new Set()
}
addItem (name) {
console.log(this)
this.items.add(name)
}
[Symbol.iterator] () {
let count = 0
const items = [...this.items]
return {
next () {
retur
done: coun{nt >= items.length,
value: items[count++]
}
}
}
}
}
const a = new Products(); // Set 타입의 this.items 생성
a.addItem('사과') // 데이터 추가
a.addItem('수박')
[...a] // ['사과', '수박']
class Products {
constructor () {
this.items = new Set()
}
addItem (name) {
console.log(this.items)
this.items.add(name)
}
*[Symbol.iterator] () {
yield* this.items
}
}
class Person {
static create (name) {
return new this(name)
}
constructor (name) {
this.name = name
}
}
const k = Person.create('kang')
k // Person {name: "kang"}
const kk = new Person('kkang')
kk // Person {name: "kkang"}
super 메소드: 상위 클래스의 constructor를 호출. 오직 constructor안에서만 사용 가능
class Square {
constructor (width) {
// this는 인스턴스 or super 메소드를 호출한 인스턴스
this.width = width
}
getArea () {
return this.width * ( this.height || this.width )
}
}
class Rectangle extends Square {
constructor (width, height){
// super: 상위 클래스의 constructor를 호출하는 함수
// 오직 constructor안에서만 호출이 가능하다.
super(width)
// this: Rectangle, this.width = width
this.height = height
}
}
const rect = new Rectangle(10, 30)
rect.getArea() // 300
class [서브클래스명] extends [수퍼클래스명] { [서브클래스 본문] }
class Employee extends class Person {
constructor (name) { this.name = name }
} {
// subClass 본문
constructor (name, position) {
super(name)
this.position = position
}
}
const k = new Employee('kang', 'worker')
console.log(k) // Employee { name: 'kang', position: 'worker' }
console.log(k.__proto__.__proto__.constructor.name) // Person
function Person (name) { this.name = name }
class Employee extends Person {
// subClass 본문
constructor (name, position) {
super(name)
this.position = position
}
}
const k = new Employee('kang', 'worker')
toString()를 처리하는 과정을 바꿔서 사용
추가하고 수정하고자 것만 설정하고 나머지는 그대로 사용 가능
class newArray extends Array {
toString () {
return `[${super.toString()}]`
}
}
const arr = new newArray(1,2,3)
arr.toString() // "[1,2,3]"
arr.pop() // 3
[1,2,3].toString() // "1,2,3"
super(내부 키워드로써, 허용된 동작 외엔 활용 불가)
constructor 내부에서
메소드 내부에서
class Rectangle {
constructor(width, height) {
this.width = width
this.height = height
}
getArea () {
return this.width * this.height
}
}
class Square extends Rectangle {
constructor(width){
super(width, width); // 가로 === 세로
}
getArea () {
console.log('getArea of Square')
return super.getArea()
}
}
const square = new Square(5)
console.log(square.getArea()) // getArea of Square 25
class Shape {
constructor () {
// new로 Shape 인스턴스를 생성한 경우
if(new.target === Shape){
throw new Error('이 클래스는 인스턴스화할 수 없는 추상클래스임.')
}
}
}
class Rectangle extends Shape {
constructor(width, height) {
this.width = width
this.height = height
}
getArea () {
return this.width * this.height
}
}
class Square extends Rectangle {
constructor(width){
super(width, width); // 가로 === 세로
}
getArea () {
console.log('getArea of Square')
console.log
return super.getArea()
}
}
const s = new Shape() // error, Shape 클래스는 instance화 불가능
const r = new Rectangle(2, 5)
좋은글 감사합니다 :-)