[javascript] ES2015 (ES6)`class` 구문은 어떤 이점을 제공합니까?

ES6 수업에 대해 많은 질문이 있습니다.

class구문 사용의 이점은 무엇입니까 ? 공개 / 비공개 / 정적이 ES7의 일부가 될 것이라고 읽었습니다. 그게 이유인가요?

또한 class다른 종류의 OOP입니까 아니면 여전히 JavaScript의 프로토 타입 상속입니까? 을 사용하여 수정할 수 있습니까 .prototype? 또는 동일한 객체이지만 선언하는 두 가지 방법입니다.

속도 이점이 있습니까? 큰 앱과 같은 큰 애플리케이션이 있다면 유지 관리 / 이해가 더 쉬울까요?



답변

새로운 class구문를 들면, 지금은 주로 문법 설탕. (하지만 좋은 종류의 설탕이 있습니다.) ES2015-ES2020 class에는 생성자 함수 Reflect.construct(서브 클래 싱 ErrorArray¹ 포함)로 할 수없는 작업이 없습니다 . (그것은 이다 아마 당신이 할 수있는 ES2021에 몇 가지가있을 것입니다 class당신이 그렇지 않으면 할 수없는 : private 필드 , 개인 방법정적 필드 / 개인 정적 방법 .)

또한 class다른 종류의 OOP입니까 아니면 여전히 JavaScript의 프로토 타입 상속입니까?

생성자 함수 ( , 등)를 사용 하는 것을 좋아 한다면 더 깔끔하고 편리한 구문으로 우리가 항상 가지고 있었던 것과 동일한 프로토 타입 상속 new Foo입니다. (특히 ES5 이전 버전에서는 할 수 없었던 Arrayor Error에서 파생 된 경우입니다 . 이제 Reflect.construct[ spec , MDN ]으로는 가능하지만 이전 ES5 스타일에서는 불가능합니다.)

을 사용하여 수정할 수 있습니까 .prototype?

예, prototype클래스를 만든 후에도 클래스 생성자 에서 개체를 수정할 수 있습니다 . 예를 들어, 이것은 완벽하게 합법적입니다.

class Foo {
    constructor(name) {
        this.name = name;
    }

    test1() {
        console.log("test1: name = " + this.name);
    }
}
Foo.prototype.test2 = function() {
    console.log("test2: name = " + this.name);
};

속도 이점이 있습니까?

이것에 대한 특정 관용구를 제공함으로써, 나는 그것의 가정 가능한 엔진이 더 나은 작업 최적화를 할 수있을 수 있음. 그러나 그들은 이미 최적화에 매우 능숙합니다. 나는 큰 차이를 기대하지 않습니다.

ES2015 (ES6) class구문은 어떤 이점을 제공합니까?

간단히 말해서 : 처음에 생성자 함수를 사용하지 않는 경우 선호 Object.create하거나 유사한 class것은 유용하지 않습니다.

생성자 함수를 사용하는 경우 다음과 같은 이점이 있습니다 class.

  • 구문이 더 간단하고 오류가 덜 발생합니다.

  • 그건 훨씬 더 쉽게 (다시, 더 적은 오류가 발생하기 쉬운) 이전보다 새로운 구문을 사용하여 상속 계층 구조를 설정합니다.

  • classnew생성자 함수와 함께 사용하지 못하는 일반적인 오류로부터 사용자를 보호합니다 (생성자에 this대해 유효한 개체가 아닌 경우 생성자가 예외를 throw하도록 함 ).

  • 새 구문을 사용하면 부모 프로토 타입 버전의 메서드를 호출하는 것이 이전 ( 또는 super.method()대신) 보다 훨씬 간단합니다 .ParentConstructor.prototype.method.call(this)Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)

다음은 계층 구조에 대한 구문 비교입니다.

// ***ES2015+**
class Person {
    constructor(first, last) {
        this.first = first;
        this.last = last;
    }

    personMethod() {
        // ...
    }
}

class Employee extends Person {
    constructor(first, last, position) {
        super(first, last);
        this.position = position;
    }

    employeeMethod() {
        // ...
    }
}

class Manager extends Employee {
    constructor(first, last, position, department) {
        super(first, last, position);
        this.department = department;
    }

