Skip to main content

Functional Programming from "JavaScript: The Good Parts"

Free2015-05-07#JS#JavaScript语言精粹

My study notes were only missing this small piece, finally complete. First time reading this part, didn't understand. Second time, still didn't understand. Third time, started to get a feeling. Fourth time, realized the feeling was wrong... Now I've mostly figured it out, let's sort it out

Preface

Read many book reviews and reading notes saying "JavaScript: The Good Parts" is word-for-word gem, truly deserves its reputation... Of course, you need to understand it first.

Personally, I think the functional programming part isn't very good. The examples given aren't very appropriate. I couldn't understand it before because I was successfully misled, just like "Head First" Design Patterns Chapter 1 "Strategy Pattern". The author deviates somewhat from the chapter theme, and readers can easily be misled.

Declaration: Let's call the functions given in the functional programming part for creating objects "creator functions" to distinguish them from "constructor functions"... Not very pleasant sounding, but let's use it.

I. Points to Note in Source Code

Easy to get the source code. Same as the code in the Chinese version of the book. After careful reading, I found a very ingenious part. Of course, it's not easy to understand.

P.S. There's a small problem in the source code: the "creator function" cat has mismatched braces. Chinese version page 54, missing }; before return that;.

A Very Ingenious Part Inside Object's Prototype Function superior

Object.method('superior', function (name) {
    var that = this,
        method = that[name];
    return function (  ) {
        return method.apply(that, arguments);
    };
});

The highlight is the arguments in the last sentence. It seems unintentional, but it's actually intentional, indicating that parameters can also be passed when calling parent class methods with superior. Of course, to pass parameters, the calling method needs to be modified. Test code is as follows:

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

var mammal = function (spec) {
    var that = {};

    that.get_name = function (  ) {
        return spec.name;
    };

    that.says = function (  ) {
        return spec.saying || '';
    };

    return that;
};

var cat = function (spec) {
    spec.saying = spec.saying || 'meow';
    var that = mammal(spec);
    that.purr = function (n) {
        var i, s = '';
        for (i = 0; i < n; i += 1) {
            if (s) {
                s += '-';
            }
            s += 'r';
        }
        return s;
    };
    that.get_name = function (  ) {
        alert("cat.get_name :" + arguments.length);///
        return that.says(  ) + ' ' + spec.name +
                ' ' + that.says(  ) + "[" + arguments.length + "]";
    };
    
    return that;
};

Object.method('superior', function (name) {
    var that = this,
        method = that[name];
    return function (  ) {
        alert("superior :" + arguments.length);///
        return method.apply(that, arguments);
    };
});

var coolcat = function (spec) {
    var that = cat(spec),
        super_get_name = that.superior('get_name');
    that.get_name = function () {
        alert("coolcat.get_name :" + arguments.length);///
        return 'like ' + super_get_name.apply(this, arguments) + ' baby';
    };
    return that;
};

var myCoolCat = coolcat({name: 'Bix'});
var name = myCoolCat.get_name(1, 2, 3);
//        'like meow Bix meow baby'


alert(name);    // 'like meow Bix meow[3] baby'

P.S. At first, I thought the arguments at the end of the superior function was the author's mistake. I thought the arguments object from outside should be passed to method instead of the inside one. After going around in a big circle, I discovered I was wrong. My skill level wasn't enough to instantly understand what Grandpa Douglas meant...

II. Original Intention of Functional Programming

The functional programming part explains the original intention at the beginning: to achieve private attributes, creating the "pseudoclassical objects" mentioned at the end.

The purpose is unquestionable. Achieving private attributes is very necessary. But the examples given mammal -> cat -> coolcat are too inappropriate. The author wants to illustrate that inheritance can be achieved through functional programming.

Of course, it's not inheritance in the strict sense, because the functional programming method doesn't use custom types. The is-a relationship between subclass instances and parent class instances is out of the question.

P.S. When reading the cat example the first time, it led me astray. I thought functional programming meant abandoning new completely and using functions to achieve inheritance... Naturally, I went deeper and deeper into the ditch.

III. Philosophy of Functional Programming

Look at the code directly. The code speaks for itself:

/*
 * Philosophy of functional programming:
 * 1. Create object
 * 2. Add private attributes
 * 3. Expose interface (add public attributes)
 * 4. Return the object
 */
/*
 * method: getSuper
 * @param spec Specification object, provides basic data needed to create object
 * @param my Container for sharing data between "creator functions"
 */
function getSuper(spec, my){
    var obj;            // Object to return
    var my = my || {};  // Create one if not passed in
    
    // Private attributes
    var attr = spec.value;  // Get data from specification object
    var fun = function(){
        alert(attr);
    }
    
    // [Optional] Put data that needs to be shared with other "creator functions" into my
    
    // Create object, can use any method, such as new, literal, calling other "creator functions"
    obj = {
        name: "SuperObject"
    };
    
    // Expose interface
    obj.fun1 = fun;
    
    // Return obj
    return obj;
}

/*
 * method: getSub
 * Parameters same as above
 */
function getSub(spec, my){
    var obj;
    var my = my || {};
    
    // Private attributes
    var attr = spec.value + 1;
    var fun = function(){
        alert(attr);
    }
    
    // [Optional] Share
    
    // Create object
    obj = getSuper(spec, my);   // Can pass directly, of course can also modify before passing, or pass something else
    
    // Expose interface
    obj.fun2 = fun;
    
    // Return obj
    return obj;
}

// Test
var spec = {
    value: 1
};
var sub = getSub(spec); // No need to pass my, my should only be used between "creator functions"
sub.fun1(); // 1
sub.fun2(); // 2

P.S. It's that same pattern again "create object -> enhance -> return new object". Isn't this the "Module Pattern" invented by Douglas as said by Nicholas?

IV. Pseudoclassical Objects (Durable Objects)

The core of the functional programming part is this. Note the way of exposing interfaces in the example above:

// Private attributes
var myFun = function(){/* ... */};
// Expose interface
obj.fun = myFun;

Instead of directly using:

// Expose interface
obj.fun = function(){/* ... */};

The first method is more secure, because even if fun is modified from outside, other methods inside that call myFun can still work normally. Such function objects are the so-called pseudoclassical objects.

Complete definition:

The properties of a pseudoclassical object can be replaced or deleted, but the object's integrity will not be compromised.

Also known as durable objects. A durable object is a collection of simple functional functions.

Afterword

Here, the study notes for "JavaScript: The Good Parts" come to a pause. Having filled the gap in [functional programming], please check [Ayqy: "JavaScript: The Good Parts" Study Notes](http://ayqy.net/blog/《JavaScript 语言精粹》学习笔记/) for other parts of the study notes.

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment