1
0
Fork 0

Add "Class Caveats" manual section

This will grow.

* doc/classes.texi (Class Caveats): Added with `this.__inst' documentation
master
Mike Gerwitz 2016-07-15 23:35:36 -04:00
parent 30e7feefc9
commit ef5eade499
No known key found for this signature in database
GPG Key ID: F22BB8158EE30EAB
1 changed files with 137 additions and 0 deletions

View File

@ -251,12 +251,149 @@ variable @var{MyClass}. By convention, we use CamelCase, with the first
letter capital, for class names (and nothing else).
@menu
* Class Caveats:: Important things to note about using ease.js classes
* Anonymous vs. Named Classes::
* Constructors:: How to declare a constructor
* Temporary Classes:: Throwaway classes that only need to be used once
* Temporary Instances:: Throwaway instances that only need to be used once
@end menu
@node Class Caveats
@subsection Class Caveats
ease.js tries to make classes act as in traditional Classical@tie{}OOP
as much as possible,
but there are certain limitations,
especially when supporting ECMAScript@tie{}3.
These situations can cause some subtle bugs,
so it's important to note and understand them.
@subsubsection Returning Self
Returning @code{this} is a common practice for method
chaining.@footnote{
An interface that performs method chaining is less frequently
referred to as a ``fluent interface''.
This manual does not use that terminology.
Note also that method chaining implies that the class has state:
consider making your objects immutable instead,
which creates code that is easier to reason about.}
In the majority of cases, this works fine in ease.js
(see also @ref{Temporary Classes}):
@float Figure, f:method-chain
@verbatim
var Foo = Class( 'Foo',
{
'public beginning': function()
{
return this;
},
'public middle': function()
{
return this;
},
'public end': function()
{
// ...
}
} );
Foo().beginning().middle().end();
@end verbatim
@caption{Using @code{this} for method chaining}
@end float
Within the context of the method, @code{this} is a reference to
the@tie{}privacy visibility object for that instance
(@pxref{The Visibility Object}).
That is---it exposes all of the object's internal state.
When it is returned from a method call, ease.js recognizes this and
replaces it with a reference to the @emph{public} visibility
object---the object that the rest of the world interacts with.
But what if you produce @code{this} in some other context?
A callback, for example:
@float Figure, f:method-this-callback
@verbatim
var Foo = Class( 'Foo',
{
'private _foo': 'good',
'public beginning': function( c )
{
// XXX: `this' is the private visibility object
c( this );
},
'public end': function()
{
return this._foo;
}
} );
// result: 'bad'
Foo()
.beginning( function( self )
{
// has access to internal state
self._foo = 'bad';
} )
.end();
@end verbatim
@caption{Accidentally revealing internal state via callback}
@end float
In @ref{f:method-this-callback},
@code{beginning} applies the callback with a reference to what most
would believe to be the class instance
(which is a reasonable assumption,
considering that ease.js usually maintains that facade).
Since @code{this} is a reference to the private visibility object,
the callback has access to all its internal state,
and therefore the ability to set @code{_foo}.
To solve this problem,
use @code{this.__inst},
which is a reference to the @emph{public} visibility object
(the same one that ease.js would normally translate to on your
behalf):
@float Figure, f:method-callback-inst
@verbatim
var Foo = Class( 'Foo',
{
'private _foo': 'good',
'public beginning': function( c )
{
// OK
c( this.__inst );
},
'public end': function()
{
return this._foo;
}
} );
// result: 'good'
Foo()
.beginning( function( self )
{
// sets public property `_foo', since `self' is now the public
// visibility object
self._foo = 'bad';
} )
.end();
@end verbatim
@caption{Providing public visibility object using @code{this.__inst}}
@end float
@node Anonymous vs. Named Classes
@subsection Anonymous vs. Named Classes
We state that @ref{f:class-easejs,} declared an @dfn{anyonmous class}