When I started thinking about this book, I wanted to take the subset idea further, to show how to take an existing programming language and make significant improvements to it by making no changes except to exclude the low-value features. We see a lot of feature-driven product design in which the cost of features is not properly accounted. Features can have a negative value to consumers because they make the products more difficult to understand and use. We are finding that people like products that just work. It turns out that designs that just work are much harder to produce than designs that assemble long lists of features.With so many languages available today, each of them having huge lists of features, it's great to have a guide to a language that points out the parts of it that you should focus on and really understand how to use.
What are the best features? In a nutshell, they are the fact that functions are first class objects, prototypal inheritance, and the rich object literal syntax. The most controversial of these is probably prototypal inheritance because it is so different than anything most programmers have encountered. Crockford is encouraging:
For some patterns that were presented, it did not make sense to me why you would ever want to do such a thing. For instance, when Stefanov was describing how to expose private functions of an object as public methods, he exposes the same private function as two public methods with different names. Then he claims that if something happens to one of the public methods, the other one will still work as it did before. That's all well and good, but why would something happen to one of the public methods? That still seems bad. Then all other uses of that public method will have changed, even if the other public method maintains the same behavior. It doesn't seem terribly useful as a protection mechanism. It's really only useful as a way to create aliases for methods, which is a good thing in and of itself for making code more readable, but you really don't want to have anything happen to either name for the method.
Then in Chapter 6, where Stefanov describes different inheritance patterns, he continually uses a somewhat dubious example of a parent and child for the inheritance hierarchy. Inheritance is all about the 'is-a' relationship, meaning that the object that inherits behavior should be a derivative of what it inherits from, like a cat is a feline or a square is a quadrilateral. That doesn't work for a parent and a child because a child is not (necessarily) a parent. A child has a parent, but that's a different relationship where the child should have a member that is its parent. The child shouldn't inherit from its parent in code even if a real child does genetically. This misrepresentation made the sections on inheritance slightly confusing because the relationship was all wrong, and I had to keep reminding myself of what it should be.
Once he finally got to the GoF design patterns, it became quite apparent that most of these patterns are trivial to implement in a dynamic language that has closures and first class functions. Many of the original patterns were designed to solve issues that came up when writing programs in a more inflexible static language. Implementing iterators and decorators and proxies is easy when you can pass functions around and have them operate on arbitrary objects without having to deal with a complicated inheritance hierarchy to accomplish the same thing. That was quite a revelation for me.
Stick to the Good Parts