with acknowledgements to David Flannigan for his contribution: 'Javascript: The definitive Guide' by O'Reilly
this repository is basically a complex write-up on about 15 lexical features of Javascript; in my opinion, important features that everyone should be knowing
[TOC]
(function(ns){
var ns_parent = this;
var create = function(base, nsString){
if (arguments.length == 1) {
nsString = base; base = this;
}
base.ns_parent = ns_parent; ns_parent = base;
if (base != window && ! base.ns_create) base.ns_create = create
base.ns_apply_to = base.ns_run = exec
if (base != window && ! base.namespace) base.namespace = namespace;
var names = nsString.split('.'),name = names.shift();
if (name != '') return create(base[name] = ( base[name] || {} ), names.join('.'));
return base;
}
var exec = function(scope){
return scope.apply(this,Array.prototype.slice.apply(arguments,[1]));
}
var namespace = function(nsString,scope){
ns_parent = this;
space = create(this, nsString);
if (scope && scope.apply) return scope.apply(space, Array.prototype.slice.apply(arguments,[2]));
//else:
return space;
}
window[ns] = namespace
})('namespace')
I'm going to take this in secions, here we go ...
Namespacing in Javascript is pretty complicated. Since every type is a member-symbol of the global or 'window' scope, by default, just adding new types can create problems if namespacing isn't carefully managed. The common conception in Javascript is to use a style not-unlike python's modules system. In Javascript, the definitive guide, David Flanagan recommends using an internet namespace that you own, such as mine: new-life-tech.com, as the base namespace for new obejcts used by Javascript applications. Then, use the package name. for-example, the javascript designed FOR this tutorial should be in the namespace: com.github.mrgenixus.namespace_info. What this means, in-practice, is that objects must be initialized at each level of the tree.
window['com'] = window['com'] || {};
Above is the easiest, and possibly, best, way to inialize the root node. Each subsequent namespace should be defined similarly:
bn = window['com'] //base_namespace, renamed for convenience
bn = (bn.github = bn.github || {}); //initize child and reset base
bn = (bn.mrgenixus = bn.mrgenixus || {}); // wash, rinse repeat
bn.namespace_info = bn.namespace_info || {}; //instances com.github.mrgenixus.namespace_info
Once you're using namespaces, there are some changes to the basic javascript which allow greater flexibility. One method is to define new methods in their namespace:
com.github.mrgenixus.namespace_info.create_namespace = function(){ /* ... */ }
another is to use the apply and call syntaxes; I'll be covering that below.
(function(){ /* ... */ })();
This is a very common idiom in javascript with several benefits and otherwise, important uses
- The code inside this function can be isolated from other code
- Variables explicity declared in this scope will NOT clutter the global scope; specifically, closures may be considered a scope package: a closed loop for ceartain kinds of data;
var ns_parent /* ... */
Javascript handles scope in a very unique way: variables created in any scope, except when prefixed with 'var' are added to the global or 'window' scope; object properties are not new variables, so they are added to an objects scope; using 'var' in the global or 'window' scope is meaningless, but may be required by some interpretters
(function(){
var ns_parent = this;
var anon = function(){ /* ... */ };
})();
var ns_parent = this;
var namespace = function(nsString,scope){
ns_parent = this;
/* ... */
}
var create = function(base, nsString){
if (arguments.length == 1) {
nsString = base; base = this;
}
/* ... */
}
var create = function(base, nsString){ /* ... */}
if (arguments.length == 1) {
nsString = base; base = this;
}
if (scope && scope.apply) { /* ... */ }
if (arguments.length == 1) {
nsString = base; base = this;
}
return scope.apply(this,Array.prototype.slice.apply(arguments,[1]));
base.ns_parent = ns_parent;
var create;
base.ns_create = create
create = function(){
/* ... */
}
base.ns_create = create
base.ns_apply_to = base.ns_run = exec
var a,b = 4, c;
base[name] = ( base[name] || {} )
var create = function(base, nsString){
var names = nsString.split('.');
var name = names.shift();
if (name != '') return create(base[name] = ( base[name] || {} ), names.join('.'));
return base;
}
var namespace = function(nsString,scope){ /* ... */
(function() { /* ... */ }).apply(namespace,arguements); //simplified
(function() { /* ... */ }).call(namespace);
windows[ns] = namespace
window[ns] = namespace
(function(ns){ })('namespace');