Classes

                                                                                     

JavaScript class는 ECMAScript 2015을 통해 소개되었으며, 기존 prototype 기반의 상속 보다 명료하게 사용할 수 있습니다. Class 문법은 새로운 객체지향 상속 모델을 제공하는 것은 아닙니다. JavaScript class는 객체를 생성하고 상속을 다루는데 있어 훨씬 더 단순하고 명확한 문법을 제공합니다.

Class 정의

Class는 사실 함수입니다. 함수를 함수 표현식과 함수 선언으로 정의할 수 있듯이 class 문법도 class 표현식과 class 선언 두 가지 방법을 제공합니다.

Class 선언

class를 정의하는 한 가지 방법은 class 선언을 이용하는 것입니다. class를 선언하기 위해서는 클래스의 이름과 함께 class 키워드를 사용해야 합니다.

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

Hoisting

함수 선언과 클래스 선언의 중요한 차이점은 함수 선언의 경우 호이스팅이 일어나지만, 클래스 선언은 그렇지 않다는 것입니다. 클래스를 사용하기 위해서는 클래스를 먼저 선언 해야 하며, 그렇지 않으면, 다음 아래의 코드는 ReferenceError 에러를 던질 것입니다. :

const p = new Rectangle(); // ReferenceError

class Rectangle {}

Class 표현식

class 표현식은 class를 정의 하는 다른 방법입니다. Class 표현식은 이름을 가질 수도 있고, 갖지 않을 수도 있습니다. 이름을 가진 class 표현식의 이름은 클래스의 body에 대해 local scope에 한해 유효합니다.

// unnamed
let Rectangle = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(Rectangle.name);
//output : "Rectangle"


// named
let Rectangle = class Rectangle2 {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(Rectangle.name);
//output: "Rectangle2"

Class body 와 method 정의

Class body는 중괄호 {} 로 묶여 있는 안쪽 부분입니다. 이곳은 여러분이 method이나 constructor와 같은 class members를 정의할 곳입니다.

Strict mode

클래스 선언클래스 표현식의 본문(body)은 strict mode 에서 실행됩니다. 즉, 이 문서에 적힌 코드는 엄격한 문법이 적용되기 때문에 strict mode가 아닌 상태에서는 무시 되는 오류가 발생합니다.

Constructor (생성자)

constructor 메소드는 class 로 생성된 객체를 생성하고 초기화하기 위한 특수한 메소드입니다.  "constructor" 라는 이름을 가진 특수한 메소드는 클래스 안에 한 개만 존재할 수 있습니다. 만약 클래스에 여러 개의 constructor 메소드가 존재하면 SyntaxError 가 발생할 것입니다.

constructor는 부모 클래스의 constructor 를 호출하기 위해 super 키워드를 사용할 수 있습니다.

Prototype methods

method definitions도 참조해보세요.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  // Getter
  get area() {
    return this.calcArea();
  }
  // Method
  calcArea() {
    return this.height * this.width;
  }
}

const square = new Rectangle(10, 10);

console.log(square.area); // 100

Static methods

static 키워드는 클래스를 위한 정적(static) 메소드를 정의합니다. 정적 메소드는 클래스의 인스턴스화(instantiating) 없이 호출되며, 클래스의 인스턴스에서는 호출할 수 없습니다. 정적 메소드는 어플리케이션(application)을 위한 유틸리티(utility) 함수를 생성하는데 주로 사용됩니다.

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.hypot(dx, dy);
    }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
p1.distance;  //undefined
p2.distance;  //undefined

console.log(Point.distance(p1, p2)); // 7.0710678118654755

Boxing with prototype and static methods

정적 메소드나 프로토타입 메소드가 this 값 없이 호출될 때, this 값은 메소드 안에서 undefined가 됩니다. 이 동작은  "use strict" 명령어 없이도 같은 방식으로 동작하는데, class 문법 안에 있는 코드는 항상 strict mode 로 실행되기 때문입니다.

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

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

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

위에 작성된 전통적 방식의 함수기반의 구문으로 작성된 경우, 메서드 호출에서의 오토박싱은 this 초기값 기준의 non-strict mode로 발생하게 됩니다.  만일 초기값이 undefine,이면, this는 전역객체로 설정됩니다.

