I am trying to implement nested namespaces using the modules pattern with anonymous functions and closure. I am missing something when it comes to changes in state variables. For example, here is a simple set of nested namespaces:
// namespace 1
var first = (function(){
'use strict';
var v = 1;
function method(){
console.log("method 1: " + v);
}
// namespace 2
var second = (function(){
var v = 2;
function method(){
console.log("method 2: " + v);
}
// namespace 3
var third = (function(){
var v = 3;
function method(){
console.log("method 3: " + v);
}
return {
v: v,
method: method
};
})();
return {
third: third,
v: v,
method: method
};
})();
return {
second: second,
v: v,
method: method
};
})();
first.method();
first.v = 4;
first.method();
first.second.method();
first.second.third.method();
This results in the following output:
"method 1: 1"
"method 1: 1"
"method 2: 2"
"method 3: 3"
Why doesn't the change to first.v stick?
UPDATE: So, I see now why this wasn't working based on feedback. I have now switched over to using object literals. I am still trying to find the best approach to nested namespaces and scoping. Here is my new version of the above code:
var first = {
v: 1,
method: function (){
console.log("method 1: " + this.v);
},
second: {
v: 2,
method: function (){
console.log("method 2: " + this.v);
},
third: {
v: 3,
method: function (){
console.log("method 3: " + this.v);
}
}
}
}
first.method();
first.v = 4;
first.method();
first.second.method();
first.second.third.method();
Namespaces aren't created by nesting functions. They are created by creating new properties on an existing object and then attaching new members to those properties:
(function(){
// Just create members of the instance as normal
// No nesting here. Within a function variables are
// private, but "this" properties are available
// and can persist state.
this.foo = function(){console.log("foo"); };
this.bar = function(){console.log("bar")};
this.baz = function(){console.log("baz")};
this.x = 42;
// We can't change the state of the above variable directly
// but we can create a function that works with that value
// and modifies it.
this.changeX = function(n){
this.x += n;
};
// If we create a new property on the Global object
// that is an empty object, we'll be essentially
// creating a namespace to be accessed from the Global object
window.namespace = {};
// Then, create new properties on that object, which point
// to state or behavior that you want to expose in the namespace
window.namespace.foo = foo;
window.namespace.bar = bar;
window.namespace.x = x;
window.namespace.changeX = changeX;
// And to create nested namespaces, repeat by adding a new empty
// object as a new property of the current namespace.
window.namespace.ns2 = {};
// And then associate internal state or behavior with that namespace
window.namespace.ns2.baz = baz;
})();
// Since our namespace is attached to the Global object (window),
// we don't have to fully qualify it with window and can just
// access the namespace directly.
namespace.foo();
namespace.bar();
namespace.ns2.baz();
console.log(namespace.x); // 42
namespace.changeX(-10);
console.log(namespace.x); // 32