Я могу понять цель функции сна, если вам приходится иметь дело с синхронным исполнением. Функции setInterval и setTimeout создают поток параллельного выполнения, который возвращает последовательность выполнения обратно в основную программу, что неэффективно, если вам нужно ждать определенного результата. Конечно, можно использовать события и обработчики, но в некоторых случаях это не то, что предназначено.
Объект может иметь только один прототип. Наследование из двух классов может быть выполнено путем создания родительского объекта в виде комбинации двух родительских прототипов.
Синтаксис для подклассификации позволяет сделать это в декларации, поскольку правая часть extends
может быть любым выражением. Таким образом, вы можете написать функцию, которая объединяет прототипы в соответствии с любыми критериями, которые вы хотите, и вызывать эту функцию в объявлении класса.
Нет простого способа выполнить множественное наследование класса. Я следую комбинации ассоциации и наследования для достижения такого поведения.
class Person {
constructor(firstname, lastname, age){
this.firstname = firstname,
this.lastname = lastname
this.Age = age
}
fullname(){
return this.firstname +" " + this.lastname;
}
}
class Organization {
constructor(orgname){
this.orgname = orgname;
}
}
class Employee extends Person{
constructor(firstname, lastname, age,id) {
super(firstname, lastname, age);
this.id = id;
}
}
var emp = new Employee("John", "Doe", 33,12345);
Object.assign(emp, new Organization("Innovate"));
console.log(emp.id);
console.log(emp.orgname);
console.log(emp.fullname());
Надеюсь, что это будет полезно.
Вот потрясающий / действительно дерьмовый способ расширения нескольких классов. Я использую пару функций, которые Бабель вложил в мой перекодированный код. Функция создает новый класс, который наследует class1, а class1 наследует класс2 и т. Д. У этого есть свои проблемы, но забавная идея.
var _typeof = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? function (obj) {
return typeof obj
} : function (obj) {
return obj && typeof Symbol === 'function' && obj.constructor === Symbol ? 'symbol' : typeof obj
}
function _inherits (subClass, superClass) {
if (typeof superClass !== 'function' && superClass !== null) {
throw new TypeError('Super expression must either be null or a function, not ' + (
typeof superClass === 'undefined' ? 'undefined' : _typeof(superClass)))
}
subClass.prototype = Object.create(
superClass && superClass.prototype,
{
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
})
if (superClass) {
Object.setPrototypeOf
? Object.setPrototypeOf(subClass, superClass)
: subClass.__proto__ = superClass.__proto__ // eslint-disable-line no-proto
}
}
function _m (...classes) {
let NewSuperClass = function () {}
let c1 = NewSuperClass
for (let c of classes) {
_inherits(c1, c)
c1 = c
}
return NewSuperClass
}
import React from 'react'
/**
* Adds `this.log()` to your component.
* Log message will be prefixed with the name of the component and the time of the message.
*/
export default class LoggingComponent extends React.Component {
log (...msgs) {
if (__DEBUG__) {
console.log(`[${(new Date()).toLocaleTimeString()}] [${this.constructor.name}]`, ...msgs)
}
}
}
export class MyBaseComponent extends _m(LoggingComponent, StupidComponent) {}
Реализация Серхио Карнейро и Джона требует определения функции инициализации для всех, кроме одного класса. Вот модифицированная версия функции агрегации, которая вместо этого использует конструкторы по умолчанию.
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.
Эта функция агрегации будет предпочитать свойства и методы класса, которые появляются позже в Список классов.
Проверьте, пожалуйста, пример ниже, 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();
Выведет
Test D: extends A, B, C -> outside instance of D: true from A -> inside instance of A: true from B -> inside instance of B: true from C -> inside instance of C: true from D -> inside instance of D: true - Test E: extends A, C -> outside instance of E: true from A -> inside instance of A: true from C -> inside instance of C: true from E -> inside instance of E: true - Test F: extends B -> outside instance of F: true from B -> inside instance of B: true from F -> inside instance of F: true - Test G: wraper to use C alone with "new" decorator, pretty format -> outside instance of G: true from C -> inside instance of C: true - Test B alone, ugly format "new (B(Object))" -> outside instance of B: false, this one fails from B -> inside instance of B: true
использовать с пользовательской функцией для обработки множественного наследования с помощью es6
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
}
class Colored {
initializer () { this._color = "white" }
get color () { return this._color }
set color (v) { this._color = v }
}
class ZCoord {
initializer () { this._z = 0 }
get z () { return this._z }
set z (v) { this._z = v }
}
class Shape {
constructor (x, y) { this._x = x; this._y = y }
get x () { return this._x }
set x (v) { this._x = v }
get y () { return this._y }
set y (v) { this._y = v }
}
class Rectangle extends aggregation(Shape, Colored, ZCoord) {}
var rect = new Rectangle(7, 42)
rect.z = 1000
rect.color = "red"
console.log(rect.x, rect.y, rect.z, rect.color)
использовать Mixins для ES6 multiple Inheritance.
let classTwo = Base => class extends Base{
// ClassTwo Code
};
class Example extends classTwo(ClassOne) {
constructor() {
}
}
Я придумал это решение:
'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;
}
use:
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'
]
};
}
}
Пока вы делаете эти трюки с помощью своих классов, написанных по-своему, он может быть прикованным. но мы скоро, так как вы хотите расширить некоторую функцию / класс, написанную не так, - у вас не будет шанса продолжить цикл.
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
Это не реально, так как работает прототипическое наследование. Давайте посмотрим, как унаследованные реквизиты работают в 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
Вы можете использовать mixins , чтобы получить некоторые из этих функций, но вы не получите позднюю привязку:
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
На странице es6-features.org/#ClassInheritanceFromExpressions можно написать функцию агрегации, чтобы разрешить множественное наследование:
class Rectangle расширяет агрегацию ( Shape, Colored, ZCoord) {}
blockquote>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 }
Но это уже предусмотрено в библиотеках, таких как aggregation .
Джастин Фагнани описывает очень чистый (imho) способ составления нескольких классов в один, используя тот факт, что в ES2015 классы могут быть созданы с помощью выражений класса .
В принципе, так же, как вы можете создать функцию с выражением:
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 поддерживают только одно наследование, вам необходимо создать цепочку классов, которая содержит все классы, которые вы используете муравей смешивать вместе. Итак, скажем, вы хотите создать класс C, который расширяет оба A и B, вы могли бы сделать это:
class A {}
class B extends A {}
class C extends B {} // C extends both A and B
Проблема в том, что он очень статичен. Если вы позже решите, что хотите сделать класс D, который расширяет B, но не A, у вас есть проблема.
. Но с помощью некоторых умных обманщиков, используя тот факт, что классы могут быть выражениями, вы можете решить это, создав 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)
Обратите внимание, как мы решаем в последний момент, какие классы включать в иерархию.
Конечно, если вы похожи на меня, это вдохновляет вас на создание окончательной библиотеки для множественного наследования в Javascript. Если вы это сделаете, пожалуйста, помогите мне сделать именно это!
mics (произносится: mix) - это библиотека, которая делает множественное наследование в Javascript - легкий ветерок. Вдохновленный отличным сообщением в блоге «Реальные» миксины с Javascript-классами Джастином Фагнани, mics пытается создать минимальную библиотеку вокруг концепции использования выражений класса (фабрик) в качестве mixins. mics расширяет концепции, представленные в блоге, создавая микшинов первоклассных граждан, которые могут быть непосредственно использованы для создания объектов и могут быть смешаны с другими миксинами, а не просто с классами.
blockquote>
Это решение ES6 работало для меня:
multiple-inheritance.js
export function allOf(BaseClass, ...Mixins) {
function copyProperties(target, source) {
const allPropertyNames = Object.getOwnPropertyNames(source).concat(Object.getOwnPropertySymbols(source))
allPropertyNames.forEach((propertyName) => {
if (propertyName.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
return
Object.defineProperty(target, propertyName, Object.getOwnPropertyDescriptor(source, propertyName))
})
}
class Base extends BaseClass
{
constructor (...args) {
super(...args)
Mixins.forEach((Mixin) => {
copyProperties(this, new Mixin(...args))
})
}
}
Mixins.forEach((mixin) => {
copyProperties(Base.prototype, Mixin.prototype)
})
return Base
}
main.js
import { allOf } from "./multiple-inheritance.js"
class A
{
constructor(name) {
this.name = name
}
sayA() {
return this.name
}
}
class B
{
constructor(name) {
this.name = name
}
sayB() {
return this.name
}
}
class AB extends allOf(A, B)
{
sayAB() {
return this.name
}
}
const ab = new AB("ab")
console.log("ab.sayA() = "+ab.sayA()+", ab.sayB() = "+ab.sayB()+", ab.sayAB() = "+ab.sayAB())
Урожайность на консоли браузера :
ab.sayA() = ab, ab.sayB() = ab, ab.sayAB() = ab