Autoboxing은 strict mode 에서 발생하지 않으며, this 값은 그대로 유지됩니다.

function Animal() { }

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

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

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

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

Instance properties

인스턴스 속성은 반드시 클래스 메서드 내에 정의되어야 합니다.:

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

정적 (클래스사이드) 속성과 프로토타입 데이터 속성은 반드시 클래스 선언부 바깥쪽에서 정의되어야 합니다. 

Rectangle.staticWidth = 20;
Rectangle.prototype.prototypeWidth = 25;

extends를 통한 클래스 상속(sub classing)

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.');
  }
}

subclass에 constructor가 있다면, "this"를 사용하기 전에 가장 먼저 super()를 호출해야 합니다.

또한 es5에서 사용되던 전통적인 함수 기반의 클래스를 통하여 확장할 수도 있습니다.

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();

클래스는 생성자가 없는 객체(non-constructible)을 확장할 수 없습니다. 만약 기존의 생성자가 없는 객체을 확장하고 싶다면, 이 메소드를 사용하세요. 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();

Species

아마 배열을 상속 받은 MyArray 클래스에서 Array를 반환하고 싶을 것입니다. Species 패턴은 기본 생성자를 덮어쓰도록 해줍니다.

예를 들어, map()과 같은 기본 생성자를 반환하는 메서드를 사용할 때 이 메서드가 MyArray 객체 대신 Array 객체가 반환하도록 하고 싶을 것입니다. Symbol.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

super 를 통한 상위 클래스 호출

super 키워드는 객체의 부모가 가지고 있는 함수들을 호출하기 위해 사용됩니다..

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.');
  }
}

Mix-ins

추상 서브 클래스 또는 믹스-인은 클래스를 위한 템플릿입니다. ECMAScript 클래스는 하나의 단일 슈퍼클래스만을 가질 수 있으며, 예를 들어 툴링 클래스로부터의 다중 상속은 불가능합니다. 기능은 반드시 슈퍼클래스에서 제공되어야 합니다.

슈퍼클래스를 인자로 받고 이 슈퍼클래스를 확장하는 서브클래스를 생성하여 반환하는 함수를 사용하여 ECMAScript에서 믹스-인을 구현할 수 있습니다:

아래는 두 함수는 어떤 클래스를 인자로 받고 그 클래스를 상속한 새로운 익명 클래스를 리턴하는 arrow function 입니다.

var calculatorMixin = Base => class extends Base {
  calc() { }
};

var randomizerMixin = Base => class extends Base {
  randomize() { }
};

위 믹스-인을 사용하는 클래스는 다음과 같이 작성할 수 있습니다:

class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }

명세서

Specification Status Comment
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Class definitions' in that specification.
Standard Initial definition.
ECMAScript 2016 (ECMA-262)
The definition of 'Class definitions' in that specification.
Standard
ECMAScript 2017 (ECMA-262)
The definition of 'Class definitions' in that specification.
Standard
ECMAScript Latest Draft (ECMA-262)
The definition of 'Class definitions' in that specification.
Draft

