BabelJS 와 MDN 에 대한 대부분의 연구를 수행했습니다. (정보가 전혀 없음)에 대한 했지만 ES6 Spec에 대한 자세한 정보를 둘러 보는 데 충분히주의를 기울이지 않았다면 언제든지 알려주십시오.
ES6이 다른 오리 유형 언어와 동일한 방식으로 다중 상속을 지원하는지 궁금합니다. 예를 들어 다음과 같이 할 수 있습니까?
class Example extends ClassOne, ClassTwo {
constructor() {
}
}
여러 클래스를 새 클래스로 확장하려면? 그렇다면 통역사는 ClassOne보다 ClassTwo의 메소드 / 속성을 선호합니까?
답변
객체는 하나의 프로토 타입 만 가질 수 있습니다. 두 개의 상위 프로토 타입의 조합으로 상위 오브젝트를 작성하여 두 클래스에서 상속 할 수 있습니다.
서브 클래 싱 구문을 사용하면 extends
절의 오른쪽이 표현식 일 수 있으므로 선언에서이를 수행 할 수 있습니다. 따라서 원하는 기준에 따라 프로토 타입을 결합하는 함수를 작성하고 클래스 선언에서 해당 함수를 호출 할 수 있습니다.
답변
아래의 예를 확인하십시오 super
. 방법이 예상대로 작동합니다. 몇 가지 트릭을 사용하면 instanceof
대부분의 경우 작동합니다.
// base class
class A {
foo() {
console.log(`from A -> inside instance of A: ${this instanceof A}`);
}
}
// B mixin, will need a wrapper over it to be used
const B = (B) => class extends B {
foo() {
if (super.foo) super.foo(); // mixins don't know who is super, guard against not having the method
console.log(`from B -> inside instance of B: ${this instanceof B}`);
}
};
// C mixin, will need a wrapper over it to be used
const C = (C) => class extends C {
foo() {
if (super.foo) super.foo(); // mixins don't know who is super, guard against not having the method
console.log(`from C -> inside instance of C: ${this instanceof C}`);
}
};
// D class, extends A, B and C, preserving composition and super method
class D extends C(B(A)) {
foo() {
super.foo();
console.log(`from D -> inside instance of D: ${this instanceof D}`);
}
}
// E class, extends A and C
class E extends C(A) {
foo() {
super.foo();
console.log(`from E -> inside instance of E: ${this instanceof E}`);
}
}
// F class, extends B only
class F extends B(Object) {
foo() {
super.foo();
console.log(`from F -> inside instance of F: ${this instanceof F}`);
}
}
// G class, C wrap to be used with new decorator, pretty format
class G extends C(Object) {}
const inst1 = new D(),
inst2 = new E(),
inst3 = new F(),
inst4 = new G(),
inst5 = new (B(Object)); // instance only B, ugly format
console.log(`Test D: extends A, B, C -> outside instance of D: ${inst1 instanceof D}`);
inst1.foo();
console.log('-');
console.log(`Test E: extends A, C -> outside instance of E: ${inst2 instanceof E}`);
inst2.foo();
console.log('-');
console.log(`Test F: extends B -> outside instance of F: ${inst3 instanceof F}`);
inst3.foo();
console.log('-');
console.log(`Test G: wraper to use C alone with "new" decorator, pretty format -> outside instance of G: ${inst4 instanceof G}`);
inst4.foo();
console.log('-');
console.log(`Test B alone, ugly format "new (B(Object))" -> outside instance of B: ${inst5 instanceof B}, this one fails`);
inst5.foo();
인쇄합니다
테스트 D : A, B, C를 D의 인스턴스 외부로 확장 : true A-> A의 인스턴스 내부 : true B에서-> B의 인스턴스 내부 : true C에서-> C의 인스턴스 내부 : true D에서-> D의 인스턴스 내부에서 : true - 테스트 E : E의 인스턴스 외부에서 A, C->를 확장합니다. A-> A의 인스턴스 내부 : true C에서-> C의 인스턴스 내부 : true E-> E의 인스턴스 내부에서 : true - 테스트 F : F-외부 인스턴스 B-> 확장 : true B에서-> B의 인스턴스 내부 : true F에서-> F의 인스턴스 내부 : true - 테스트 G : "새로운"데코레이터와 함께 C를 단독으로 사용하는 랩퍼, 예쁜 형식-> G의 인스턴스 외부 : true C에서-> C의 인스턴스 내부 : true - 테스트 B 단독, 못생긴 형식 "new (B (Object))"-> B의 외부 인스턴스 : false, 실패 B에서-> B의 인스턴스 내부 : true
답변
Sergio Carneiro와 Jon의 구현을 위해서는 하나의 클래스를 제외하고 초기화 프로그램 함수를 정의해야합니다. 다음은 생성자에서 기본 매개 변수를 사용하는 집계 함수의 수정 된 버전입니다. 저의 의견도 포함되어 있습니다.
var aggregation = (baseClass, ...mixins) => {
class base extends baseClass {
constructor (...args) {
super(...args);
mixins.forEach((mixin) => {
copyProps(this,(new mixin));
});
}
}
let copyProps = (target, source) => { // this function copies all properties and symbols, filtering out some special ones
Object.getOwnPropertyNames(source)
.concat(Object.getOwnPropertySymbols(source))
.forEach((prop) => {
if (!prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop));
})
}
mixins.forEach((mixin) => { // outside contructor() to allow aggregation(A,B,C).staticFunction() to be called etc.
copyProps(base.prototype, mixin.prototype);
copyProps(base, mixin);
});
return base;
}
다음은 약간의 데모입니다.
class Person{
constructor(n){
this.name=n;
}
}
class Male{
constructor(s='male'){
this.sex=s;
}
}
class Child{
constructor(a=12){
this.age=a;
}
tellAge(){console.log(this.name+' is '+this.age+' years old.');}
}
class Boy extends aggregation(Person,Male,Child){}
var m = new Boy('Mike');
m.tellAge(); // Mike is 12 years old.
이 집계 함수는 나중에 클래스 목록에 나타나는 클래스의 속성과 메서드를 선호합니다.
답변
Justin Fagnani 는 ES2015에서 클래스 표현식 으로 클래스를 작성할 수 있다는 사실을 사용하여 여러 클래스를 하나로 구성하는 매우 깨끗한 (imho) 방법을 설명 합니다 .
식 대 선언
기본적으로 표현식을 사용하여 함수를 만들 수있는 것처럼 :
function myFunction() {} // function declaration
var myFunction = function(){} // function expression
클래스에서도 똑같이 할 수 있습니다.
class MyClass {} // class declaration
var MyClass = class {} // class expression
표현식은 코드가 실행될 때 런타임에 평가되는 반면, 선언은 사전에 실행됩니다.
클래스 표현식을 사용하여 믹스 인 만들기
이를 사용하여 함수가 호출 될 때만 클래스를 동적으로 작성하는 함수를 작성할 수 있습니다.
function createClassExtending(superclass) {
return class AwesomeClass extends superclass {
// you class body here as usual
}
}
그것에 대한 멋진 점은 전체 클래스를 미리 정의하고 함수를 호출 할 때까지 확장 할 클래스 만 결정할 수 있다는 것입니다.
class A {}
class B {}
var ExtendingA = createClassExtending(A)
var ExtendingB = createClassExtending(B)
여러 클래스를 함께 혼합하려면 ES6 클래스가 단일 상속 만 지원하므로 함께 혼합하려는 모든 클래스를 포함하는 클래스 체인을 작성해야합니다. A와 B를 모두 확장하는 클래스 C를 만들고 싶다고 가정 해 봅시다.
class A {}
class B extends A {}
class C extends B {} // C extends both A and B
이것의 문제는 매우 정적 인 것입니다. 나중에 A가 아닌 B로 확장되는 클래스 D를 만들고자한다면 문제가있는 것입니다.
그러나 클래스가 표현식이 될 수 있다는 사실을 사용하는 현명한 속임수를 사용하면 A와 B를 클래스가 아닌 클래스 팩토리로 작성 하여이 문제를 해결할 수 있습니다 (간단한 화살표 기능 사용).
class Base {} // some base class to keep the arrow functions simple
var A = (superclass) => class A extends superclass
var B = (superclass) => class B extends superclass
var C = B(A(Base))
var D = B(Base)
마지막 순간에 계층 구조에 포함 할 클래스를 결정하는 방법에 주목하십시오.
답변
프로토 타입 상속이 작동하는 방식으로는 불가능합니다. 상속 된 소품이 js에서 어떻게 작동하는지 살펴 보겠습니다.
var parent = {a: function() { console.log('ay'); }};
var child = Object.create(parent);
child.a() // first look in child instance, nope let's go to it's prototype
// then look in parent, found! return the method
존재하지 않는 소품에 액세스하면 어떻게되는지 봅시다 :
child.b; // first look in child instance, nope let's go to it's prototype
// then look in parent, nope let's go to it's prototype
// then look in Object.prototype, nope let's go to it's prototype
// then look at null, give up and return undefined
mixin 을 사용 하여 해당 기능 중 일부를 얻을 수 있지만 바인딩이 늦지 않습니다.
var a = {x: '1'};
var b = {y: '2'};
var c = createWithMixin([a, b]);
c.x; // 1
c.y; // 2
b.z = 3;
c.z; // undefined
vs
var a = {x: 1}
var o = Object.create(a);
o.x; // 1
a.y = 2;
o.y; // 2
답변
이 솔루션을 생각해 냈습니다.
'use strict';
const _ = require( 'lodash' );
module.exports = function( ParentClass ) {
if( ! ParentClass ) ParentClass = class {};
class AbstractClass extends ParentClass {
/**
* Constructor
**/
constructor( configs, ...args ) {
if ( new.target === AbstractClass )
throw new TypeError( "Cannot construct Abstract instances directly" );
super( args );
if( this.defaults === undefined )
throw new TypeError( new.target.name + " must contain 'defaults' getter" );
this.configs = configs;
}
/**
* Getters / Setters
**/
// Getting module configs
get configs() {
return this._configs;
}
// Setting module configs
set configs( configs ) {
if( ! this._configs ) this._configs = _.defaultsDeep( configs, this.defaults );
}
}
return AbstractClass;
}
용법:
const EventEmitter = require( 'events' );
const AbstractClass = require( './abstracts/class' )( EventEmitter );
class MyClass extends AbstractClass {
get defaults() {
return {
works: true,
minuses: [
'u can have only 1 class as parent wich was\'t made by u',
'every othere classes should be your\'s'
]
};
}
}
사용자가 작성한 클래스로 이러한 트릭을 만드는 한 체인 될 수 있습니다. 그러나 우리가 u가 그런 식으로 작성하지 않은 함수 / 클래스를 확장하려고하면 루프를 계속할 기회가 없습니다.
const EventEmitter = require( 'events' );
const A = require( './abstracts/a' )(EventEmitter);
const B = require( './abstracts/b' )(A);
const C = require( './abstracts/b' )(B);
노드 v5.4.1에서 –harmony 플래그와 함께 작동합니다.
답변
es6-features.org/#ClassInheritanceFromExpressions 페이지에서 다중 상속을 허용하는 집계 함수를 작성할 수 있습니다.
Rectangle 클래스는 집계를 확장합니다 (Shape, Colored, ZCoord) {}
var aggregation = (baseClass, ...mixins) => {
let base = class _Combined extends baseClass {
constructor (...args) {
super(...args)
mixins.forEach((mixin) => {
mixin.prototype.initializer.call(this)
})
}
}
let copyProps = (target, source) => {
Object.getOwnPropertyNames(source)
.concat(Object.getOwnPropertySymbols(source))
.forEach((prop) => {
if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
return
Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop))
})
}
mixins.forEach((mixin) => {
copyProps(base.prototype, mixin.prototype)
copyProps(base, mixin)
})
return base
}
그러나 그것은 이미 집계 와 같은 라이브러리에서 제공됩니다 .