[#5] Reworked member keywords and member visibility section in manual
parent
fae30c877a
commit
6c379968bc
356
doc/classes.texi
356
doc/classes.texi
|
@ -71,8 +71,6 @@ ease.js, until such a point where prototypes are no longer adequate.
|
||||||
@menu
|
@menu
|
||||||
* Defining Classes:: Learn how to define a class with ease.js
|
* Defining Classes:: Learn how to define a class with ease.js
|
||||||
* Inheritance:: Extending classes from another
|
* Inheritance:: Extending classes from another
|
||||||
* Member Visibility:: Encapsulation is a core concept of Object-Oriented
|
|
||||||
programming
|
|
||||||
* Static Members:: Members whose use do not require instantiation
|
* Static Members:: Members whose use do not require instantiation
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
|
@ -149,50 +147,31 @@ determines what type of member will be declared.
|
||||||
@var{name} must be unique across all members of @var{dfn}.
|
@var{name} must be unique across all members of @var{dfn}.
|
||||||
@end enumerate
|
@end enumerate
|
||||||
|
|
||||||
@anchor{mkeywords}
|
@subsection Member Validations
|
||||||
@subsection Member Keywords
|
For any member @var{name}:
|
||||||
@float Table, t:keywords
|
@itemize
|
||||||
@multitable @columnfractions .10 .9
|
@item
|
||||||
@headitem Keyword @tab Description
|
@var{keywords} of member @var{name} may contain only one access modifier
|
||||||
@item @code{public}
|
(@pxref{Access Modifiers}).
|
||||||
@tab Access modifier. Places member @var{name} in public interface (accessible
|
@item
|
||||||
outside of @var{C} or instance of @var{C}; accessible by subtypes). Implied if
|
See @ref{Member Keywords,,Member Keywords} for @var{keywords} restrictions.
|
||||||
no other access modifier is provided. May not be used in conjunction with other
|
@end itemize
|
||||||
access modifiers. @xref{Member Visibility}.
|
|
||||||
@item @code{protected}
|
|
||||||
@tab Access modifier. Places member @var{name} in protected interface
|
|
||||||
(accessible only within @var{C} or instance of @var{C}; accessible by subtypes).
|
|
||||||
May not be used in conjunction with other access modifiers. @xref{Member
|
|
||||||
Visibility}.
|
|
||||||
@item @code{private}
|
|
||||||
@tab Access modifier. Places member @var{name} in private interface (accessible
|
|
||||||
only within @var{C} or instance of @var{C}; not accessible by subtypes). May not
|
|
||||||
be used in conjunction with other access modifiers. @xref{Member Visibility}.
|
|
||||||
@item @code{static}
|
|
||||||
@tab Binds member @var{name} to class @var{C} rather than instance of @var{C}.
|
|
||||||
Member data shared with each instance of type @var{C}. @xref{Static Members}.
|
|
||||||
@item @code{abstract}
|
|
||||||
@tab Declares member @var{name} and defers definition to subtype. @var{value}
|
|
||||||
is interpreted as an argument list and must be of type @code{array}. May only be
|
|
||||||
used with methods.
|
|
||||||
@item @code{const}
|
|
||||||
@tab Defines an immutable property @var{name}. May not be used with methods or
|
|
||||||
getters/setters. @xref{Constants}.
|
|
||||||
@item @code{virtual}
|
|
||||||
@tab Declares that method @var{name} may be overridden by subtypes. Methods
|
|
||||||
without this keyword may not be overridden. May only be used with methods.
|
|
||||||
@xref{Inheritance}.
|
|
||||||
@item @code{override}
|
|
||||||
@tab Overrides method @var{name} of supertype of @var{C} with @var{value}. May
|
|
||||||
only override virtual methods. May only be used with methods.
|
|
||||||
@xref{Inheritance}.
|
|
||||||
@end multitable
|
|
||||||
@caption{Supported keywords}
|
|
||||||
@end float
|
|
||||||
|
|
||||||
Only the keywords in @ref{t:keywords} are supported as valid tokens within
|
|
||||||
@var{keywords}.
|
|
||||||
|
|
||||||
|
For any member @var{name} declared as a @emph{method}, the following must hold
|
||||||
|
true:
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
@var{keywords} of member @var{name} may not contain
|
||||||
|
@ref{Member Keywords,,@code{override}} without a super method of the same
|
||||||
|
@var{name} (@pxref{Inheritance}).
|
||||||
|
@item
|
||||||
|
@var{keywords} of member @var{name} may contain both
|
||||||
|
@ref{Member Keywords,,@code{static}} and @ref{Member Keywords,,@code{virtual}}
|
||||||
|
keywords (@pxref{Static Members} and @ref{Inheritance}).
|
||||||
|
@item
|
||||||
|
@var{keywords} of member @var{name} may not contain the
|
||||||
|
@ref{Member Keywords,,@code{const}} keyword.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
@subsection Discussion
|
@subsection Discussion
|
||||||
In @ref{f:class-js}, we saw how one would conventionally declare a class-like
|
In @ref{f:class-js}, we saw how one would conventionally declare a class-like
|
||||||
|
@ -259,9 +238,9 @@ capital, for class names (and nothing else).
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* Anonymous vs. Named Classes::
|
* Anonymous vs. Named Classes::
|
||||||
* Constructors:: How to declare a constructor
|
* Constructors:: How to declare a constructor
|
||||||
* Temporary Classes:: Throwaway classes that only need to be used once
|
* Temporary Classes:: Throwaway classes that only need to be used once
|
||||||
* Temporary Instances:: Throwaway instances that only need to be used once
|
* Temporary Instances:: Throwaway instances that only need to be used once
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Anonymous vs. Named Classes
|
@node Anonymous vs. Named Classes
|
||||||
|
@ -519,18 +498,19 @@ For any positive condition @var{o\_n} where member @var{n} is defined as a
|
||||||
One of the following conditions must always be true:
|
One of the following conditions must always be true:
|
||||||
@itemize
|
@itemize
|
||||||
@item
|
@item
|
||||||
@var{dfn\_n\^C} is declared with the @ref{mkeywords,,@code{virtual}} keyword
|
@var{dfn\_n\^C} is declared with the @ref{Member Keywords,,@code{virtual}}
|
||||||
and @var{dfn\_n\^C'} is declared with the @ref{mkeywords,,@code{override}}
|
keyword and @var{dfn\_n\^C'} is declared with the
|
||||||
keyword.
|
@ref{Member Keywords,,@code{override}} keyword.
|
||||||
@itemize
|
@itemize
|
||||||
@item
|
@item
|
||||||
Note that @var{dfn\_n\^C'} will not become @ref{mkeywords,,@code{virtual}}
|
Note that @var{dfn\_n\^C'} will not become @ref{Member
|
||||||
by default (unlike languages such as C++); they must be explicitly declared
|
Keywords,,@code{virtual}} by default (unlike languages such as C++); they
|
||||||
as such.
|
must be explicitly declared as such.
|
||||||
@end itemize
|
@end itemize
|
||||||
@item
|
@item
|
||||||
@var{dfn\_n\^C} is declared with the @ref{mkeywords,,@code{abstract}} keyword and
|
@var{dfn\_n\^C} is declared with the @ref{Member Keywords,,@code{abstract}}
|
||||||
@var{dfn\_n\^C'} omits the @ref{mkeywords,,@code{override}} keywords.
|
keyword and @var{dfn\_n\^C'} omits the @ref{Member Keywords,,@code{override}}
|
||||||
|
keywords.
|
||||||
@end itemize
|
@end itemize
|
||||||
@item
|
@item
|
||||||
The argument count of method @var{dfn\_n\^C'} must be >= the argument count of
|
The argument count of method @var{dfn\_n\^C'} must be >= the argument count of
|
||||||
|
@ -547,8 +527,8 @@ A method is said to be @dfn{concrete} when it provides a definition and
|
||||||
Any method @var{n} such that @var{dfn\_n\^C} is declared @code{abstract} may
|
Any method @var{n} such that @var{dfn\_n\^C} is declared @code{abstract} may
|
||||||
be overridden by a concrete or abstract method @var{dfn\_n\^C'}.
|
be overridden by a concrete or abstract method @var{dfn\_n\^C'}.
|
||||||
@item
|
@item
|
||||||
A method @var{n} may @emph{not} be declared @ref{mkeywords,,@code{abstract}}
|
A method @var{n} may @emph{not} be declared @ref{Member
|
||||||
if @var{dfn\_n\^C} is concrete.
|
Keywords,,@code{abstract}} if @var{dfn\_n\^C} is concrete.
|
||||||
@end itemize
|
@end itemize
|
||||||
@item
|
@item
|
||||||
Member @var{dfn\_n\^C} must be a method.
|
Member @var{dfn\_n\^C} must be a method.
|
||||||
|
@ -585,7 +565,7 @@ of the two. We describe inheritance as an ``is a'' relationship. That is:
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
Subtypes @dfn{inherit} all public and protected members of their supertypes
|
Subtypes @dfn{inherit} all public and protected members of their supertypes
|
||||||
(@pxref{Member Visibility}). This means that, in the case of our above example,
|
(@pxref{Access Modifiers}). This means that, in the case of our above example,
|
||||||
the @code{walk()} and @code{bark()} methods would be available to our subtypes.
|
the @code{walk()} and @code{bark()} methods would be available to our subtypes.
|
||||||
If the subtype also defines a method of the same name, as was done above, it
|
If the subtype also defines a method of the same name, as was done above, it
|
||||||
will @dfn{override} the parent functionality. For now, we will limit our
|
will @dfn{override} the parent functionality. For now, we will limit our
|
||||||
|
@ -659,6 +639,7 @@ conciseness.
|
||||||
* Overriding Methods:: Overriding inherited methods
|
* Overriding Methods:: Overriding inherited methods
|
||||||
* Type Checks and Polymorphism:: Substituting similar classes for
|
* Type Checks and Polymorphism:: Substituting similar classes for
|
||||||
one-another
|
one-another
|
||||||
|
* Visibility Escalation:: Increasing visibility of inherited members
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Understanding Member Inheritance
|
@node Understanding Member Inheritance
|
||||||
|
@ -677,15 +658,15 @@ public members. We will be focusing on public members in this chapter.
|
||||||
@item Protected API
|
@item Protected API
|
||||||
Protected members make up a protected API, which is an API available to
|
Protected members make up a protected API, which is an API available to
|
||||||
subclasses but @emph{not} the outside world. This is discussed more in the
|
subclasses but @emph{not} the outside world. This is discussed more in the
|
||||||
Member Visibility section (@pxref{Member Visibility}), so we're going to leave
|
Access Modifiers section (@pxref{Access Modifiers}), so we're going to leave
|
||||||
this untouched for now.
|
this untouched for now.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
When a subtype inherits a member from its parent, it acts almost as if that
|
When a subtype inherits a member from its parent, it acts almost as if that
|
||||||
member was defined in the class itself@footnote{This statement is not to imply
|
member was defined in the class itself@footnote{This statement is not to imply
|
||||||
that inheritance is a case of copy-and-paste. There are slight variations, which
|
that inheritance is a case of copy-and-paste. There are slight variations, which
|
||||||
are discussed in more detail in the Member Visibility section (@pxref{Member
|
are discussed in more detail in the Access Modifiers section (@pxref{Access
|
||||||
Visibility}).}. This means that the subtype can use the inherited members as if
|
Modifiers}).}. This means that the subtype can use the inherited members as if
|
||||||
they were its own (keep in mind that members also include properties). This
|
they were its own (keep in mind that members also include properties). This
|
||||||
means that we @emph{do not} have to redefine the members in order to use them
|
means that we @emph{do not} have to redefine the members in order to use them
|
||||||
ourselves.
|
ourselves.
|
||||||
|
@ -884,255 +865,6 @@ Currently, it is necessary to perform this type check yourself. In future
|
||||||
versions, ease.js will allow for argument type hinting/strict typing, which will
|
versions, ease.js will allow for argument type hinting/strict typing, which will
|
||||||
automate this check for you.
|
automate this check for you.
|
||||||
|
|
||||||
|
|
||||||
@node Member Visibility
|
|
||||||
@section Member Visibility
|
|
||||||
One of the major hurdles ease.js aimed to address (indeed, one of the core
|
|
||||||
reasons for its creation) was that of encapsulation. JavaScript's prototype
|
|
||||||
model provides limited means of encapsulating data. Since functions limit scope,
|
|
||||||
they may be used to mimic private members. These are often referred to as
|
|
||||||
@dfn{privileged members}. However, declaring classes in this manner can be
|
|
||||||
messy. ease.js aims to provide an elegant implementation that is both a pleasure
|
|
||||||
to work with and able to support protected members.
|
|
||||||
|
|
||||||
The term @dfn{visibility} refers to how a class member may be accessed. There
|
|
||||||
are three levels of visibility implemented by ease.js, which are listed here
|
|
||||||
from most visible to least:
|
|
||||||
|
|
||||||
@table @dfn
|
|
||||||
@item public
|
|
||||||
Accessible outside of the instance (e.g. @samp{foo.publicProp}). Inherited by
|
|
||||||
subtypes.
|
|
||||||
|
|
||||||
@item protected
|
|
||||||
Not accessible outside of the instance (only accessible by
|
|
||||||
@samp{this.protectedProp}). Inherited by subtypes.
|
|
||||||
|
|
||||||
@item private
|
|
||||||
Not accessible outside of the instance. Not inherited by subtypes.
|
|
||||||
@end table
|
|
||||||
|
|
||||||
By default, all members are public. This means that the members can be accessed
|
|
||||||
and modified from within an instance and from outside. Subtypes (classes that
|
|
||||||
inherit from it) will inherit public members. Public methods expose an API by
|
|
||||||
which users may use your class. Public properties, however, should be less
|
|
||||||
common in practice for a very important reason, which is explored throughout the
|
|
||||||
rest of this section.
|
|
||||||
|
|
||||||
@dfn{Encapsulation} is the act of hiding information within a class or instance.
|
|
||||||
Classes should be thought of black boxes. We want them to do their job, but we
|
|
||||||
do not care @emph{how} they do their job. Encapsulation takes the complexity out
|
|
||||||
of a situation and allows the developer to focus on accomplishing the task using
|
|
||||||
familiar concepts. For example, consider a class named @var{Dog} which has a
|
|
||||||
method @code{walk()}. To walk a dog, we simply call @code{Dog().walk()}. The
|
|
||||||
@code{walk()} method could be doing anything. By preventing the details of the
|
|
||||||
method from being exposed, we present the developer with a very simple
|
|
||||||
interface. Rather than the developer having to be concerned with moving each of
|
|
||||||
the dog's legs, all they have to do is understand that the dog is being walked.
|
|
||||||
|
|
||||||
Let's consider our @var{Dog} class in more detail:
|
|
||||||
|
|
||||||
@float Figure, f:encapsulation
|
|
||||||
@verbatim
|
|
||||||
Class( 'Dog',
|
|
||||||
{
|
|
||||||
'private _legs': {},
|
|
||||||
|
|
||||||
'private _body': {},
|
|
||||||
|
|
||||||
// ...
|
|
||||||
|
|
||||||
|
|
||||||
'public walk': function()
|
|
||||||
{
|
|
||||||
this.stand();
|
|
||||||
this._moveFrontLeg( 0 );
|
|
||||||
this._moveBackLeg( 1 );
|
|
||||||
this._moveFrontLeg( 1 );
|
|
||||||
this._moveBackLeg( 0 );
|
|
||||||
},
|
|
||||||
|
|
||||||
'protected stand': function()
|
|
||||||
{
|
|
||||||
if ( this.isSitting() )
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
'public rollOver': function()
|
|
||||||
{
|
|
||||||
this._body.roll();
|
|
||||||
},
|
|
||||||
|
|
||||||
'private _moveFrontLeg': function( leg )
|
|
||||||
{
|
|
||||||
this._legs.front[ leg ].move();
|
|
||||||
},
|
|
||||||
|
|
||||||
'private _moveBackLeg': function( leg )
|
|
||||||
{
|
|
||||||
this._legs.back[ leg ].move();
|
|
||||||
},
|
|
||||||
|
|
||||||
// ...
|
|
||||||
} );
|
|
||||||
@end verbatim
|
|
||||||
@caption{Encapsulating behavior of a class}
|
|
||||||
@end float
|
|
||||||
|
|
||||||
As you can see above, the act of making the dog move forward is a bit more
|
|
||||||
complicated than the developer may have originally expected. The dog has four
|
|
||||||
separate legs that need to be moved individually. The dog must also first stand
|
|
||||||
before it can be walked, but it can only stand if it's sitting. Detailed tasks
|
|
||||||
such as these occur all the time in classes, but they are hidden from the
|
|
||||||
developer using the public API. Why should the developer be concerned with all
|
|
||||||
of the legs?
|
|
||||||
|
|
||||||
As a general rule of thumb, you should use the @emph{lowest} level of visibility
|
|
||||||
possible unless you have a strong reason for increasing it. Start by declaring
|
|
||||||
everything as private and work from there.
|
|
||||||
|
|
||||||
@menu
|
|
||||||
* Private Members::
|
|
||||||
* Protected Members::
|
|
||||||
* Visibility Escalation:: Increasing visibility of inherited members
|
|
||||||
@end menu
|
|
||||||
|
|
||||||
@node Private Members
|
|
||||||
@subsection Private Members
|
|
||||||
Let's first explore private members. The majority of the members in the
|
|
||||||
@var{Dog} class (@pxref{f:encapsulation,}) are private. This is the lowest level
|
|
||||||
of visibility (and consequently the @emph{highest} level of encapsulation). By
|
|
||||||
convention, we prefix private members with an underscore. Private members are
|
|
||||||
available @emph{only to the class that defined it} and are not available outside
|
|
||||||
the class.
|
|
||||||
|
|
||||||
@float Figure, f:encapsulation-call-priv
|
|
||||||
@verbatim
|
|
||||||
var dog = Dog();
|
|
||||||
dog._moveFrontLeg( 1 );
|
|
||||||
|
|
||||||
// TypeError: Object #<Dog> has no method '_moveFrontLeg'
|
|
||||||
@end verbatim
|
|
||||||
@caption{Cannot access private members outside the class}
|
|
||||||
@end float
|
|
||||||
|
|
||||||
You will notice that the dog's legs are declared private as well
|
|
||||||
(@pxref{f:encapsulation,}). This is to ensure we look at the dog as a whole; we
|
|
||||||
don't care about what the dog is made up of. Legs, fur, tail, teeth, tongue, etc
|
|
||||||
- they are all irrelevant to our purpose. We just want to walk the dog.
|
|
||||||
Encapsulating those details also ensures that they will not be tampered with,
|
|
||||||
which will keep the dog in a consistent, predictable state.
|
|
||||||
|
|
||||||
Private members cannot be inherited. Let's say we want to make a class called
|
|
||||||
@var{TwoLeggedDog} to represent a dog that was trained to walk only on two feet.
|
|
||||||
We could approach this in a couple different ways. The first way would be to
|
|
||||||
prevent the front legs from moving. What happens when we explore that approach:
|
|
||||||
|
|
||||||
|
|
||||||
@float Figure, f:encapsulation-inherit-priv
|
|
||||||
@verbatim
|
|
||||||
var two_legged_dog = Class( 'TwoLeggedDog' ).extend( Dog,
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* This won't override the parent method.
|
|
||||||
*/
|
|
||||||
'private _moveFrontLeg': function( leg )
|
|
||||||
{
|
|
||||||
// don't do anything
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
} )();
|
|
||||||
|
|
||||||
two_legged_dog.walk();
|
|
||||||
@end verbatim
|
|
||||||
@caption{Cannot override private members of supertype}
|
|
||||||
@end float
|
|
||||||
|
|
||||||
If you were to attempt to walk a @var{TwoLeggedDog}, you would find that
|
|
||||||
@emph{the dog's front legs still move}! This is because, as mentioned before,
|
|
||||||
private methods are not inherited. Rather than overriding the parent's
|
|
||||||
@var{_moveFrontLeg} method, you are instead @emph{defining a new method}, with
|
|
||||||
the name @var{_moveFrontLeg}. The old method will still be called. Instead, we
|
|
||||||
would have to override the public @var{walk} method to prevent our dog from
|
|
||||||
moving his front feet.
|
|
||||||
|
|
||||||
@node Protected Members
|
|
||||||
@subsection Protected Members
|
|
||||||
Protected members are often misunderstood. Many developers will declare all
|
|
||||||
of their members as either public or protected under the misconception that they
|
|
||||||
may as well allow subclasses to override whatever functionality they want. This
|
|
||||||
makes the class more flexible.
|
|
||||||
|
|
||||||
While it is true that the class becomes more flexible to work with for subtypes,
|
|
||||||
this is a dangerous practice. In fact, doing so @emph{violates encapsulation}.
|
|
||||||
Let's reconsider the levels of visibility in this manner:
|
|
||||||
|
|
||||||
@table @strong
|
|
||||||
@item public
|
|
||||||
Provides an API for @emph{users of the class}.
|
|
||||||
|
|
||||||
@item protected
|
|
||||||
Provides an API for @emph{subclasses}.
|
|
||||||
|
|
||||||
@item private
|
|
||||||
Provides an API for @emph{the class itself}.
|
|
||||||
@end table
|
|
||||||
|
|
||||||
Just as we want to hide data from the public API, we want to do the same for
|
|
||||||
subtypes. If we simply expose all members to any subclass that comes by, that
|
|
||||||
acts as a peephole in our black box. We don't want people spying into our
|
|
||||||
internals. Subtypes shouldn't care about the dog's implementation either.
|
|
||||||
|
|
||||||
Private members (@pxref{Private Members,Private}) should be used whenever
|
|
||||||
possible, unless you are looking to provide subtypes with the ability to access
|
|
||||||
or override methods. In that case, we can move up to try protected members.
|
|
||||||
Remember not to make a member public unless you wish it to be accessible to the
|
|
||||||
entire world.
|
|
||||||
|
|
||||||
@var{Dog} (@pxref{f:encapsulation,}) defined a single method as protected -
|
|
||||||
@code{stand()}. Because the method is protected, it can be inherited by
|
|
||||||
subtypes. Since it is inherited, it may also be overridden. Let's define another
|
|
||||||
subtype, @var{LazyDog}, which refuses to stand.
|
|
||||||
|
|
||||||
@float Figure, f:encapsulation-inherit-prot
|
|
||||||
@verbatim
|
|
||||||
var lazy_dog = Class( 'LazyDog' ).extend( Dog,
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Overrides parent method
|
|
||||||
*/
|
|
||||||
'protected stand': function()
|
|
||||||
{
|
|
||||||
// nope!
|
|
||||||
this.rollOver();
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
} )();
|
|
||||||
|
|
||||||
lazy_dog.walk();
|
|
||||||
@end verbatim
|
|
||||||
@caption{Protected members are inherited by subtypes}
|
|
||||||
@end float
|
|
||||||
|
|
||||||
There are a couple important things to be noted from the above example. Firstly,
|
|
||||||
we are able to override the @code{walk()} method, because it was inherited.
|
|
||||||
Secondly, since @code{rollOver()} was also inherited from the parent, we are
|
|
||||||
able to call that method, resulting in an upside-down dog that refuses to stand
|
|
||||||
up, just moving his feet.
|
|
||||||
|
|
||||||
Another important detail to notice is that @code{Dog.rollOver()} accesses a
|
|
||||||
private property of @var{Dog} -- @var{_body}. Our subclass does not have access
|
|
||||||
to that variable. Since it is private, it was not inherited. However, since the
|
|
||||||
@code{rollOver()} method is called within the context of the @var{Dog} class,
|
|
||||||
the @emph{method} has access to the private member, allowing our dog to
|
|
||||||
successfully roll over. If, on the other hand, we were to override
|
|
||||||
@code{rollOver()}, our code would @emph{not} have access to that private object.
|
|
||||||
Calling @samp{this.__super()} from within the overridden method would, however,
|
|
||||||
call the parent method, which would again have access to its parent's private
|
|
||||||
members.
|
|
||||||
|
|
||||||
@node Visibility Escalation
|
@node Visibility Escalation
|
||||||
@subsection Visibility Escalation
|
@subsection Visibility Escalation
|
||||||
@dfn{Visibility escalation} is the act of increasing the visibility of a member.
|
@dfn{Visibility escalation} is the act of increasing the visibility of a member.
|
||||||
|
@ -1433,7 +1165,7 @@ as any static access, references the exact same value. This is especially
|
||||||
important for objects and arrays.
|
important for objects and arrays.
|
||||||
|
|
||||||
One important difference between other languages, such as PHP, is that ease.js
|
One important difference between other languages, such as PHP, is that ease.js
|
||||||
supports the @ref{Member Visibility, visibility modifiers} in conjunction with
|
supports the @ref{Access Modifiers, visibility modifiers} in conjunction with
|
||||||
the @code{const} keyword. That is, you can have public, protected and private
|
the @code{const} keyword. That is, you can have public, protected and private
|
||||||
constants. Constants are public by default, like every other type of member.
|
constants. Constants are public by default, like every other type of member.
|
||||||
This feature permits encapsulating constant values, which is important if you
|
This feature permits encapsulating constant values, which is important if you
|
||||||
|
|
|
@ -30,10 +30,19 @@ body, .float-caption
|
||||||
font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', Courier, monospace;
|
font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', Courier, monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
table, table td {
|
table, table td {
|
||||||
padding: 0.25em;
|
padding: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table ul {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px 0px 0px 1em;
|
||||||
|
}
|
||||||
|
|
||||||
dfn {
|
dfn {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -95,6 +104,11 @@ sub.left {
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* unnecessary addition by texinfo */
|
||||||
|
.float table td br {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.float-caption {
|
.float-caption {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
|
|
|
@ -43,6 +43,7 @@ Free Documentation License".
|
||||||
* About:: About the project
|
* About:: About the project
|
||||||
* Integration:: How to integrate ease.js into your project
|
* Integration:: How to integrate ease.js into your project
|
||||||
* Classes:: Learn to work with Classes
|
* Classes:: Learn to work with Classes
|
||||||
|
* Member Keywords:: Control member visibility and more.
|
||||||
* Source Tree:: Overview of source tree
|
* Source Tree:: Overview of source tree
|
||||||
* Implementation Details:: The how and why of ease.js
|
* Implementation Details:: The how and why of ease.js
|
||||||
* License:: Document License
|
* License:: Document License
|
||||||
|
@ -56,6 +57,7 @@ Free Documentation License".
|
||||||
@include about.texi
|
@include about.texi
|
||||||
@include integration.texi
|
@include integration.texi
|
||||||
@include classes.texi
|
@include classes.texi
|
||||||
|
@include mkeywords.texi
|
||||||
@include source-tree.texi
|
@include source-tree.texi
|
||||||
@include impl-details.texi
|
@include impl-details.texi
|
||||||
@include license.texi
|
@include license.texi
|
||||||
|
|
Loading…
Reference in New Issue