The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.브라우저 호환성

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
classesChrome Full support 49
Notes
Full support 49
Notes
Notes From Chrome 42 to 48, strict mode is required. Non-strict mode support can be enabled using the flag "Enable Experimental JavaScript".
Edge Full support 13Firefox Full support 45IE No support NoOpera Full support 36
Notes
Full support 36
Notes
Notes From Opera 29 to 35, strict mode is required. Non-strict mode support can be enabled using the flag "Enable Experimental JavaScript".
Safari Full support 9WebView Android Full support 49
Notes
Full support 49
Notes
Notes From WebView 42 to 48, strict mode is required.
Chrome Android Full support 49
Notes
Full support 49
Notes
Notes From Chrome 42 to 48, strict mode is required. Non-strict mode support can be enabled using the flag "Enable Experimental JavaScript".
Firefox Android Full support 45Opera Android Full support 36
Notes
Full support 36
Notes
Notes From Opera 29 to 35, strict mode is required. Non-strict mode support can be enabled using the flag "Enable Experimental JavaScript".
Safari iOS Full support 9Samsung Internet Android Full support 5.0
Notes
Full support 5.0
Notes
Notes In Samsung Internet 4.0, strict mode is required.
nodejs Full support 6.0.0
Full support 6.0.0
Full support 4.0.0
Disabled
Disabled From version 4.0.0: this feature is behind the --use_strict runtime flag.
Full support 5.0.0
Disabled
Disabled From version 5.0.0: this feature is behind the --harmony runtime flag.
constructorChrome Full support 49
Notes
Full support 49
Notes
Notes From Chrome 42 to 48 strict mode is required. Non-strict mode support can be enabled using the flag "Enable Experimental JavaScript".
Edge Full support 13Firefox Full support 45IE No support NoOpera Full support 36Safari Full support 9WebView Android Full support 49
Notes
Full support 49
Notes
Notes From Chrome 42 to 48 strict mode is required. Non-strict mode support can be enabled using the flag "Enable Experimental JavaScript".
Chrome Android Full support YesFirefox Android Full support 45Opera Android ? Safari iOS Full support 9Samsung Internet Android Full support Yesnodejs Full support 6.0.0
Full support 6.0.0
Full support 4.0.0
Disabled
Disabled From version 4.0.0: this feature is behind the --use_strict runtime flag.
Full support 5.0.0
Disabled
Disabled From version 5.0.0: this feature is behind the --harmony runtime flag.
extendsChrome Full support 49
Notes
Full support 49
Notes
Notes From Chrome 42 to 48 strict mode is required. Non-strict mode support can be enabled using the flag "Enable Experimental JavaScript".
Edge Full support 13Firefox Full support 45IE No support NoOpera Full support 36Safari Full support 9WebView Android Full support 49
Notes
Full support 49
Notes
Notes From Chrome 42 to 48 strict mode is required. Non-strict mode support can be enabled using the flag "Enable Experimental JavaScript".
Chrome Android Full support YesFirefox Android Full support 45Opera Android ? Safari iOS Full support 9Samsung Internet Android Full support Yesnodejs Full support 6.0.0
Full support 6.0.0
Full support 4.0.0
Disabled
Disabled From version 4.0.0: this feature is behind the --use_strict runtime flag.
Full support 5.0.0
Disabled
Disabled From version 5.0.0: this feature is behind the --harmony runtime flag.
Private class fieldsChrome Full support 74Edge No support NoFirefox No support NoIE No support NoOpera Full support 62Safari No support NoWebView Android Full support 74Chrome Android Full support 74Firefox Android No support NoOpera Android Full support 53Safari iOS No support NoSamsung Internet Android No support Nonodejs Full support 12.0.0
Public class fieldsChrome Full support 72Edge No support NoFirefox Full support 69IE No support NoOpera Full support 60Safari No support NoWebView Android Full support 72Chrome Android Full support 72Firefox Android No support NoOpera Android Full support 51Safari iOS No support NoSamsung Internet Android No support Nonodejs Full support 12.0.0
staticChrome Full support 49
Notes
Full support 49
Notes
Notes From Chrome 42 to 48 strict mode is required. Non-strict mode support can be enabled using the flag "Enable Experimental JavaScript".
Edge Full support 13Firefox Full support 45IE No support NoOpera Full support 36Safari Full support 9WebView Android Full support 49
Notes
Full support 49
Notes
Notes From Chrome 42 to 48 strict mode is required. Non-strict mode support can be enabled using the flag "Enable Experimental JavaScript".
Chrome Android Full support YesFirefox Android Full support 45Opera Android ? Safari iOS Full support 9Samsung Internet Android Full support Yesnodejs Full support 6.0.0
Full support 6.0.0
Full support 4.0.0
Disabled
Disabled From version 4.0.0: this feature is behind the --use_strict runtime flag.
Full support 5.0.0
Disabled
Disabled From version 5.0.0: this feature is behind the --harmony runtime flag.
Static class fieldsChrome Full support 72Edge No support NoFirefox No support No
Notes
No support No
Notes
Notes Static fields aren't supported, see bug 1535804.
IE No support NoOpera Full support 60Safari No support NoWebView Android Full support 72Chrome Android Full support 72Firefox Android No support NoOpera Android Full support 51Safari iOS No support NoSamsung Internet Android No support Nonodejs Full support 12.0.0

Legend

Full support  
Full support
No support  
No support
Compatibility unknown  
Compatibility unknown
See implementation notes.
See implementation notes.
User must explicitly enable this feature.
User must explicitly enable this feature.


참조