Javascript module pattern introduced in TGP deenti

2019-07-19 03:06发布

问题:

Crockford introduces a pattern in the deentityify method to create a module. He claims:

The module pattern takes advantage of function scope and close to create relationships that are binding and private. In this example, only the deentityify method has access to the entity data structure.

Distilling to remove his custom functions, I think the code boils down to...

String.prototype.deentityify = function() {
    var entity = { 
        quot: '"',
        lt: '<',
        gt: '>'
    };

    return function() {
        return this.replace(/&([^&;]+);/g, function(a, b) {
            var r = entity[b];
            return typeof r === 'string' ? r : a;
        });  //close function(a,b)
    }; //close the returned function
} /* close  top level */ (); /* but evaluate it so deentitify becomes the returned fcn(!)

Problem is I don't see why this additional layer of indirection is necessary. Is this code not equivalent?

String.prototype.deentityify = function() {
    var entity = { 
        quot: '"',
        lt: '<',
        gt: '>'
    };

//    return function() {
        return this.replace(/&([^&;]+);/g, function(a, b) {
            var r = entity[b];
            return typeof r === 'string' ? r : a;
        });  //close function(a,b)
//    }; //close the returned function
} /* close  top level, don't evaluate

回答1:

The basic reason for this pattern is to avoid re-evaluating entity on every call. Replace entity with something that is expensive to construct and doesn't change from call to call:

String.prototype.deentityify = function() {
    // expensiveFunctionCall is called *once* - when the function is defined.
    var entity = expensiveFunctionCall();

    return function() {
        return this.replace(/&([^&;]+);/g, function(a, b) {
            var r = entity[b];
            return typeof r === 'string' ? r : a;
        });  //close function(a,b)
    }; //close the returned function
}();

vs

String.prototype.deentityify = function() {
    // expensiveFunctionCall is called
    // *every time* "anyString".deentityify() is called.
    var entity = expensiveFunctionCall();

    return this.replace(/&([^&;]+);/g, function(a, b) {
        var r = entity[b];
        return typeof r === 'string' ? r : a;
    });  //close function(a,b)
};