티스토리 뷰


ES6


Class


ES6에서 class 라는 문법이 추가 되었고, 기존의 prototype 기반으로 클래스를 만드는 것보다 명료하게 클래스를 만들 수 있게 되었습니다.



1. 클래스 정의

ES6에서 클래스는 특별한 함수입니다. 그렇기 때문에, 함수와 동일하게 클래스 선언(Class declarations)과 클래스 표현(Class expressions)으로 클래스를 만들 수 있습니다 ([자바스크립트] 함수(Function), 즉시실행함수(Immediately-invoked function expression) 참고)


클래스 선언(Class declarations)

class Polygon {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
}

클래스 선언은 함수 선언과 달리 호이스팅 되지 않습니다. ([자바스크립트] 유효범위(Scope)와 호이스팅(Hoisting) 참고)

var p = new Polygon(); // ReferenceError
class Polygon {}

클래스 선언은 호이스팅 되지 않습니다.클래스 선언은 호이스팅 되지 않습니다.


클래스 표현(Class expressions)

익명 클래스와 기명 클래스를 만들 수 있습니다.

// unnamed
var Polygon = class {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
};

// named
var Polygon = class Polygon {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
};

클래스 표현(Class expressions) 또한 클래스 선언(Class declarations)와 같이 호이스팅(hoisting)이 되지 않습니다.



2. 메소드 정의

ES6의 class에서, 클래스의 몸통(body)는 {} 이며, class 메소드는 class의 {} 안에 정의해야 합니다.


Strict mode

클래스 몸통(body)는 strict mode로 실행됩니다. ([자바스크립트] 엄격 모드(strict mode) 참고)


생성자(Constructor)

생성자 메소드는 객체의 생성과 초기화를 하는 특별한 메소드입니다. 클래스에서 constructor 이름을 갖는 메소드는 하나여야 합니다.

var Polygon = class {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
    constructor(height2, width2) {
        this.height = height2 * 2 ;
        this.width = width2 * 2;
    }
};

constructor는 하나여야 합니다.constructor는 하나여야 합니다.


생성자 메소드에서 super 키워드를 통해 상위 클래스의 생성자 메소드를 호출 할 수 있습니다.

class Polygon {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
}

class Square extends Polygon {
    constructor(length) {
        // length로 다각형의 넓이와 높이를 정의하기 위해 부모클래스의 생성자를 호출합니다.
        super(length, length);
        // Note: 파생 클래스에서, 'this'를 사용하기 전에는 반드시 super()를
        // 호출하여야 합니다. 그렇지 않을 경우 참조에러가 발생합니다.
        this.name = 'Square';
    }

    get area() {
        return this.height * this.width;
    }

    set area(value) {
        this.area = value;
    } 
}

var test = new Square(4);
console.log(test.area);

생성자 메소드에서 this를 사용하기 위해서 super 메소드를 먼저 호출해야 합니다.

set, get 함수의 선언법은 [자바스크립트] getter, setter 참고바랍니다.


프로토타입 메소드(Prototype methods)

class Polygon {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  
  get area() {
    return this.calcArea();
  }

  calcArea() {
    return this.height * this.width;
  }
}

const square = new Polygon(10, 10);

console.log(square.area);


ES6는 메소드 정의를 위한 더 짧은 구문이 도입되었습니다. 다음 코드가 주어지면,

var obj = {
    foo: function() {},
    bar: function() {}
};

ES6에서는 아래와 같이 줄일 수 있습니다.

var obj = {
    foo() {},
    bar() {}
};


정적 메소드(static methods)

static 메소드는 클래스의 인스턴스 (var a = new testFunc()) 필요없이 호출 가능합니다. 또한 클래스의 인스턴스에서 static 메소드를 호출 할 수 없습니다.

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    static distance(a, b) {
        const dx = a.x - b.x;
        const dy = a.y - b.y;

        return Math.sqrt(dx*dx + dy*dy);
    }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
console.log(Point.distance(p1, p2));

var p3 = new Point(1, 1);
p3.distance(p1, p2);

class의 static 메소드class의 static 메소드


인스턴스 없이 정상적으로 distance가 호출 되는 것과, 인스턴스를 통해 distance를 호출 할 때 TypeError가 발생하는 것을 확인 할 수 있습니다.



오토박싱(Autoboxing)

autoboxing이란?

일반 함수에서 this는 window 객체를 가르키게 됩니다. this가 window 객체 (global object)를 가르키는 이유는 autoboxing 덕분입니다.

non-strict 모드에서 ([자바스크립트] this의 정체 참고) this 값이 null 혹은 undefined 일 경우 window 객체(global object)로 자동으로 변환해 주는 것을 autoboxing이라고 합니다.


프로토타입 기반의 클래스에서 autoboxing

프로토타입 기반의 class의 경우

function Animal() { }

Animal.prototype.speak = function(){
    console.log(this);
    return this;
}

Animal.eat = function() {
    console.log(this);
    return this;
}

let obj = new Animal();
let speak = obj.speak;
speak(); // global object

let eat = Animal.eat;
eat(); // global object

프로토타입 기반의 클래스의 autoboxing프로토타입 기반의 클래스의 autoboxing


