16. Pseudo-classical
function SubClass() {
// constructor
}
SubClass.prototype = new SuperClass();
SubClass.prototype.someProperty = "booga!";
SubClass.prototype.someMethod = function () { ... };
...
SubClass.someStaticMethod = function () { ... };
...
17. Pseudo-classical
Y.extend = function (SubClass, SuperClass, proto, static)
function SubClass() {
// constructor
}
SubClass.prototype = new SuperClass();
SubClass.prototype.someProperty = "booga!";
SubClass.prototype.someMethod = function () { ... };
...
SubClass.someStaticMethod = function () { ... };
...
18. Pseudo-classical
Y.extend = function (SubClass, SuperClass, proto, static)
function SubClass() {
// constructor
}
Y.extend(SubClass, SuperClass);
SubClass.prototype.someProperty = "booga!";
SubClass.prototype.someMethod = function () { ... };
...
SubClass.someStaticMethod = function () { ... };
...
19. Pseudo-classical
Y.extend = function (SubClass, SuperClass, proto, static)
function SubClass() {
// constructor
}
Y.extend(SubClass, SuperClass, {
someProperty: "booga!",
someMethod : function () { ... },
...
});
SubClass.someStaticMethod = function () { ... };
...
20. Pseudo-classical
Y.extend = function (SubClass, SuperClass, proto, static)
function SubClass() {
// constructor
}
Y.extend(SubClass, SuperClass, {
someProperty: "booga!",
someMethod : function () { ... },
...
}, {
someStaticMethod: function () { ... },
...
});
21. Pseudo-classical
Y.extend = function (SubClass, SuperClass, proto, static)
Y.SubClass = Y.extend(
function() {
// constructor
},
/* extends */ SuperClass,
{ // Instance members
someProperty: "booga!",
someMethod : function () { ... }
},
{ // Static members
someStaticMethod: function () { ... }
});
22. Y.extend() PROs
• Creates a “clean” subclass relationship
• no YUI class requirement
• Preserves instanceof
• SubClass.superclass (not super, but close)
• Control superclass constructor execution
23. Y.extend() CONs
• No multiple inheritance
• Manual constructor chaining required
• Constructor chaining is awkward
• Constructor chaining may be costly
24. Y.extend() CONs
• No multiple inheritance
• Manual constructor chaining required
• Constructor chaining is awkward
• Constructor chaining may be costly
function SubClass() {
// Chain superclass constructor
SubClass.superclass.constructor.apply(this, arguments);
// My constructor stuff
...
}
25. Y.extend() CONs
• No multiple inheritance
• Manual constructor chaining required
• Constructor chaining is awkward
• Constructor chaining may be costly
function SubClass() {
// Chain superclass constructor
SubClass.superclass.constructor.apply(this, arguments);
A RD
W KW
// My constructor stuff A
...
}
26. Y.extend() CONs
• No multiple inheritance
• Manual constructor chaining required
• Constructor chaining is awkward
• Constructor chaining may be costly
function SubClass() {
// Chain superclass constructor
SubClass.superclass.constructor.apply(this, arguments);
A RD
W KW COST
// My constructor stuff A LY?
...
}
27. To sum up
• Good for basic class inheritance
• If you can extend Y.Base, there are more options
32. Prototypal
// Old and busted
SubClass.prototype = new SuperClass();
SuperClass SubClass
f(n) f(n)
Constructor Constructor
{} {}
Prototype Prototype
33. Prototypal
// Old and busted
SubClass.prototype = new SuperClass();
SuperClass SubClass
f(n) f(n)
Constructor Constructor
{} {}
Prototype Prototype
34. Prototypal
// Old and busted
SubClass.prototype = new SuperClass();
BA
SuperClass D SubClass
f(n) f(n)
Constructor Constructor
{} {}
Prototype Prototype
35. Prototypal
// Old and busted
SubClass.prototype = new SuperClass();
SuperClass SubClass
f(n) f(n)
Constructor Constructor
{} {}
Prototype Prototype
40. Prototypal
Y.Object = (function () {
function F() {}
return function (obj) {
F.prototype = obj;
return new F();
};
})();
(anon)
f(n)
EMPTY
Constructor
{} {}
Any Object Prototype
41. Prototypal
Y.Object = (function () {
function F() {}
return function (obj) {
F.prototype = obj;
return new F();
};
})();
(anon)
f(n)
EMPTY
Constructor
{} {}
Any Object Prototype
42. Prototypal
Y.Object = (function () {
function F() {}
return function (obj) {
F.prototype = obj;
return new F();
};
})();
(anon)
f(n)
EMPTY
Constructor
{} {} f(n)
(anon)
EMPTY
Constructor
Any Object Prototype New Object
{}
Prototype
43. Factory constructor
function Set() {
var that = (this instanceof Set) ?
this :
Y.Object(Set.prototype);
// use that instead of this
[].push.apply(that._items, arguments);
return that;
}
44. Factory constructor
function Set() {
var that = (this instanceof Set) ?
this :
Y.Object(Set.prototype);
// use that instead of this
[].push.apply(that._items, arguments);
return that;
}
var set = new Set(‘a’,’b’);
45. Factory constructor
function Set() {
var that = (this instanceof Set) ?
this :
Y.Object(Set.prototype);
// use that instead of this
[].push.apply(that._items, arguments);
return that;
}
var set = new Set(‘a’,’b’);
set instanceof Set; // true
46. Factory constructor
function Set() {
var that = (this instanceof Set) ?
this :
Y.Object(Set.prototype);
// use that instead of this
[].push.apply(that._items, arguments);
return that;
}
var set = Set(‘a’,’b’); // <-- OOPS! I forgot 'new'!
47. Factory constructor
function Set() {
var that = (this instanceof Set) ?
this :
Y.Object(Set.prototype);
// use that instead of this
[].push.apply(that._items, arguments);
return that;
}
var set = Set(‘a’,’b’);
set instanceof Set; // true
48. Y.Object() PROs
• Avoids copying a lot of properties
• Can be used to make factory constructors
• Can be used to store original values for revert
• Any object can be the prototype
• Avoids class explosion
49. Y.Object() CONs
• No multiple inheritance
• Factory constructor can promote sloppiness
• Can’t use hasOwnProperty in for/in loops
50. To sum up
• Useful for some internal logic patterns
• Not a good fit for most web app problems
• Common use suggests need for a constructor
51. To sum up
• Useful for some internal logic patterns
• Not a good fit for most web app problems
• Common use suggests need for a constructor
var account1 = Y.Object(accountProto);
account1.id = 1234;
account1.holder = 'John Q. Consumer';
var account2 = Y.Object(accountProto);
account2.id = 1235;
account2.holder = 'Jane B. Investor';
52. To sum up
• Useful for some internal logic patterns
• Not a good fit for most web app problems
• Common use suggests need for a constructor
var account1 = Y.Object(accountProto);
account1.id = 1234;
account1.holder = 'John Q. Consumer';
var account2 = Y.Object(accountProto);
account2.id = 1235;
account2.holder = 'Jane B. Investor';
53. To sum up
• Useful for some internal logic patterns
• Not a good fit for most web app problems
• Common use suggests need for a constructor
var account1 = Y.Object(accountProto); CO
account1.id = 1234; NS
account1.holder = 'John Q. Consumer'; TR
UC
var account2 = Y.Object(accountProto); TO
account2.id = 1235; R
account2.holder = 'Jane B. Investor';
54. To sum up
• Useful for some internal logic patterns
• Not a good fit for most web app problems
• Common use suggests need for a constructor
function Account(id, holder) {
this.id = id;
this.holder = holder;
}
var account1 = new Account(1234, 'John Q. Consumer');
var account2 = new Account(1235, 'Jane B. Invester');
55. Class structure strategies
✓ Pseudo-classical
Native
✓ Prototypal
• Augmentation
• Plugins
Artificial
• Class extensions
• MVC
56. Class structure strategies
✓ Pseudo-classical
Native
✓ Prototypal
• Augmentation
• Plugins
Artificial
• Class extensions
• MVC
65. Augmentation
Y.augment(Y.ModelList, Y.ArrayList);
var list = new Y.ModelList({ ... });
list.each(function (item) { ... });
ModelList
Constructor
ArrayList list
Prototype Prototype
Constructor
create create
init Prototype
ModelList
Constructor
Prototype
create
init
init
each
item
each each each
item item item
66. Augmentation
Y.augment(Y.ModelList, Y.ArrayList);
var list = new Y.ModelList({ ... });
list.each(function (item) { ... });
ModelList
Constructor
ArrayList list
Prototype
Constructor
create
init Prototype
ModelList
Constructor
Prototype
create
init
each
item
each each
item item Prototype
67. Augmentation
Y.augment(Y.ModelList, Y.ArrayList);
var list = new Y.ModelList({ ... });
list.each(function (item) { ... });
ModelList
Constructor
ArrayList list
Prototype
Constructor
create
init Prototype
each each
item item Prototype
68. Augmentation
Y.augment(Y.ModelList, Y.ArrayList);
var list = new Y.ModelList({ ... });
each
list.each(function (item) { ... });
ModelList
Constructor
ArrayList list
Prototype
Constructor
create
init Prototype
each each
item item Prototype
69. Augmentation
Y.augment(Y.ModelList, Y.ArrayList);
var list = new Y.ModelList({ ... });
each
list.each(function (item) { ... });
ModelList
Constructor
ArrayList list
Prototype
Constructor
create
init Prototype
each each
item item Prototype
70. Augmentation
Y.augment(Y.ModelList, Y.ArrayList);
var list = new Y.ModelList({ ... });
each
list.each(function (item) { ... });
ModelList
Constructor
ArrayList list
Prototype each
create
Constructor 1. Copy
item
init Prototype
each each
item item Prototype
71. Augmentation
Y.augment(Y.ModelList, Y.ArrayList);
var list = new Y.ModelList({ ... });
each
list.each(function (item) { ... });
ModelList
Constructor
ArrayList list
Prototype each
create
Constructor 1. Copy
item
init Prototype
2. Construct
each each
item item Prototype
72. Augmentation
Y.augment(Y.ModelList, Y.ArrayList);
var list = new Y.ModelList({ ... });
list.each(function (item) { ... });
ModelList
Constructor
ArrayList list
Prototype each
create
Constructor 1. Copy
item
init Prototype
2. Construct
each each 3. Execute
item item Prototype
74. Y.augment() PROs
• Defers constructor overhead
• Can augment with multiple classes
• Supports class or instance augmentation
• No YUI class requirement
75. Y.augment() CONs
• First augmented method call is costly
• instanceof is false for augmenting classes
• Consumes more memory
• Limited control of constructor invocation
76. To sum up
• Use it to simulate lazy multiple inheritance
• Y.Base-based classes should use class extensions
• Beware the diamond problem
• Weigh the importance of constructor deferral
77. To sum up
• Use it to simulate lazy multiple inheritance
• Y.Base-based classes should use class extensions
• Beware the diamond problem
• Weigh the importance of constructor deferral
Y.SubClass = Y.extend(
function () {
Y.SuperClass.apply(this, arguments);
Y.EventTarget.apply(this, { /* config */ });
},
Y.SuperClass, // <-- one "official" extention class
Y.mix({ /* prototype */ }, Y.EventTarget.prototype),
{ /* static */ });
79. Plugins
var overlay = new Y.Overlay({ ... });
overlay.plug(Y.Plugin.Drag);
overlay.dd.set('lock', true);
overlay.unplug('dd');
80. Plugins
var overlay = new Y.Overlay({ ... });
overlay.plug(Y.Plugin.Drag);
overlay.dd.set('lock', true);
overlay.unplug('dd');
Overlay
Constructor
Attributes
x
y
81. Plugins
var overlay = new Y.Overlay({ ... });
overlay.plug(Y.Plugin.Drag);
overlay.dd.set('lock', true);
overlay.unplug('dd');
Overlay
Constructor
Attributes
x
y
82. Plugins
var overlay = new Y.Overlay({ ... });
overlay.plug(Y.Plugin.Drag);
overlay.dd.set('lock', true);
overlay.unplug('dd');
Overlay
overlay
Constructor
Attributes Attributes
x x
y y
83. Plugins
var overlay = new Y.Overlay({ ... });
overlay.plug(Y.Plugin.Drag);
overlay.dd.set('lock', true);
overlay.unplug('dd');
Overlay
Constructor
overlay Plugin.Drag
Constructor
ATTRS Attributes
x x ATTRS
y y lock
84. Plugins
var overlay = new Y.Overlay({ ... });
overlay.plug(Y.Plugin.Drag);
overlay.dd.set('lock', true);
overlay.unplug('dd');
Overlay
Constructor
overlay Plugin.Drag
Constructor
ATTRS Attributes
x x ATTRS
y y lock
85. Plugins
var overlay = new Y.Overlay({ ... });
overlay.plug(Y.Plugin.Drag);
overlay.dd.set('lock', true);
overlay.unplug('dd');
Overlay
Constructor
overlay overlay.dd Plugin.Drag
Attributes
Constructor
Attributes lock
ATTRS
x x ATTRS
y y lock
86. Plugins
var overlay = new Y.Overlay({ ... });
overlay.plug(Y.Plugin.Drag);
overlay.dd.set('lock', true);
overlay.unplug('dd');
Overlay
Constructor
overlay overlay.dd Plugin.Drag
dd Attributes
Constructor
Attributes lock
ATTRS
x x ATTRS
y y lock
87. Plugins
var overlay = new Y.Overlay({ ... });
overlay.plug(Y.Plugin.Drag);
overlay.dd.set('lock', true);
overlay.unplug('dd');
Overlay
Constructor
overlay overlay.dd Plugin.Drag
dd Attributes
Constructor
Attributes lock
ATTRS
x x ATTRS
y y lock
88. Plugins
var overlay = new Y.Overlay({ ... });
overlay.plug(Y.Plugin.Drag);
overlay.dd.set('lock', true);
overlay.unplug('dd');
Overlay
Constructor
overlay overlay.dd Plugin.Drag
dd Attributes
Constructor
Attributes lock
ATTRS
x x ATTRS
y y lock
89. Plugins
var overlay = new Y.Overlay({ ... });
overlay.plug(Y.Plugin.Drag);
overlay.dd.set('lock', true);
overlay.unplug('dd');
Overlay
Constructor
overlay Plugin.Drag
Constructor
ATTRS Attributes
x x ATTRS
y y lock
90. The requirements
Host class
• Y.Plugin.Host (free in Y.Base, or add with Y.augment)
Plugin class
• Static NS property
91. The requirements
Host class
• Y.Plugin.Host (free in Y.Base, or add with Y.augment)
Plugin class
• Static NS property
That’s it
95. The contract
SHOULD MAY
✓ Expect an object ✓ Provide namespaced API
constructor argument ✓ Modify core behavior via
with ‘host’ property events or AOP
96. The contract
SHOULD MAY
✓ Expect an object ✓ Provide namespaced API
constructor argument ✓ Modify core behavior via
with ‘host’ property events or AOP
MUST
✓ Remove all traces
when unplugged
97. The contract
SHOULD MAY
✓ Expect an object ✓ Provide namespaced API
constructor argument ✓ Modify core behavior via
with ‘host’ property events or AOP
MUST MUST NOT
✓ Remove all traces ✓ Modify host directly
when unplugged other than add the
namespace
99. Plugin PROs
• Avoids method/property naming collisions
• Preserves host behavior when unplug()ed
• Plug classes or instances
• Generic plugins can work for multiple host types
• Works on Nodes
100. Plugin CONs
• Fragments API
• Plugin contract to restore host can add code weight
• Difficult to manage competing plugins
• plug() could use a little sugar
101. to sum up
• Flexible
• Better in smaller numbers
• Class Plugins vs Augmentation?
• Free with Y.Base-based classes and Y.Nodes
(have I mentioned that you should use Y.Base?)
110. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor Constructor
ATTRS ATTRS
Prototype Prototype
ATTRS
Prototype
111. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor Constructor
Constructor
ATTRS ATTRS
Constructor
Prototype Prototype
ATTRS
Prototype
112. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor
Constructor Constructor
Constructor
ATTRS ATTRS
Constructor
Prototype Prototype
ATTRS
Prototype
113. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor Constructor
ATTRS ATTRS ATTRS
direction type
type
Prototype
Prototype
Prototype
114. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor Constructor
ATTRS ATTRS ATTRS
direction styles type
type
Prototype
Prototype
Prototype
115. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor Constructor
ATTRS ATTRS ATTRS
direction styles type
type direction
Prototype
type
Prototype
Prototype
116. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor Constructor
ATTRS ATTRS ATTRS
direction styles type
type direction
Prototype
type
Prototype
Prototype
117. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor Constructor
ATTRS ATTRS ATTRS
direction styles type
type direction
Prototype
type
Prototype
Prototype
118. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor Constructor
ATTRS ATTRS ATTRS
Prototype Prototype Prototype
draw drawLines
119. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor Constructor
ATTRS ATTRS ATTRS
Prototype Prototype Prototype
draw drawLines
120. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor Constructor
ATTRS ATTRS ATTRS
Prototype Prototype Prototype
Prototype
draw Prototype
draw drawLines
draw
drawLines
drawSeries
121. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
Cartesian LineSeries Lines
Constructor Constructor Constructor
ATTRS
ATTRS ATTRS
Prototype Prototype Prototype
draw
initializer initializer drawLines
initializer
initializer
initializer
initializer
122. Class extensions
Y.LineSeries = Y.Base.create('lineSeries', Y.CartesianSeries,
[ Y.Lines ], { ... });
var series = new Y.LineSeries({ ... });
1. Constructors are called
2. Attributes are set
3. initializers are called
123. Two types of extensions
1. Class decoration
Add feature APIs and Attributes
2. Core functionality
Satisfy abstract class implementation
126. Extensions PROs
• Promotes code reuse across environments
• Feature APIs are added to the prototype
• Can be used to mimic MVC breakdown
127. Extensions CONs
• Requires Y.Base
• Initialization overhead
• Class definition only (no instance feature additions)
• Does not work on Nodes
• Increased potential for accidental name collisions
128. Extension vs Plugin
• Extensions can be used to contribute core behavior
• Extensions modify the class prototype, plugins are
always namespaced
• Feature extension constructors are always
executed, plugin constructors on plug()
• Feature APIs/attributes on the prototype vs class
plugins in namespace is a stylistic choice