본문 바로가기

0/javascript

Mastering Design Patterns (1)

반응형

Modules

There is no first class support for namespaces.

To create modules just attach an object to the global namespace.

Westeros = {}

This object is, by default, attached to the top-level object, so we need not do anything more than that. This allows you to spread your definitions over a number of files.

Westeros = Westeros || {}
Westeros.Castle = function(name) { this. name }; // constructor
Westeros.Castle.prototype.Build = function(){ console.log("Castle built: " + this.name) };

Of course, with JavaScript, there is more than one way to build the same code structure. An easy way to structure the preceding code is to make use of the ability to create and immediately execute a function :

var Castle = (function(){
	function Castle(name){
    	this.name = name;
    }
    Castle.prototype.Build = function(){
    	console.log("Castle built: " + this.name);
    }
    return Castle;
})();
Westros.Structures.Castle = Castle;

If we were to define a BaseStructure class which was to be in the ancestor of all structures, then making use of it would look like this:

var BaseStructure = (function(){
	function BaseStructure(){}
    return BaseStructure;
})();

Structures.BaseStructure = BaseStructure;

var Castle = (function(_super){
	__extends(Castle, _super);
    function Castle(name){
    	this.name = name;
        _super.call(this);
    }
    Castle.prototype.Build = function(){
    	console.log("Castle built: " + this.name);
    };
    return Castle;
})(BaseStructure); // Base structure is passed into the castle when the closure is evaluated.

 

__extends method is responsible for copying the functions over from the base prototype to the derived class. This particular piece of code was generated from a TypeScript compiler which also generated an extends method.

var __extends = this.__extends || function (d, b) {
	for (var p in b) if(b.hasOwnProperty(p) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
var Westeros;
(function (Westeros){
	(function(Structures){
    	var Castle = (function(){
        	function Castle(name){
            	this.name = name;
            }
            Castle.prototype.Build = function(){
 				console.log("Castle built " + this.name);           
            };
            return Castle;
        })();
        Structures.Castle = Castle;
        var Wall = (function(){
        	function Wall(){
            	console.log("Wall constructed");
            }
            return Wall;
        })();
        Structures.Wall = Wall;
        /*
        	Expose the class outside of the closure.
        */
    })(Westeros.Structures || (Westeros.Structures = {}));
    var Structures = Westeros.Structures;
})(Westeros || (Westeros = {}));

If we want to make private classes that are only available within the module, then we need to exclude only the line that exposes the class. This is actually known as the revealing module pattern. We only "reveal" the classes that need to be globally available.

 

ECMAScript 6 classes and modules

class Castle extends Westeros.Structures.BaseStructure {
	constructor(name, allegience){
    	super(name);
        // ...
    }
    Build(){
    	// ...
        super.Build();
    }
}
module 'Westeros' {
	export function Rule(rulerNmae, house){
    	//...
        return "Long live " + rulerName + " of house " + house;
    }
}
import westeros from 'Westeros';
module JSON from 'https://json.org/modules/json2.js'
westeros.Rule("Rob Stark", "Stark");

 

Summary

How to organize your code is a large part of the naming problem.

The primary concern with JavaScript is to avoid polluting the global namespace with a large number of similarly named, unconnected objects. Encapsulating JavaScript into modules is a key step on the road to writing maintainable and reusable code.

Prototype-based inheritance, which seems difficult at the onset, is a tremendous tool for aiding in the simplification of design patterns.

반응형