autoboxing이 되어, 일반 함수를 호출하는 것처럼 메소드를 호출 한 경우 window 객체(global object)를 출력하는 것을 확인 할 수 있습니다.


ES6의 클래스 기반의 autoboxing

ES6의 class에서는 autoboxing이 되지 않습니다.

class Animal { 
    speak() {
        console.log(this);
        return this;
    }
    static eat() {
        console.log(this);
        return this;
    }
}

let obj = new Animal();
let speak = obj.speak;
speak(); // undefined
obj.speak();

let eat = Animal.eat;
eat(); // undefined
Animal.eat();

ES6의 class는 autoboxing이 안됨ES6의 class는 autoboxing이 안됨


autoboxing이 되지 않아, 일반 함수를 호출하는 것처럼 메소드를 호출 한 경우 undefined가 출력되는 것을 확인 할 수 있습니다.

그렇기 때문에 ES6의 클래스에서 메소드를 변수에 저장하여 사용할 경우, this에 유의해서 사용해야 합니다.



3. 클래스 상속(sub classing)

ES6의 클래스 상속

extends 키워드를 통하여 클래스를 상속 받아, 자식 클래스를 만들 수 있습니다.

class Animal { 
    constructor(name) {
        this.name = name;
    }
  
    speak() {
        console.log(this.name + ' makes a noise.');
    }
}

class Dog extends Animal {
    speak() {
        console.log(this.name + ' barks.');
    }
}

var d = new Dog('Mitzie');
d.speak();

ES6의 클래스 상속ES6의 클래스 상속


프로토타입 기반의 클래스 상속

프로토타입 기반의 클래스도 extends 키워드를 통해 상속 할 수 있습니다.

function Animal (name) {
    this.name = name;  
}

Animal.prototype.speak = function () {
    console.log(this.name + ' makes a noise.');
}

class Dog extends Animal {
    speak() {
        console.log(this.name + ' barks.');
    }
}

var d = new Dog('Mitzie');
d.speak();

프로토타입 기반의 클래스 상속프로토타입 기반의 클래스 상속


일반 객체의 클래스 상속

일반 객체는 extends 키워드를 통해 상속할 수 없습니다. 상속하고 싶다면 Object.setPrototypeOf 메소드를 사용하여 상속해야 합니다.

var Animal = {
    speak() {
        console.log(this.name + ' makes a noise.');
    }
};

class Dog {
    constructor(name) {
        this.name = name;
    }
    speak() {
        console.log(this.name + ' barks.');
    }
}

Object.setPrototypeOf(Dog.prototype, Animal);

var d = new Dog('Mitzie');
d.speak();

일반 객체의 클래스 상속일반 객체의 클래스 상속



4. Species

class MyArray extends Array {
    // 부모 Array 생성자로 종류 덮어쓰기
    static get [Symbol.species]() { return Array; }
}
var a = new MyArray(1,2,3);
var mapped = a.map(x => x * x);

console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array);   // true

Symbol.speciesSymbol.species


Array를 상속받은 MyArray에서 Array의 default 생성자를 덮어 쓰고 싶을 경우, Symbol.species를 사용하면 됩니다. (get []의 문법은 [자바스크립트] getter, setter 참고 바랍니다.)

Symbol.species로 Array의 생성자를 가져오고, get [] 로 Array를 리턴함으로 부모 Array의 생성자를 덮어 쓸 수 있습니다.



5. super로 부모 클래스 호출하기

super 키워드를 홈하여 부모 클래스의 메소드를 호출 할 수 있습니다.


프로토타입 기반의 부모 클래스 메소드 호출

function Cat(name) {
  this.name = name;
}

Cat.prototype.speak = function () {
  console.log(this.name + ' makes a noise.');
};

function Lion(name) {
  // `super()` 호출
  Cat.call(this, name);
}

// `Cat` 클래스 상속
Lion.prototype = new Cat();
Lion.prototype.constructor = Lion;

// `speak()` 메서드 오버라이드
Lion.prototype.speak = function () {
  Cat.prototype.speak.call(this);
  console.log(this.name + ' roars.');
};

var lion = new Lion("BIG");
lion.speak();

프로토타입 기반의 부모 클래스 메소드 호출프로토타입 기반의 부모 클래스 메소드 호출


프로토타입 기반의 클래스에서 부모 클래스의 메소드를 호출하기 위해서 call과 같은 함수를 사용해야 합니다. ([자바스크립트] API - call, apply 함수 참고)


ES6 클래스 기반의 부모 클래스 메소드 호출

class Cat { 
    constructor(name) {
        this.name = name;
    }
  
    speak() {
        console.log(this.name + ' makes a noise.');
    }
}

class Lion extends Cat {
    speak() {
        super.speak();
        console.log(this.name + ' roars.');
    }
}

var lion = new Lion("BIG");
lion.speak();

 ES6 클래스 기반의 부모 클래스 메소드 호출 ES6 클래스 기반의 부모 클래스 메소드 호출


ES6 클래스는 super 메소드를 사용하여 부모 클래스의 메소드를 호출 할 수 있습니다.



댓글
공지사항
최근에 올라온 글