Table of Contents for
JavaScript: The Good Parts

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition JavaScript: The Good Parts by Douglas Crockford Published by O'Reilly Media, Inc., 2008
  1. Cover
  2. JavaScript: The Good Parts
  3. SPECIAL OFFER: Upgrade this ebook with O’Reilly
  4. A Note Regarding Supplemental Files
  5. Preface
  6. Using Code Examples
  7. Safari® Books Online
  8. How to Contact Us
  9. Acknowledgments
  10. 1. Good Parts
  11. Analyzing JavaScript
  12. A Simple Testing Ground
  13. 2. Grammar
  14. Names
  15. Numbers
  16. Strings
  17. Statements
  18. Expressions
  19. Literals
  20. Functions
  21. 3. Objects
  22. Retrieval
  23. Update
  24. Reference
  25. Prototype
  26. Reflection
  27. Enumeration
  28. Delete
  29. Global Abatement
  30. 4. Functions
  31. Function Literal
  32. Invocation
  33. Arguments
  34. Return
  35. Exceptions
  36. Augmenting Types
  37. Recursion
  38. Scope
  39. Closure
  40. Callbacks
  41. Module
  42. Cascade
  43. Curry
  44. Memoization
  45. 5. Inheritance
  46. Object Specifiers
  47. Prototypal
  48. Functional
  49. Parts
  50. 6. Arrays
  51. Length
  52. Delete
  53. Enumeration
  54. Confusion
  55. Methods
  56. Dimensions
  57. 7. Regular Expressions
  58. Construction
  59. Elements
  60. 8. Methods
  61. 9. Style
  62. 10. Beautiful Features
  63. A. Awful Parts
  64. Scope
  65. Semicolon Insertion
  66. Reserved Words
  67. Unicode
  68. typeof
  69. parseInt
  70. +
  71. Floating Point
  72. NaN
  73. Phony Arrays
  74. Falsy Values
  75. hasOwnProperty
  76. Object
  77. B. Bad Parts
  78. with Statement
  79. eval
  80. continue Statement
  81. switch Fall Through
  82. Block-less Statements
  83. ++ −−
  84. Bitwise Operators
  85. The function Statement Versus the function Expression
  86. Typed Wrappers
  87. new
  88. void
  89. C. JSLint
  90. Members
  91. Options
  92. Semicolon
  93. Line Breaking
  94. Comma
  95. Required Blocks
  96. Forbidden Blocks
  97. Expression Statements
  98. for in Statement
  99. switch Statement
  100. var Statement
  101. with Statement
  102. =
  103. == and !=
  104. Labels
  105. Unreachable Code
  106. Confusing Pluses and Minuses
  107. ++ and −−
  108. Bitwise Operators
  109. eval Is Evil
  110. void
  111. Regular Expressions
  112. Constructors and new
  113. Not Looked For
  114. HTML
  115. JSON
  116. Report
  117. D. Syntax Diagrams
  118. E. JSON
  119. Using JSON Securely
  120. A JSON Parser
  121. Index
  122. About the Author
  123. Colophon
  124. SPECIAL OFFER: Upgrade this ebook with O’Reilly

Chapter 5. Inheritance

Divides one thing entire to many objects; Like perspectives, which rightly gazed upon Show nothing but confusion. . .

William Shakespeare, The Tragedy of King Richard the Second

Inheritance is an important topic in most programming languages.

In the classical languages (such as Java), inheritance (or extends) provides two useful services. First, it is a form of code reuse. If a new class is mostly similar to an existing class, you only have to specify the differences. Patterns of code reuse are extremely important because they have the potential to significantly reduce the cost of software development. The other benefit of classical inheritance is that it includes the specification of a system of types. This mostly frees the programmer from having to write explicit casting operations, which is a very good thing because when casting, the safety benefits of a type system are lost.

JavaScript, being a loosely typed language, never casts. The lineage of an object is irrelevant. What matters about an object is what it can do, not what it is descended from.

JavaScript provides a much richer set of code reuse patterns. It can ape the classical pattern, but it also supports other patterns that are more expressive. The set of possible inheritance patterns in JavaScript is vast. In this chapter, we'll look at a few of the most straightforward patterns. Much more complicated constructions are possible, but it is usually best to keep it simple.

In classical languages, objects are instances of classes, and a class can inherit from another class. JavaScript is a prototypal language, which means that objects inherit directly from other objects.

