});
}());
Finally, it is worth emphasizing that the ability to create class factories like this one
arises from the dynamic nature of JavaScript. Class factories are a powerful and useful
feature that has no analog in languages like Java and C++.
9.7.3  Composition Versus Subclassing
In the previous section, we wanted to define sets that restricted their members accord-
ing to certain criteria, and we used subclassing to accomplish this, creating a custom
subclass of a specified set implementation that used a specified filter function to restrict
membership in the set. Each combination of superclass and filter function required the
creation of a new class.
There is a better way to accomplish this, however. A well-known principle in object-
oriented design is “favor composition over inheritance.”
2
In this case we can use com-
position by defining a new set implementation that “wraps” another set object and
forwards requests to it, after filtering out prohibited members. Example 9-15 shows
how it is done.
Example 9-15. Composing sets instead of subclassing them
/*
* A FilteredSet wraps a specified set object and applies a specified filter
* to values passed to its add() method.  All of the other core set methods 
* simply forward to the wrapped set instance.
*/
var FilteredSet = Set.extend(
function FilteredSet(set, filter) {  // The constructor
this.set = set;
this.filter = filter;
}, 
{  // The instance methods
add: function() {
// If we have a filter, apply it
if (this.filter) {
for(var i = 0; i < arguments.length; i++) {
var v = arguments[i];
if (!this.filter(v))
throw new Error("FilteredSet: value " + v +
" rejected by filter");
}
}
// Now forward the add() method to this.set.add()
this.set.add.apply(this.set, arguments);
return this;
},
// The rest of the methods just forward to this.set and do nothing else.
remove: function() {
2.See Design Patterns by Erich Gamma et al. or Effective Java by Joshua Bloch, for example.
9.7  Subclasses | 233
Core JavaScript
Pdf links - insert, remove PDF links in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
Free C# example code is offered for users to edit PDF document hyperlink (url), like inserting and deleting
add email link to pdf; adding links to pdf
Pdf links - VB.NET PDF url edit library: insert, remove PDF links in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
Help to Insert a Hyperlink to Specified PDF Document Page
adding links to pdf document; add links to pdf document
this.set.remove.apply(this.set, arguments);
return this;
},
contains: function(v) { return this.set.contains(v); },
size: function() { return this.set.size(); },
foreach: function(f,c) { this.set.foreach(f,c); }
});
One of the benefits of using composition in this case is that only a single FilteredSet
subclass is required. Instances of this class can be created to restrict the membership
of any other set instance. Instead of using the NonNullSet class defined earlier, for
example, we can do this:
var s = new FilteredSet(new Set(), function(x) { return x !== null; });
We can even filter a filtered set:
var t = new FilteredSet(s, { function(x} { return !(x instanceof Set); });
9.7.4  Class Hierarchies and Abstract Classes
In the previous section you were urged to “favor composition over inheritance.” But to
illustrate this principle, we created a subclass of Set. We did this so that the resulting
class would be 
instanceof Set
, and so that it could inherit the useful auxiliary Set
methods like 
toString()
and 
equals()
. These are valid pragmatic reasons, but it still
would have been nice to be able to do set composition without subclassing a concrete
implementation like the Set class. A similar point can be made about our SingletonSet
class from Example 9-12—that class subclassed Set, so that it could inherit the auxiliary
methods, but its  implementation  was completely different than its superclass.
SingletonSet is not a specialized version of the Set class, but a completely different kind
of Set. SingletonSet should be a sibling of Set in the class hierarchy, not a descendant
of it.
The solution in classical OO languages and also in JavaScript is to separate interface
from implementation. Suppose we define an AbstractSet class which implements the
auxiliary methods like 
toString()
but does not implement the core methods like
foreach()
. Then, our set implementations, Set, SingletonSet, and FilteredSet, can all
be subclasses of AbstractSet. FilteredSet and SingletonSet no longer subclass an unre-
lated implementation.
Example 9-16 takes this approach further and defines a hierarchy of abstract set classes.
AbstractSet defines only a single abstract method, 
contains()
. Any class that purports
to be a set must define at least this one method. Next, we subclass AbstractSet to define
AbstractEnumerableSet. That class adds abstract 
size()
and 
foreach()
methods, and
defines useful concrete methods (
toString()
toArray()
equals()
, and so on) on top
of them. AbstractEnumerableSet does not define 
add()
or 
remove()
methods and rep-
resents read-only sets. SingletonSet can be implemented as a concrete subclass. Finally,
we define AbstractWritableSet as a subclass of AbstractEnumerableSet. This final ab-
stract set defines the abstract methods 
add()
and 
remove()
, and implements concrete
234 | Chapter 9: Classes and Modules
C# PDF Convert to HTML SDK: Convert PDF to html files in C#.net
Embed zoom setting (fit page, fit width). Turn PDF form data to HTML form. Export PDF images to HTML images. Embed PDF hyperlinks to HTML links.
adding an email link to a pdf; add links to pdf
C# Image: Tutorial for Document Management Using C#.NET Imaging
more detailed C# tutorials on each part by following the links respectively are dedicated to provide powerful & profession imaging controls, PDF document, image
pdf link; add hyperlinks to pdf
methods like 
union()
and 
intersection()
that use them. 
AbstractWritableSet
is the
appropriate superclass for our Set and FilteredSet classes. They are omitted from this
example, however, and a new concrete implementation named ArraySet is included
instead.
Example 9-16 is a long example, but worth reading through in its entirety. Note that
it uses 
Function.prototype.extend()
as a shortcut for creating subclasses.
Example 9-16. A hierarchy of abstract and concrete Set classes
// A convenient function that can be used for any abstract method
function abstractmethod() { throw new Error("abstract method"); }
/*
* The AbstractSet class defines a single abstract method, contains().
*/
function AbstractSet() { throw new Error("Can't instantiate abstract classes");}
AbstractSet.prototype.contains = abstractmethod;
/*
* NotSet is a concrete subclass of AbstractSet.
* The members of this set are all values that are not members of some
* other set. Because it is defined in terms of another set it is not
* writable, and because it has infinite members, it is not enumerable.
* All we can do with it is test for membership.
* Note that we're using the Function.prototype.extend() method we defined
* earlier to define this subclass.
*/
var NotSet = AbstractSet.extend(
function NotSet(set) { this.set = set; },
{
contains: function(x) { return !this.set.contains(x); },
toString: function(x) { return "~" + this.set.toString(); },
equals: function(that) {
return that instanceof NotSet && this.set.equals(that.set);
}
}
);
/*
* AbstractEnumerableSet is an abstract subclass of AbstractSet.
* It defines the abstract methods size() and foreach(), and then implements
* concrete isEmpty(), toArray(), to[Locale]String(), and equals() methods
* on top of those. Subclasses that implement contains(), size(), and foreach() 
* get these five concrete methods for free.
*/
var AbstractEnumerableSet = AbstractSet.extend(
function() { throw new Error("Can't instantiate abstract classes"); }, 
{
size: abstractmethod,
foreach: abstractmethod,
isEmpty: function() { return this.size() == 0; },
toString: function() {
var s = "{", i = 0;
9.7  Subclasses | 235
Core JavaScript
.NET PDF Document Viewing, Annotation, Conversion & Processing
PDF Write. Insert text, text box into PDF. Edit, delete text from PDF. Insert images into PDF. Edit, remove images from PDF. Add, edit, delete links. Form Process
convert a word document to pdf with hyperlinks; add links to pdf file
VB.NET PDF Convert to HTML SDK: Convert PDF to html files in vb.
Turn PDF images to HTML images in VB.NET. Embed PDF hyperlinks to HTML links in VB.NET. Available zoom setting (fit page, fit width).
add hyperlinks pdf file; clickable links in pdf files
this.foreach(function(v) {
if (i++ > 0) s += ", ";
s += v;
});
return s + "}";
},
toLocaleString : function() {
var s = "{", i = 0;
this.foreach(function(v) {
if (i++ > 0) s += ", ";
if (v == null) s += v; // null & undefined
else s += v.toLocaleString(); // all others
});
return s + "}";
},
toArray: function() {
var a = [];
this.foreach(function(v) { a.push(v); });
return a;
},
equals: function(that) {
if (!(that instanceof AbstractEnumerableSet)) return false;
// If they don't have the same size, they're not equal
if (this.size() != that.size()) return false;
// Now check whether every element in this is also in that.
try {
this.foreach(function(v) {if (!that.contains(v)) throw false;});
return true;  // All elements matched: sets are equal.
} catch (x) {
if (x === false) return false; // Sets are not equal
throw x; // Some other exception occurred: rethrow it.
}
}
});
/*
* SingletonSet is a concrete subclass of AbstractEnumerableSet.
* A singleton set is a read-only set with a single member.
*/
var SingletonSet = AbstractEnumerableSet.extend(
function SingletonSet(member) { this.member = member; },
{
contains: function(x) {  return x === this.member; },
size: function() { return 1; },
foreach: function(f,ctx) { f.call(ctx, this.member); }
}
);
/*
* AbstractWritableSet is an abstract subclass of AbstractEnumerableSet.
* It defines the abstract methods add() and remove(), and then implements
* concrete union(), intersection(), and difference() methods on top of them.
*/
var AbstractWritableSet = AbstractEnumerableSet.extend(
function() { throw new Error("Can't instantiate abstract classes"); }, 
236 | Chapter 9: Classes and Modules
C# PDF Convert to Word SDK: Convert PDF to Word library in C#.net
keeps the elements (like images, tables and chats) of original PDF file and maintains the original text style (including font, size, color, links and boldness
add links in pdf; pdf email link
How to C#: Basic SDK Concept of XDoc.PDF for .NET
XDoc.PDF for .NET allows C# developers to edit hyperlink of PDF document, including editing PDF url links and quick navigation link in bookmark/outline.
adding hyperlinks to pdf documents; add links to pdf acrobat
{
add: abstractmethod,
remove: abstractmethod,
union: function(that) {
var self = this;
that.foreach(function(v) { self.add(v); });
return this;
},
intersection: function(that) {
var self = this;
this.foreach(function(v) { if (!that.contains(v)) self.remove(v);});
return this;
},
difference: function(that) {
var self = this;
that.foreach(function(v) { self.remove(v); });
return this;
}
});
/*
* An ArraySet is a concrete subclass of AbstractWritableSet.
* It represents the set elements as an array of values, and uses a linear
* search of the array for its contains() method. Because the contains()
* method is O(n) rather than O(1), it should only be used for relatively
* small sets. Note that this implementation relies on the ES5 Array methods
* indexOf() and forEach().
*/
var ArraySet = AbstractWritableSet.extend(
function ArraySet() {
this.values = [];
this.add.apply(this, arguments);
},
{
contains: function(v) { return this.values.indexOf(v) != -1; },
size: function() { return this.values.length; },
foreach: function(f,c) { this.values.forEach(f, c); },
add: function() { 
for(var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (!this.contains(arg)) this.values.push(arg);
}
return this;
},
remove: function() {
for(var i = 0; i < arguments.length; i++) {
var p = this.values.indexOf(arguments[i]);
if (p == -1) continue;
this.values.splice(p, 1);
}
return this;
}
}
);
9.7  Subclasses | 237
Core JavaScript
VB.NET PDF: Basic SDK Concept of XDoc.PDF
XDoc.PDF for .NET allows VB.NET developers to edit hyperlink of PDF document, including editing PDF url links and quick navigation link in bookmark/outline.
pdf links; add a link to a pdf in acrobat
C# Create PDF Library SDK to convert PDF from other file formats
file. Create and save editable PDF with a blank page, bookmarks, links, signatures, etc. Create fillable PDF document with fields.
accessible links in pdf; convert excel to pdf with hyperlinks
9.8  Classes in ECMAScript 5
ECMAScript 5 adds methods for specifying property attributes (getters, setters, enu-
merability, writability, and configurability) and for restricting the extensibility of ob-
jects. These methods were described in §6.6§6.7, and §6.8.3, but turn out to be quite
useful when defining classes. The subsections that follow demonstrate how to use these
ECMAScript 5 capabilities to make your classes more robust.
9.8.1  Making Properties Nonenumerable
The Set class of Example 9-6 used a trick to store objects as set members: it defined an
“object id” property on any object added to the set. Later, if other code uses that object
in a 
for/in
loop, this added property will be returned. ECMAScript 5 allows us to avoid
this by making properties nonenumerable. Example 9-17 demonstrates how to do this
with 
Object.defineProperty()
and also shows how to define a getter function and how
to test whether an object is extensible.
Example 9-17. Defining nonenumerable properties
// Wrap our code in a function so we can define variables in the function scope
(function() { 
// Define objectId as a nonenumerable property inherited by all objects.
// When this property is read, the getter function is invoked.
// It has no setter, so it is read-only.
// It is nonconfigurable, so it can't be deleted.
Object.defineProperty(Object.prototype, "objectId", {
get: idGetter,       // Method to get value
enumerable: false,   // Nonenumerable
configurable: false  // Can't delete it
});
// This is the getter function called when objectId is read
function idGetter() {             // A getter function to return the id
if (!(idprop in this)) {      // If object doesn't already have an id
if (!Object.isExtensible(this)) // And if we can add a property
throw Error("Can't define id for nonextensible objects");
Object.defineProperty(this, idprop, {         // Give it one now.
value: nextid++,    // This is the value
writable: false,    // Read-only
enumerable: false,  // Nonenumerable
configurable: false // Nondeletable
});
}
return this[idprop];          // Now return the existing or new value
};
// These variables are used by idGetter() and are private to this function
var idprop = "|**objectId**|";    // Assume this property isn't in use
var nextid = 1;                   // Start assigning ids at this #
}()); // Invoke the wrapper function to run the code right away
238 | Chapter 9: Classes and Modules
9.8.2  Defining Immutable Classes
In addition to making properties nonenumerable, ECMAScript 5 allows us to make
properties read-only, which is handy if we want to define classes whose instances are
immutable. Example 9-18 is an immutable version of our Range class that does
this  using 
Object.defineProperties()
and  with 
Object.create()
 It  also  uses
Object.defineProperties()
to set up the prototype object for the class, making the
instance methods nonenumerable, like the methods of built-in classes. In fact, it goes
further than this and makes those instance methods read-only and nondeletable, which
prevents any dynamic alterations (“monkey-patching”) to the class. Finally, as an in-
teresting trick, Example 9-18 has a constructor function that works as a factory function
when invoked without the 
new
keyword.
Example 9-18. An immutable class with read-only properties and methods
// This function works with or without 'new': a constructor and factory function
function Range(from,to) {
// These are descriptors for the read-only from and to properties.
var props = {
from: {value:from, enumerable:true, writable:false, configurable:false},
to: {value:to, enumerable:true, writable:false, configurable:false}
};
if (this instanceof Range)                // If invoked as a constructor
Object.defineProperties(this, props); // Define the properties
else                                      // Otherwise, as a factory 
return Object.create(Range.prototype, // Create and return a new
props);          // Range object with props
}
// If we add properties to the Range.prototype object in the same way,
// then we can set attributes on those properties.  Since we don't specify
// enumerable, writable, or configurable, they all default to false.
Object.defineProperties(Range.prototype, {
includes: {
value: function(x) { return this.from <= x && x <= this.to; }
},
foreach: {
value: function(f) {
for(var x = Math.ceil(this.from); x <= this.to; x++) f(x);
}
},
toString: {
value: function() { return "(" + this.from + "..." + this.to + ")"; }
}
});
Example 9-18 uses 
Object.defineProperties()
and 
Object.create()
to define immut-
able and nonenumerable properties. These are powerful methods, but the property
descriptor objects they require can make the code difficult to read. An alternative is to
define utility functions for modifying the attributes of properties that have already been
defined. Example 9-19 shows two such utility functions.
9.8  Classes in ECMAScript 5 | 239
Core JavaScript
Example 9-19. Property descriptor utilities
// Make the named (or all) properties of o nonwritable and nonconfigurable.
function freezeProps(o) {
var props = (arguments.length == 1)              // If 1 arg
? Object.getOwnPropertyNames(o)              //  use all props
: Array.prototype.splice.call(arguments, 1); //  else named props
props.forEach(function(n) { // Make each one read-only and permanent
// Ignore nonconfigurable properties
if (!Object.getOwnPropertyDescriptor(o,n).configurable) return;
Object.defineProperty(o, n, { writable: false, configurable: false });
});
return o;  // So we can keep using it
}
// Make the named (or all) properties of o nonenumerable, if configurable.
function hideProps(o) {
var props = (arguments.length == 1)              // If 1 arg
? Object.getOwnPropertyNames(o)              //  use all props
: Array.prototype.splice.call(arguments, 1); //  else named props
props.forEach(function(n) { // Hide each one from the for/in loop
// Ignore nonconfigurable properties
if (!Object.getOwnPropertyDescriptor(o,n).configurable) return;
Object.defineProperty(o, n, { enumerable: false });
});
return o;
}
Object.defineProperty()
and 
Object.defineProperties()
can be used to create new
properties and also to modify the attributes of existing properties. When used to define
new properties, any attributes you omit default to 
false
. When used to alter existing
properties, however, the attributes you omit are left unchanged. In the 
hideProps()
function above, for example, we specify only the 
enumerable
attribute because that is
the only one we want to modify.
With these utility functions defined, we can take advantage of ECMAScript 5 features
to write an immutable class without dramatically altering the way we write classes.
Example 9-20 shows an immutable Range class that uses our utility functions.
Example 9-20. A simpler immutable class
function Range(from, to) {    // Constructor for an immutable Range class
this.from = from;
this.to = to;
freezeProps(this);        // Make the properties immutable
}
Range.prototype = hideProps({ // Define prototype with nonenumerable properties
constructor: Range,
includes: function(x) { return this.from <= x && x <= this.to; },
foreach: function(f) {for(var x=Math.ceil(this.from);x<=this.to;x++) f(x);},
toString: function() { return "(" + this.from + "..." + this.to + ")"; }
});
240 | Chapter 9: Classes and Modules
9.8.3  Encapsulating Object State
§9.6.6 and Example 9-10 showed how you can use variables or arguments of a con-
structor function as private state for the objects created by that constructor. The short-
coming of this technique is that in ECMAScript 3, the accessor methods that provide
access to that state can be replaced. ECMAScript 5 allows us to encapsulate our state
variables more robustly by defining property getter and setter methods that cannot be
deleted. Example 9-21 demonstrates.
Example 9-21. A Range class with strongly encapsulated endpoints
// This version of the Range class is mutable but encapsulates its endpoint
// variables to maintain the invariant that from <= to.
function Range(from, to) {
// Verify that the invariant holds when we're created
if (from > to) throw new Error("Range: from must be <= to");
// Define the accessor methods that maintain the invariant
function getFrom() {  return from; }
function getTo() {  return to; }
function setFrom(f) {  // Don't allow from to be set > to
if (f <= to) from = f;
else throw new Error("Range: from must be <= to");
}
function setTo(t) {    // Don't allow to to be set < from
if (t >= from) to = t;
else throw new Error("Range: to must be >= from");
}
// Create enumerable, nonconfigurable properties that use the accessors
Object.defineProperties(this, {
from: {get: getFrom, set: setFrom, enumerable:true, configurable:false},
to: { get: getTo, set: setTo, enumerable:true, configurable:false }
});
}
// The prototype object is unchanged from previous examples.
// The instance methods read from and to as if they were ordinary properties.
Range.prototype = hideProps({
constructor: Range,
includes: function(x) { return this.from <= x && x <= this.to; },
foreach: function(f) {for(var x=Math.ceil(this.from);x<=this.to;x++) f(x);},
toString: function() { return "(" + this.from + "..." + this.to + ")"; }
});
9.8.4  Preventing Class Extensions
It is usually considered a feature of JavaScript that classes can be dynamically extended
by adding new methods to the prototype object. ECMAScript 5 allows you to prevent
this, if you want to. 
Object.preventExtensions()
makes an object nonextensible
(§6.8.3), which means that no new properties can be added to it. 
Object.seal()
takes
this a step further: it prevents the addition of new properties and also makes all current
properties nonconfigurable, so that they cannot be deleted. (A nonconfigurable
9.8  Classes in ECMAScript 5 | 241
Core JavaScript
property can still be writable, however, and can still be converted into a read-only
property.) To prevent extensions to 
Object.prototype
, you can simply write:
Object.seal(Object.prototype);
Another dynamic feature of JavaScript is the ability to replace (or “monkey-patch”)
methods of an object:
var original_sort_method = Array.prototype.sort;
Array.prototype.sort = function() {
var start = new Date();
original_sort_method.apply(this, arguments);
var end = new Date();
console.log("Array sort took " + (end - start) + " milliseconds.");
};
You can prevent this kind of alteration by making your instance methods read-only.
The 
freezeProps()
utility function defined above is one way to accomplish this. An-
other way is with 
Object.freeze()
, which does everything that 
Object.seal()
does, but
also makes all properties read-only and nonconfigurable.
There is a feature of read-only properties that is important to understand when
working with classes. If an object 
o
inherits a read-only property 
p
, an attempt to assign
to 
o.p
will fail and will not create a new property in 
o
. If you want to override an
inherited  read-only  property,  you  have  to  use 
Object.defineProperty()
or
Object.defineProperties()
or 
Object.create()
to create the new property. This means
that if you make the instance methods of a class read-only, it becomes significantly
more difficult for subclasses to override those methods.
It is not usually necessary to lock down prototype objects like this, but there are some
circumstances where preventing extensions to an object can be useful. Think back to
the 
enumeration()
class factory function of Example 9-7. That function stored the in-
stances of each enumerated type in properties of the constructor object, and also in the
values
array of the constructor. These properties and array serve as the official list of
instances of the enumerated type, and it is worth freezing them, so that new instances
cannot be  added  and existing instances cannot be deleted or altered. In the
enumeration()
function we can simply add these lines of code:
Object.freeze(enumeration.values);
Object.freeze(enumeration);
Notice that by calling 
Object.freeze()
on the enumerated type, we prevent the future
use of the 
objectId
property defined in Example 9-17. A solution to this problem is to
read the 
objectId
property (calling the underlying accessor method and setting the
internal property) of the enumerated type once before freezing it.
9.8.5  Subclasses and ECMAScript 5
Example 9-22 demonstrates subclassing using ECMAScript 5 features. It defines a
StringSet class as a subclass of the AbstractWritableSet class from Example 9-16. The
main feature of this example is the use of 
Object.create()
to create a prototype object
242 | Chapter 9: Classes and Modules
Documents you may be interested
Documents you may be interested