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
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'
]
};
}
}
// 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
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) {}
class Animal {
constructor(){
Object.assign(this, new Shark())
Object.assign(this, new Clock())
}
}
class Shark {
// only what's in constructor will be on the object, ence the weird this.bite = this.bite.
constructor(){ this.color = "black"; this.bite = this.bite }
bite(){ console.log("bite") }
eat(){ console.log('eat') }
}
class Clock{
constructor(){ this.tick = this.tick; }
tick(){ console.log("tick"); }
}
let animal = new Animal();
animal.bite();
console.log(animal.color);
animal.tick();
我从没见过这种方法,但它确实很有用。您可以使用 function shark(){}代替 class,但是使用 class 也有一些优点。
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.
function myFunction() {} // function declaration
var myFunction = function(){} // function expression
你可以对类做同样的事情:
class MyClass {} // class declaration
var MyClass = class {} // class expression
表达式在运行时,即代码执行时计算,而声明是预先执行的。
使用类表达式创建 Mixin
您可以使用它来创建一个函数,该函数仅在调用该函数时动态创建一个类:
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
问题在于它非常静止。如果您后来决定要创建一个扩展了 B 但不扩展了 A 的类 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)
/*
(c) Jon Krazov 2019
Below is an experiment searching boundaries of JavaScript.
It allows to compute one class out of many classes.
Usage 1: Without own constructor
If no constructor is passed then constructor of each class will be called
with params passed in object. In case of missing params, constructor
will be called without params.
Example:
const MyClass1 = computeClass([Class1, Class2, Class3]);
const myClass1Instance = new MyClass1({
'Class1': [1, 2],
'Class2': ['test'],
'Class3': [(value) => value],
});
Usage 2: With own constructor
If constructor is passed in options object (second param) then it will
be called in place of constructors of all classes.
Example:
const MyClass2 = computeClass([Class1, Class2, Class3], {
ownConstructor(param1) {
this.name = param1;
}
});
const myClass2Instance = new MyClass2('Geoffrey');
*/
// actual function
var computeClass = (classes = [], { ownConstructor = null } = {}) => {
const noConstructor = (value) => value != 'constructor';
const ComputedClass = ownConstructor === null
? class ComputedClass {
constructor(args) {
classes.forEach((Current) => {
const params = args[Current.name];
if (params) {
Object.assign(this, new Current(...params));
} else {
Object.assign(this, new Current());
}
})
}
}
: class ComputedClass {
constructor(...args) {
if (typeof ownConstructor != 'function') {
throw Error('ownConstructor has to be a function!');
}
ownConstructor.call(this, ...args);
}
};
const prototype = classes.reduce(
(composedPrototype, currentClass) => {
const partialPrototype = Object.getOwnPropertyNames(currentClass.prototype)
.reduce(
(result, propName) =>
noConstructor(propName)
? Object.assign(
result,
{ [propName]: currentClass.prototype[propName] }
)
: result,
{}
);
return Object.assign(composedPrototype, partialPrototype);
},
{}
);
Object.entries(prototype).forEach(([prop, value]) => {
Object.defineProperty(ComputedClass.prototype, prop, { value });
});
return ComputedClass;
}
// demo part
var A = class A {
constructor(a) {
this.a = a;
}
sayA() { console.log('I am saying A'); }
}
var B = class B {
constructor(b) {
this.b = b;
}
sayB() { console.log('I am saying B'); }
}
console.log('class A', A);
console.log('class B', B);
var C = computeClass([A, B]);
console.log('Composed class');
console.log('var C = computeClass([A, B]);', C);
console.log('C.prototype', C.prototype);
var c = new C({ A: [2], B: [32] });
console.log('var c = new C({ A: [2], B: [32] })', c);
console.log('c instanceof A', c instanceof A);
console.log('c instanceof B', c instanceof B);
console.log('Now c will say:')
c.sayA();
c.sayB();
console.log('---');
var D = computeClass([A, B], {
ownConstructor(c) {
this.c = c;
}
});
console.log(`var D = computeClass([A, B], {
ownConstructor(c) {
this.c = c;
}
});`);
var d = new D(42);
console.log('var d = new D(42)', d);
console.log('Now d will say:')
d.sayA();
d.sayB();
console.log('---');
var E = computeClass();
console.log('var E = computeClass();', E);
var e = new E();
console.log('var e = new E()', e);
class DerivedBase extends cloneClass(Derived, Base) {}
//To add another superclass:
//class Der1Der2Base extends cloneClass(Derived2, DerivedBase)
let o = new DerivedBase()
可选项: 如果方法依赖于超类中的方法,我建议创建另一个 BaseClass并使用 class Class1 extends BaseClass {}。这样,Example的可重用部分就不会被重写。
class Class1 extends BaseClass {}
class Class2 extends BaseClass {}
class Example {
class1: Class1 // Sorry for the Typescript
class2: Class2
constructor (props) {
this.class1 = new Class1(props)
this.class2 = new Class2(props)
}
}
const example = new Example(props)
example.class1.someMethod()
class A{
constructor(name)
{
this.name=name;
}
getname=function(){return this.name};
}
B=(x)=>(class B extends (()=>x||Object)(){
constructor(surname,name)
{ super(name);
this.surname=surname;
}
getsurname(){return this.surname};
})
class C extends B(A){
constructor(name,surname)
{
super(surname,name);
}
getfullname(){return this.name+" "+this.surname};
};
let person=new C("Ed","Boon");
console.log(person.getname());//output Ed
console.log(person.getsurname());//output Boon
console.log(person.getfullname());//output Ed Boon
console.log(person);
console.log(person.__proto__.constructor); //person.__proto__ properties inherit from C class
console.log(person.__proto__.__proto__.constructor); //person.__proto__.__proto__ properties inherit from B class
console.log(person.__proto__.__proto__.__proto__.constructor); //person.__proto__.__proto__ .__proto__ properties inherit from A class
备注: person instanceof A true
但是 B 的人实例是假的,因为 B 看起来像函数。
只以类的形式出现,内部运行类中定义的代码。
我加了第二种方法
//extendsClass function using for create temporary extendedfirst argument baseClass ,other arguments is classes using for inherit
function extendsClass(...cls)
{
let str="";
for (let i=arguments.length-1;i>0;i--)
{
str+=(i==1?"(":"")+(arguments[i-1]+"").replace(RegExp(arguments[i-1].name+"({|\\s.*{)?"),arguments[i-1].name+" extends "+arguments[i].name+" {").replaceAll("//super","super")+(i==1?")":"");
}
return eval(str);
}
class A{
constructor(name)
{
this.name=name;
}
getname=function(){return this.name};
run(){console.log(`instance of A ${this instanceof A}`)};
}
class B {
constructor(surname,name)
{
//super(name);
this.surname=surname;
}
getsurname(){return this.surname};
run(){
//super.run();
console.log(`instance of B ${this instanceof B}`)};
}
class C {
constructor(name,surname)
{
//super(surname,name);
}
getfullname(){return this.name+" "+this.surname};
};
class D extends extendsClass(C,B,A) {
constructor(name,surname,address)
{
super(name,surname);
this.address=address;
}
}
//extendsClass function create temprory, class C extends from B,B extends from A, A class dont create temporary stay as global class.
var person=new (extendsClass(C,B,A))("Ed","Boon");
console.log(person.getname());//output Ed
console.log(person.getsurname());//output Boon
console.log(person.getfullname());//output Ed Boon
person.run();
var person2=new D("Cem","Firat","A place in the world");
console.log(person2.getname());//output Cem
console.log(person2.getsurname());//output Firat
console.log(person.getfullname());//output Cem Firat
person2.run();
const aggregator = (base, ...mixins) => {
const blackList = /^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/
const copyAttributes = (target, source) => {
Object.getOwnPropertyNames(source)
.concat(Object.getOwnPropertySymbols(source))
.forEach(prop => {
if (prop.match(blackList)) return
Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop))
})
}
return class extends base {
constructor(...args) {
super(...args)
for (const mixin of mixins) {
const target = this.constructor
copyAttributes(target.prototype, mixin.prototype)
copyAttributes(target, mixin)
}
}
}
}
class A {
foo() {
console.log(`from A -> inside instance of A: ${this instanceof A}`)
}
}
class B {
foo() {
if (super.foo) super.foo()
console.log(`from B -> inside instance of B: ${this instanceof B}`)
}
}
class C {
foo() {
if (super.foo) super.foo()
console.log(`from C -> inside instance of C: ${this instanceof C}`)
}
}
// D class, extends A and aggregates B and C
const CBA = aggregator(A, B, C)
class D extends CBA {
foo() {
if (super.foo) super.foo()
console.log(`from D -> inside instance of D: ${this instanceof D}`)
}
}
// E class, extends A and aggregates C
const CA = aggregator(A, C)
class E extends CA {
foo() {
if (super.foo) super.foo()
console.log(`from E -> inside instance of E: ${this instanceof E}`)
}
}
// F class, extends B
class F extends B {
foo() {
if (super.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 aggregator(C) {}
// H class, extends B
const H = aggregator(B)
// J class, extends Object and aggregates B
const J = aggregator(Object, B)
const d = new D()
const e = new E()
const f = new F()
const g = new G()
const h = new H()
const j = new J()
console.log(`Test D:
Class: D extends A, and aggregates B and C
Instance of D: ${d instanceof D}`)
d.foo()
console.log('-')
console.log(`Test E:
Class: E extends A, and aggregates C
Instance of E: ${e instanceof E}`)
e.foo()
console.log('-')
console.log(`Test F:
Class: F extends B
Instance of F: ${f instanceof F}`)
f.foo()
console.log('-')
console.log(`Test G:
Class: G wrapped to use C alone with "new" decorator
Instance of G: ${g instanceof G}`)
g.foo()
console.log('-')
console.log(`Test H:
Class: H extend B,
Instanceof B: ${h instanceof B}`)
h.foo()
console.log('-')
console.log(`Test J:
Class: H extend Object,
Instance of B: ${j instanceof B}, this one fails`)
h.foo()
// B mixin
const B = c => class extends c {
foo() {
if (super.foo) super.foo()
console.log(`[from B] is instance of B: ${this instanceof c}`)
}
}
// C mixin
const C = c => class extends c {
foo() {
if (super.foo) super.foo()
console.log(`[from C] is instance of C: ${this instanceof c}`)
}
}
现在我们扩展到这样的一个常规类:
// D class, extends A class and B and C mixins
class D extends C(B(A)) {
foo() {
if (super.foo) super.foo()
console.log(`[from D] is instance of D: ${this instanceof D}`)
}
}
下面是一个带有一些测试的工作代码片段:
class A {
foo() {
console.log(`[from A] is instance of A: ${this instanceof A}`)
}
}
// B mixin
const B = c => class extends c {
foo() {
if (super.foo) super.foo()
console.log(`[from B] is instance of B: ${this instanceof c}`)
}
}
// C mixin
const C = c => class extends c {
foo() {
if (super.foo) super.foo()
console.log(`[from C] is instance of C: ${this instanceof c}`)
}
}
// D class, extends A class and B and C mixins
class D extends C(B(A)) {
foo() {
if (super.foo) super.foo()
console.log(`[from D] is instance of D: ${this instanceof D}`)
}
}
// E class, extends A class and C mixin
class E extends C(A) {
foo() {
if (super.foo) super.foo()
console.log(`[from E] is instance of E: ${this instanceof E}`)
}
}
// F class, extends B mixin
class F extends B(Object) {
foo() {
if (super.foo) super.foo()
console.log(`[from F] is instance of F: ${this instanceof F}`)
}
}
// G class, wraps C mixin. Will use new decorator for instantiation, pretty format
class G extends C(Object) {}
const d = new D()
const e = new E()
const f = new F()
const g = new G()
const h = new (B(Object))
console.log(`Test D:
Class: D extends A, B and C
Instance of D: ${d instanceof D}`)
d.foo()
console.log('-')
console.log(`Test E:
Class: E extends A and C
Instance of E: ${e instanceof E}`)
e.foo()
console.log('-')
console.log(`Test F:
Class: F extends B
Instance of F: ${f instanceof F}`)
f.foo()
console.log('-')
console.log(`Test G:
Class: G wrapped to use C alone with "new" decorator
Instance of G: ${g instanceof G}`)
g.foo()
console.log('-')
const isInstanceOfB = i => {
try {
return i instanceof B
} catch (e) {
return false
}
}
console.log(`Test H:
Class: Anonymous class extends Object
Instance of B: ${isInstanceOfB(h)}
Instance of Object: ${h instanceof Object}`)
h.foo()
测试 D 清楚地表明 D 类正在扩展 A、 B 和 C。
Test D:
Class: D extends A, B and C
Instance of D: true
[from A] is instance of A: true
[from B] is instance of B: true
[from C] is instance of C: true
[from D] is instance of D: true
此外,我们可以欣赏在 测试 HH 不扩展 B,因为是一个混合,扩展
Test H:
Class: Anonymous class does has a prototype 'undefined'
Instance of B: false
Instance of Object: true
[from B] is instance of B: true
我们还可以为更好的语法添加一个构建器,如下所示:
const extender = base => new MixinBuilder(base)
// Our helper class that will make things look better
class MixinBuilder {
constructor(base) {
this.base = base;
}
with(...mixins) {
return mixins.reduce((c, mixin) => mixin(c), this.base);
}
}
const extender = base => new MixinBuilder(base)
class MixinBuilder {
constructor(base) {
this.base = base
}
with(...mixins) {
return mixins.reduce((c, mixin) => mixin(c), this.base)
}
}
class A {
foo() {
console.log(`[from A] is instance of A: ${this instanceof A}`)
}
}
// B mixin
const B = c => class extends c {
foo() {
if (super.foo) super.foo()
console.log(`[from B] is instance of B: ${this instanceof c}`)
}
}
// C mixin
const C = c => class extends c {
foo() {
if (super.foo) super.foo()
console.log(`[from C] is instance of C: ${this instanceof c}`)
}
}
// D class, extends A class and B and C mixins
const ABC = extender(A).with(B,C)
class D extends ABC {
foo() {
if (super.foo) super.foo()
console.log(`[from D] is instance of D: ${this instanceof D}`)
}
}
// E class, extends A class and C mixin
const AC = extender(A).with(C)
class E extends AC {
foo() {
if (super.foo) super.foo()
console.log(`[from E] is instance of E: ${this instanceof E}`)
}
}
// F class, extends Object and B mixin
class F extends extender(Object).with(B) {
foo() {
if (super.foo) super.foo()
console.log(`[from F] is instance of F: ${this instanceof F}`)
}
}
// G class, wraps C mixin. Will use new decorator for instantiation, pretty format
class G extends extender(Object).with(C) {}
const d = new D()
const e = new E()
const f = new F()
const g = new G()
const h = new (extender(Object).with(B))
console.log(`Test D:
Class: D extends A, B and C
Instance of D: ${d instanceof D}`)
d.foo()
console.log('-')
console.log(`Test E:
Class: E extends A and C
Instance of E: ${e instanceof E}`)
e.foo()
console.log('-')
console.log(`Test F:
Class: F extends B
Instance of F: ${f instanceof F}`)
f.foo()
console.log('-')
console.log(`Test G:
Class: G wrapped to use C alone with "new" decorator
Instance of G: ${g instanceof G}`)
g.foo()
console.log('-')
const isInstanceOfB = i => {
try {
return i instanceof B
} catch (e) {
return false
}
}
console.log(`Test H:
Class: Anonymous class extends Object
Instance of B: ${isInstanceOfB(h)}
Instance of Object: ${h instanceof Object}`)
h.foo()