Pseudoclassical

JavaScript is conflicted about its prototypal nature. Its prototype mechanism is obscured by some complicated syntactic business that looks vaguely classical. Instead of having objects inherit directly from other objects, an unnecessary level of indirection is inserted such that objects are produced by constructor functions.

When a function object is created, the Function constructor that produces the function object runs some code like this:

this.prototype = {constructor: this};

The new function object is given a prototype property whose value is an object containing a constructor property whose value is the new function object. The prototype object is the place where inherited traits are to be deposited. Every function gets a prototype object because the language does not provide a way of determining which functions are intended to be used as constructors. The constructor property is not useful. It is the prototype object that is important.

When a function is invoked with the constructor invocation pattern using the new prefix, this modifies the way in which the function is executed. If the new operator were a method instead of an operator, it could have been implemented like this:

Function.method('new', function (  ) {

// Create a new object that inherits from the
// constructor's prototype.

    var that = Object.beget(this.prototype);

// Invoke the constructor, binding -this- to
// the new object.

    var other = this.apply(that, arguments);

// If its return value isn't an object,
// substitute the new object.

    return (typeof other === 'object' && other) || that;
});

We can define a constructor and augment its prototype:

var Mammal = function (name) {
    this.name = name;
};

Mammal.prototype.get_name = function (  ) {
    return this.name;
};

Mammal.prototype.says = function (  ) {
    return this.saying || '';
};

Now, we can make an instance:

var myMammal = new Mammal('Herb the Mammal');
var name = myMammal.get_name(  ); // 'Herb the Mammal'

We can make another pseudoclass that inherits from Mammal by defining its constructor function and replacing its prototype with an instance of Mammal:

var Cat = function (name) {
    this.name = name;
    this.saying = 'meow';
};

// Replace Cat.prototype with a new instance of Mammal

Cat.prototype = new Mammal(  );

// Augment the new prototype with
// purr and get_name methods.

Cat.prototype.purr = function (n) {
    var i, s = '';
    for (i = 0; i < n; i += 1) {
        if (s) {
            s += '-';
        }
        s += 'r';
    }
    return s;
};
Cat.prototype.get_name = function (  ) {
    return this.says(  ) + ' ' + this.name + ' ' + this.says(  );
};

var myCat = new Cat('Henrietta');
var says = myCat.says(  ); // 'meow'
var purr = myCat.purr(5); // 'r-r-r-r-r'
var name = myCat.get_name(  );
//            'meow Henrietta meow'

The pseudoclassical pattern was intended to look sort of object-oriented, but it is looking quite alien. We can hide some of the ugliness by using the method method and defining an inherits method:

Function.method('inherits', function (Parent) {
    this.prototype = new Parent(  );
    return this;
});

Our inherits and method methods return this, allowing us to program in a cascade style. We can now make our Cat with one statement.

var Cat = function (name) {
    this.name = name;
    this.saying = 'meow';
}.
    inherits(Mammal).
    method('purr', function (n) {
        var i, s = '';
        for (i = 0; i < n; i += 1) {
            if (s) {
                s += '-';
            }
            s += 'r';
        }
        return s;
    }).
    method('get_name', function (  ) {
        return this.says(  ) + ' ' + this.name + ' ' + this.says(  );
    });

By hiding the prototype jazz, it now looks a bit less alien. But have we really improved anything? We now have constructor functions that act like classes, but at the edges, there may be surprising behavior. There is no privacy; all properties are public. There is no access to super methods.

Even worse, there is a serious hazard with the use of constructor functions. If you forget to include the new prefix when calling a constructor function, then this will not be bound to a new object. Sadly, this will be bound to the global object, so instead of augmenting your new object, you will be clobbering global variables. That is really bad. There is no compile warning, and there is no runtime warning.

This is a serious design error in the language. To mitigate this problem, there is a convention that all constructor functions are named with an initial capital, and that nothing else is spelled with an initial capital. This gives us a prayer that visual inspection can find a missing new. A much better alternative is to not use new at all.

The pseudoclassical form can provide comfort to programmers who are unfamiliar with JavaScript, but it also hides the true nature of the language. The classically inspired notation can induce programmers to compose hierarchies that are unnecessarily deep and complicated. Much of the complexity of class hierarchies is motivated by the constraints of static type checking. JavaScript is completely free of those constraints. In classical languages, class inheritance is the only form of code reuse. JavaScript has more and better options.