ES6 수업에 대해 많은 질문이 있습니다.
class
구문 사용의 이점은 무엇입니까 ? 공개 / 비공개 / 정적이 ES7의 일부가 될 것이라고 읽었습니다. 그게 이유인가요?
또한 class
다른 종류의 OOP입니까 아니면 여전히 JavaScript의 프로토 타입 상속입니까? 을 사용하여 수정할 수 있습니까 .prototype
? 또는 동일한 객체이지만 선언하는 두 가지 방법입니다.
속도 이점이 있습니까? 큰 앱과 같은 큰 애플리케이션이 있다면 유지 관리 / 이해가 더 쉬울까요?
답변
새로운 class
구문를 들면, 지금은 주로 문법 설탕. (하지만 좋은 종류의 설탕이 있습니다.) ES2015-ES2020 class
에는 생성자 함수 Reflect.construct
(서브 클래 싱 Error
및 Array
¹ 포함)로 할 수없는 작업이 없습니다 . (그것은 이다 아마 당신이 할 수있는 ES2021에 몇 가지가있을 것입니다 class
당신이 그렇지 않으면 할 수없는 : private 필드 , 개인 방법 및 정적 필드 / 개인 정적 방법 .)
또한
class
다른 종류의 OOP입니까 아니면 여전히 JavaScript의 프로토 타입 상속입니까?
생성자 함수 ( , 등)를 사용 하는 것을 좋아 한다면 더 깔끔하고 편리한 구문으로 우리가 항상 가지고 있었던 것과 동일한 프로토 타입 상속 new Foo
입니다. (특히 ES5 이전 버전에서는 할 수 없었던 Array
or 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
.
-
구문이 더 간단하고 오류가 덜 발생합니다.
-
그건 훨씬 더 쉽게 (다시, 더 적은 오류가 발생하기 쉬운) 이전보다 새로운 구문을 사용하여 상속 계층 구조를 설정합니다.
-
class
new
생성자 함수와 함께 사용하지 못하는 일반적인 오류로부터 사용자를 보호합니다 (생성자에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 : 우리가 이미하고있는 일에 당연한 일이며 코드에서 귀하의 의도를 명확히합니다.