    personMethod() {
        const result = super.personMethod();
        // ...use `result` for something...
        return result;
    }

    managerMethod() {
        // ...
    }
}

예:

코드 스 니펫 표시

// **ES5**
var Person = function(first, last) {
    if (!(this instanceof Person)) {
        throw new Error("Person is a constructor function, use new with it");
    }
    this.first = first;
    this.last = last;
};

Person.prototype.personMethod = function() {
    // ...
};

var Employee = function(first, last, position) {
    if (!(this instanceof Employee)) {
        throw new Error("Employee is a constructor function, use new with it");
    }
    Person.call(this, first, last);
    this.position = position;
};
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.employeeMethod = function() {
    // ...
};

var Manager = function(first, last, position, department) {
    if (!(this instanceof Manager)) {
        throw new Error("Manager is a constructor function, use new with it");
    }
    Employee.call(this, first, last, position);
    this.department = department;
};
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.personMethod = function() {
    var result = Employee.prototype.personMethod.call(this);
    // ...use `result` for something...
    return result;
};
Manager.prototype.managerMethod = function() {
    // ...
};

라이브 예 :

코드 스 니펫 표시

보시다시피, 틀리기 쉽고 재 입력하기 지루한 반복적이고 장황한 내용이 많이 있습니다 (이것이 제가 스크립트를 작성 했던 이유 입니다.


¹ “ES2015-ES2018 class에는 생성자 함수 및 Reflect.construct(하위 클래스 Error및 포함 Array)로 할 수없는 작업이 없습니다. “

예:


답변

ES6 클래스는 오늘날 우리가 사용하는 프로토 타입 클래스 시스템을위한 구문 설탕입니다. 그들은 당신의 코드를 더 간결하고 자체 문서화하기 때문에 (제 생각에는) 그것을 사용하기에 충분한 이유입니다.

Babel을 사용하여이 ES6 클래스를 트랜스 파일합니다.

class Foo {
  constructor(bar) {
    this._bar = bar;
  }

  getBar() {
    return this._bar;
  }
}

다음과 같은 것을 줄 것입니다.

var Foo = (function () {
  function Foo(bar) {
    this._bar = bar;
  }

  Foo.prototype.getBar = function () {
    return this._bar;
  }

  return Foo;
})();

두 번째 버전은 훨씬 더 복잡하지 않고 유지 관리 할 코드가 더 많습니다. 상속이 관련되면 이러한 패턴은 더욱 복잡해집니다.

클래스는 우리가 사용해 왔던 동일한 프로토 타입 패턴으로 컴파일되기 때문에 동일한 프로토 타입 조작을 수행 할 수 있습니다. 여기에는 런타임시 메소드 추가,에서 메소드 액세스 Foo.prototype.getBar등이 포함됩니다.

액세스를 원하지 않는 개체를 내 보내지 않는 것을 기반으로하지만 오늘날 ES6에는 개인 정보 보호에 대한 몇 가지 기본 지원이 있습니다. 예를 들어 다음을 수행 할 수 있습니다.

const BAR_NAME = 'bar';

export default class Foo {
  static get name() {
    return BAR_NAME;
  }
}

BAR_NAME다른 모듈을 직접 참조하는 데 사용할 수 없습니다.

extends메서드와 같은 함수 및 속성의 검증되지 않은 해시를 사용하는 Backbone과 같은 많은 라이브러리가이를 지원하거나 해결하려고 시도했지만 프로토 타입을 다루지 않는 프로토 타입 상속을 노출하는 일관된 시스템이 없습니다.

JS 코드가 더 복잡해지고 코드베이스가 커짐에 따라 우리는 상속 및 모듈과 같은 것을 처리하기 위해 많은 패턴을 발전시키기 시작했습니다. 모듈의 전용 범위를 만드는 데 사용되는 IIFE에는 많은 중괄호와 괄호가 있습니다. 이들 중 하나가 누락되면 완전히 다른 작업을 수행하는 유효한 스크립트가 생성 될 수 있습니다 (모듈이 다음 모듈을 매개 변수로 전달한 후 세미콜론을 건너 뛰는 것은 거의 좋지 않음).

tl; dr : 우리가 이미하고있는 일에 당연한 일이며 코드에서 귀하의 의도를 명확히합니다.


답변