Version 2.x
This file is written using a literate JavaScript. You can download
this cheatsheet to use as a local reference
or to run it locally.
If you prefer to see text as inline comments, just click on a sidebar
handle at the far right.
While dcl
works great in browsers using an AMD loader or
even simple <script>
, this tutorial is assumed to be run with
node.js .
For our examples we will need the main dcl module:
file.js
1
var dcl = require ( 'dcl' );
Declaring “classes”
See dcl() .
Simple “class” based on Object
file.js
1
2
3
4
5
6
7
8
9
10
11
var A = dcl ({
declaredClass : 'A' ,
constructor : function ( scale ) {
this . scale = scale ;
},
calculate : function ( x ) {
return this . scale * x ;
}
});
console . log ( new A ( 2 ). calculate ( 1 )); // 2
Single inheritance
file.js
1
2
var B = dcl ( A , {
declaredClass : 'B' ,
Constructor of A
will be called automatically.
It will deal with scale
– no need to touch it.
file.js
1
2
3
4
5
6
7
8
9
constructor : function ( scale , offset ) {
this . offset = offset ;
},
calculate : function ( x ) {
return this . scale * x + this . offset ;
}
});
console . log ( new B ( 2 , 1 ). calculate ( 1 )); // 3
Supercall
See dcl.superCall() .
Let’s repeat B
, but with a supercall to modularize calculate()
:
file.js
1
2
3
4
5
var B2 = dcl ( A , {
declaredClass : 'B2' ,
constructor : function ( scale , offset ) {
this . offset = offset ;
},
Don’t forget the double function pattern for supercalls and around advices
explained in Supercalls !
file.js
1
2
3
4
5
6
7
8
calculate : dcl . superCall ( function ( sup ) {
return function ( x ) {
return sup . call ( this , x ) + this . offset ;
};
})
});
console . log ( new B2 ( 2 , 1 ). calculate ( 1 )); // 3
Mixins
This time we’ll restructure our B
example.
file.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var Linear = dcl ({
declaredClass : 'Linear' ,
constructor : function ( arg ) {
this . scale = arg . scale || 1 ;
this . offset = arg . offset || 0 ;
}
});
var Calculator = dcl ( Linear , {
declaredClass : 'Calculator' ,
calculate : function ( x ) {
return this . scale * x + this . offset ;
}
});
var ReverseCalculator = dcl ( Linear , {
declaredClass : 'ReverseCalculator' ,
reverse : function ( x ) {
return ( x - this . offset ) / this . scale ;
}
});
var LinearCalculator = dcl ([
Calculator , ReverseCalculator
]);
var l = new LinearCalculator ({ scale : 2 , offset : 1 });
console . log ( l . calculate ( 1 )); // 3
console . log ( l . reverse ( 3 )); // 1
Introspection
See dcl.isInstanceOf() .
file.js
1
2
3
4
5
6
7
8
9
console . log ( l instanceof Linear ); // true
console . log ( l instanceof Calculator ); // true
console . log ( l instanceof ReverseCalculator ); // false
console . log ( l instanceof LinearCalculator ); // true
console . log ( dcl . isInstanceOf ( l , Linear )); // true
console . log ( dcl . isInstanceOf ( l , Calculator )); // true
console . log ( dcl . isInstanceOf ( l , ReverseCalculator )); // true
console . log ( dcl . isInstanceOf ( l , LinearCalculator )); // true
AOP
See dcl.advise() ,
dcl.before() , and
dcl.after() .
Let’s attach all possible advices:
file.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var C = dcl ({
declaredClass : 'C' ,
targetForBefore : function () {},
targetForAfter : function () {},
targetForAll : function () {}
});
var D = dcl ( C , {
declaredClass : 'D' ,
targetForBefore : dcl . before ( function ( x ) {
console . log ( x );
}),
targetForAfter : dcl . after ( function ( args , result ) {
console . log ( result );
}),
targetForAll : dcl . advise ({
before : function ( x ) {
console . log ( x );
},
Don’t forget the double function pattern for supercalls and around advices
explained in Supercalls !
file.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
around : function ( sup ) {
return function ( x ) {
return sup && sup . call ( this , x ) ? 1 : - 1 ;
};
},
after : function ( args , result ) {
console . log ( result );
}
})
});
var d = new D ;
d . targetForBefore ( 1 ); // 1
d . targetForAfter ( 1 ); // undefined
d . targetForAll ( 1 ); // 1, -1
Chaining
See dcl.chainBefore() and
dcl.chainAfter() .
file.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var E = dcl ({
declaredClass : 'E' ,
b : function ( x ) { console . log ( 'Eb' + x ); },
a : function ( x ) { console . log ( 'Ea' + x ); }
});
dcl . chainBefore ( E , 'b' );
dcl . chainAfter ( E , 'a' );
var F = dcl ({
declaredClass : 'F' ,
b : function ( x ) { console . log ( 'Fb' + x ); },
a : function ( x ) { console . log ( 'Fa' + x ); }
});
var G = dcl ([ E , F ], {
declaredClass : 'G' ,
b : function ( x ) { console . log ( 'Gb' + x ); },
a : function ( x ) { console . log ( 'Ga' + x ); }
});
var g = new G ;
g . b ( 1 ); // Gb1, Fb1, Eb1
g . a ( 2 ); // Ea2, Fa2, Ga2
Property descriptors
See dcl.prop() .
Define a read-only property:
file.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var H = dcl ({
declaredClass : 'H' ,
m1 : function () {},
m2 : dcl . prop ({
value : function () {},
writable : false
})
});
console . log (
Object . getOwnPropertyDescriptor (
H . prototype , 'm1' ). writable ); // true
console . log (
Object . getOwnPropertyDescriptor (
H . prototype , 'm2' ). writable ); // false
Detect property descriptors:
file.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var I = dcl ({
declaredClass : 'I' ,
m1 : function () {},
m2 : {
value : function () {},
writable : false
}
}, { detectProps : true });
console . log (
Object . getOwnPropertyDescriptor (
I . prototype , 'm1' ). writable ); // true
console . log (
Object . getOwnPropertyDescriptor (
I . prototype , 'm2' ). writable ); // false
Define all “class” properties with property descriptors:
file.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var J = dcl ( dcl . prop ({
declaredClass : {
value : 'J'
},
m1 : {
value : function () {},
writable : true
},
m2 : {
value : function () {},
writable : false
}
}));
console . log (
Object . getOwnPropertyDescriptor (
J . prototype , 'm1' ). writable ); // true
console . log (
Object . getOwnPropertyDescriptor (
J . prototype , 'm2' ). writable ); // false
Set defaults for “classic” properties:
file.js
1
2
3
4
5
6
7
8
var K = dcl ({
declaredClass : 'K' ,
m1 : function () {}
}, { writable : false });
console . log (
Object . getOwnPropertyDescriptor (
K . prototype , 'm1' ). writable ); // false
Advise properties:
file.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var L = dcl ( dcl . prop ({
declaredClass : {
value : 'L'
},
m : {
get : dcl . superCall ( function ( sup ) {
return function () {
return sup ? sup . call ( this ) : null ;
};
})
},
p : {
get : dcl . advise ({
before : function () { console . log ( 'getting p' ); },
around : function ( sup ) {
return function () {
return sup ? sup . apply ( this , arguments ) : null ;
}
}
})
}
}));
AOP for objects
For our examples we will need advise module:
file.js
1
var advise = require ( 'dcl/advise' );
See advise() ,
advise.before() ,
advise.around() , and
advise.after() .
Let’s attach all possible advices:
file.js
1
2
3
4
5
6
7
8
9
10
var m = {
targetForBefore : function () {},
targetForAround : function () {},
targetForAfter : function () {},
targetForAll : function () {}
};
advise . before ( m , 'targetForBefore' , function ( x ) {
console . log ( x );
});
Don’t forget the double function pattern for supercalls and around advices
explained in Supercalls !
file.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
advise . around ( m , 'targetForAround' , function ( sup ) {
return function ( x ) {
var result = sup && sup . call ( this , x ) ? 1 : - 1 ;
console . log ( result );
return result ;
};
});
advise . after ( m , 'targetForAfter' , function ( args , result ) {
console . log ( result );
});
advise ( m , 'targetForAll' , {
before : function ( x ) {
console . log ( x );
},
Don’t forget the double function pattern for supercalls and around advices
explained in Supercalls !
file.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
around : function ( sup ) {
return function ( x ) {
return sup && sup . call ( this , x ) ? 1 : - 1 ;
};
},
after : function ( args , result ) {
console . log ( result );
}
});
m . targetForBefore ( 1 ); // 1
m . targetForAround ( 1 ); // -1
m . targetForAfter ( 1 ); // undefined
m . targetForAll ( 1 ); // 1, -1
Debugging helpers
For our examples we will need debug module.
We don’t store its value, because it augments and returns dcl
.
file.js
See dcl.log() .
Inspect an object:
file.js
1
2
3
4
5
6
dcl . log ( m );
; // *** class does not have meta information compatible with dcl
; // targetForBefore: object-level advice (before 1, after 0)
; // targetForAround: object-level advice (before 0, after 0)
; // targetForAfter: object-level advice (before 0, after 1)
; // targetForAll: object-level advice (before 1, after 1)
Inspect a constructor:
file.js
1
2
3
4
dcl . log ( L );
; // *** class L depends on 0 classes
; // *** class L has 3 weavers:
; // constructor: after, m: super, p: super
Inspect an instance:
file.js
1
2
3
4
5
6
7
dcl . log ( g );
; // *** object of class G
; // *** class G depends on 2 classes: E, F
; // *** class G has 3 weavers:
; // constructor: after, b: before, a: after
; // b: class-level advice (before 0, after 0)
; // a: class-level advice (before 0, after 0)