I have a bunch of JavaScript prototypes inheriting from each other. Each class is defined in its own file like this. An example file looks like this:
goog.provide("app.classes.ClassA");
(function() {
app.classes.ClassA = function() {
// constructor
}
app.classes.ClassA.prototype.example = function() {
// example method
}
})();
A second file may look like this:
goog.provide("app.classes.ClassB");
goog.require("app.classes.ClassA");
(function() {
app.classes.ClassB = function() {
// constructor
}
goog.inherits(app.classes.ClassB, app.classes.ClassA);
app.classes.ClassB.prototype.example = function() {
// example method
}
})();
After running the compiler, the code specified in the first file looks like this:
goog.provide("app.classes.ClassA");
(function() {
a.classes.ClassA = function() {
// constructor
}
a.classes.ClassA.prototype.example = function() {
// example method
}
})();
'app' in ClassA has been replaced by a single 'a' and goog.inherits cannot find app.classes.ClassA because it is undefined.
How can I prevent the Closure Compiler from renaming namespaces like this?
Thanks!
Two ways, first you can annotate your external methods/variables/classes with #expose:
(function() {
/**
* #expose
*/
a.classes.ClassA = function() {
// constructor
}
a.classes.ClassA.prototype.example = function() {
// example method
}
})();
Or, you can disable optimizations when running the closure compiler:
java -jar ccompiler.jar --compilation_level WHITESPACE_ONLY ..
This code will rename object keys and still able to call functions with original key
// ==ClosureCompiler==
// #compilation_level ADVANCED_OPTIMIZATIONS
// #output_file_name default.js
// ==/ClosureCompiler==
var myClass = function() {
this["myFunc"] = this.myFunc;
this["myFunc2"] = this.myFunc2;
};
window["myClass"] = myClass;
myClass.prototype = {
myFunc: function() { alert("myFunc"); },
myFunc2: function() { alert("myFunc2"); }
};
compiled into
function a(){
this.myFunc=this.a;
this.myFunc2=this.b
}
window.myClass=a;
a.prototype={
a:function(){alert("myFunc")},
b:function(){alert("myFunc2")}
};
(new myClass()).myFunc() or (new a()).a() both work
However this method need to declare myFunc1,myFunc2...myFuncN too many time
Is it other way can achieve the same thing too?
I want to get this work with closure compiler to rename all myFunc into a (something like this)
In same script call myClass.myFunc() will compile into a.b()
But I still can call window.myClass.myFunc() in other scripts
Many thanks.
I want to access them on other scripts using window.myClass.myFunc
This suggests you want to set the property on window differently, i.e. the result of a new, for example
window.myClass = (function () { // make a closure with IIFE
function a() {
// if all you want is on the prototype, nothing to do here
}
a.prototype = { // set prototype
myFunc: function () {alert("myFunc")},
myFunc2: function () {alert("myFunc2")}
};
return new a(); // construct, return out of IIFE
}()); // Invoke IIFE
Now, window.myClass is a constructed Object with a prototype, and you can use
window.myClass.myFunc(); // alerts "myFunc"
If prototyping/inheritance is not important to you, you could simply do
window.myClass = { // set directly
myFunc: function () {alert("myFunc")},
myFunc2: function () {alert("myFunc2")}
};
If prototyping/inheritance is important to you but you don't need to construct and can assume a modern browser,
window.myClass = Object.create(
{ // prototype
myFunc: function () {alert("myFunc")},
myFunc2: function () {alert("myFunc2")}
}
);
(new myClass()).myFunc() should work :)
Anyway, you could also export your methods this way:
// ==ClosureCompiler==
// #output_file_name default.js
// #compilation_level ADVANCED_OPTIMIZATIONS
// ==/ClosureCompiler==
var myClass = function() {
//don't declare your exports here
};
myClass.prototype["myFunc"] = function() { alert("myFunc"); };
myClass.prototype["myFunc2"] = function() { alert("myFunc2"); };
window['myClass'] = myClass;
This is a bit less error prone, since you don't have to remember to "initialize" all the method names.
It compiles to:
function a() {
}
a.prototype.myFunc = function() {
alert("myFunc");
};
a.prototype.myFunc2 = function() {
alert("myFunc2");
};
window.myClass = a;
I've been using the module pattern for a while, but recently have started wanting to mix in functions and properties into them to increase code re-use. I've read some good resources on the subject, but still am a bit uncertain as to the best approach. Here is a module:
var myModule = function () {
var privateConfigVar = "Private!";
//"constructor"
function module() {}
module.publicMethod = function () {
console.log('public');
}
function privateMethod1() {
console.log('private');
}
return module;
}
And here is a mixin object:
var myMixin = function () {};
Mixin.prototype = {
mixinMethod1: function () {
console.log('mixin private 1');
},
mixinMethod2: function () {
console.log('mixin private 2');
}
};
Ideally, I'd like to mix-in some methods from other objects as private methods and some as public methods, so that I could call some "extend" function, with a param as "private"/"public". So, that
mixin(myModule, myMixin, "private");
makes the myMixin methods available within myModule by just calling mixinMethod1() and have correct scope, and:
mixin(myModule, myMixin, "public");
makes the myMixin methods available within myModule by calling module.mixinMethod1() and have correct scope
I've tried using a method that copies properties from one prototype to another, I've tried the underscore extend method to copy properties of the object from one to to the other, and various things in between. I think I'm a bit turned around regarding scope and prototypes at this point, and would love some direction as to how best to do mixins like this when using the module pattern. Note that it doesn't matter what the object myMixin looks like (whether adding functions to the prototype, or a module itself), I'm just trying to figure out some way to make it work.
Thank!
So that [some code] makes the myMixin methods available within myModule by just calling mixinMethod1() and have correct scope
That's impossible. You cannot modify a scope by calling a function, especially not from outside. See also Is it possible to import variables in JavaScript? for the design reasons of that.
So, what can you do?
From outside the module
Nothing to the private scope(s) of module functions. And you cannot use the private functions of the module, obviously. You can extend its prototype with methods (which is the most common), you can even decorate its constructor function. Within those, you can use your own private functions, either completely static ones or class-specific ones.
var myMixin = (function() {
// everything class-unspecific but mixin-local
var staticMixinVariables, …;
function globalPrivateFunction(){…}
function staticMethod(){…}
return function(mod) {
// everything class-specific
// also using the locals from above
mod.staticHelper = function() { staticMixinVariable … };
mod.prototype.mixinMethod1 = staticMethod;
mod.prototype.mixinMethod2 = function(){…};
…
};
})();
// Example:
myMixin(SomeClass)
From within the module
Using the mixin in the module code itself can allow for much greater flexibility.
var myMixin = (function() {
// everything class-unspecific but mixin-local
…
return {
publicHelper1: function(){…},
publicHelper2: function(){…},
decorateInstance: function(o) {
o.xy = …;
},
extendPrototype: function(proto) {
// everything class-specific
// also using the locals from above
proto.mixinMethod1 = staticMethod;
proto.mixinMethod2 = function(){…};
…
}
};
})();
With such an interface, it becomes easy to construct a class that is using this as a mixin (not inheriting from it):
var myClass = (function() {
function Constructor() {
myMixin.decorateInstance(this);
…
}
Constructor.prototype.method1 = function() { myMixin.publicHelper1() … };
Constructor.prototype.method2 = function() { … };
myMixin.extendPrototype(Constructor.prototype);
Constructor.myHelper = myMixin.publicHelper2; // re-export explicitly
return Constructor;
})();
However, the mixin will never have access to the private class variables, nor can it present a private, class-specific API. Still, we can use dependency injection to provide that access explicitly (and having a mixin factory in effect):
var myClass = (function() {
var … // private class functions and variables
var mixer = myMixin(privateClassHelper,
privateClassVariable,
function setPrivateVar(x) {…},
… );
var myHelper = mixer.customHelper, … // local "aliases"
function Constructor(localX) {
mixer.decorateInstance(this, localX);
…
}
… // further using the class-specific private mixer
return Constructor;
})();
Not all techniques shown above need to be used in every mixin, just choose the ones you need. Not all possible techniques are shown in the above examples, also :-) The mixin pattern can be applied onto a plain module or inside its declaration as well, the above examples have only shown classes with prototypes.
For a few good examples, and a theoretical distinction between (stateless) Traits, (stateful) Mixins and their "privileged" counterparts, have a look at this presentation.
The with keyword can be very usefull to define a scope, but it has also some drawbacks (it is by the way forbidden in strict mode).
Using the with keyword, you can define a private variable privateScope within the body of your module, that would contain all your provate methods :
var myModule = function () {
var privateConfigVar = "Private!";
var privateScope = {};
//"constructor"
function module() {}
var proto = module.prototype;//avoids multiple attribute lookup
//Let's re-define you example' private method, but with a new strategy
privateScope['privateMethod1'] = function() {
console.log('private');
}
proto.publicMethod = function () {
with(privateScope){
//this call should work
privateMethod1();
}
console.log('public');
}
proto.publicMethod2=function(name,fn){
with(privateScope){
//this will be defined later by a Mixin
otherPrivateMethod();
}
console.log('public2');
}
proto.definePrivateFunction=function(name,fn){
privateScope[name] = fn;
}
return module;
}
Your mixin will use the definePrivateFunction we just defined to add private methods to the private scope :
//An example mixin implementation
function Mixin(source,target,flag){
if(flag==="private"){
for(var currentMethodName in source){
target.definePrivateFunction(currentMethodName,source[currentMethod])
}
}else{
for(var currentMethodName in source){
target[currentMethodName]=source[currentMethod];
}
}
}
The following code should work fine:
var test = myModule();
var testInstance = new test();
testInstance.publicMethod();// will call the private method defined internally
Mixin({
otherPrivateMethod:function(){
console.log("other Prvate Method called")
}
},test.prototype,"private");
testInstance.publicMethod2();// will call the private method defined by the mixin
Ideally, I'd like to mix-in some methods from other objects as private methods and some as public methods, so that I could call some "extend" function, with a param as "private"/"public". ...
As it already has been mentioned, there is no way of achieving exactly this goal.
So, that ... makes the myMixin methods available within myModule by just calling mixinMethod1() and have correct scope, and: ... makes the myMixin methods available within myModule by calling module.mixinMethod1() and have correct scope.
And referring to scope ... this is a closed address space created by functions.
Except for closures, scope only is available during a function's runtime
within this function's body. It never ever can be manipulated/spoofed.
The term one is looking for is context. JavaScript, being in many ways highly
dynamic, is build upon late binding (the object/target/context a method is called
on gets evaluated/looked up at runtime) and two kinds of delegation.
Context gets delegated either automatically by "walking the prototype chain"
or explicitly by one of both call methods which every function object does provide
- either call or apply.
Thus JavaScript already at language core level does offer a function based
Mixin pattern that is mightier than any of the available extend(s) or mixin
implementations for it provides delegation for free and is able of passing
around state which almost every of the blamed helpers does lack unless there
was effort of implementing this feature again in a rather roundabout fashion
(or ass-backwards to put it bluntly).
Bergi for his explanation already earned the bounties.
Within his answer's last paragraph there is a link to resources of mine that
already got outdated 3 month after giving the referred talk. Due of not having
enough reputation points, I'm not able to comment his answer directly. For this
I'll take the chance pointing now to the latest state of my personal research and
understanding of »The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins«
Back again answering the OP's question.
I'm going to change the two first given code examples from the assumed module pattern
and the rather exemplarily provided mixin code base towards a plain constructor function
and what I'm meanwhile tempted to call a "proxified" and/or "bicontextual" mixin in order
to boil down the mechanics of delegating two different target/context objects at once.
Thus demonstrating a pure function based mixin pattern that might come closest to what
the OP tries to achieve.
var MyBicontextualMixin = function (localProxy) {
localProxy.proxifiedAccessible = function () {
console.log("proxified accessible.");
};
this.publiclyAccessible = function () {
console.log("publicly accessible.");
};
};
var MyConstructor = function () {
var localProxy = {};
MyBicontextualMixin.call(this, localProxy);
var locallyAccessible = localProxy.proxifiedAccessible;
// call 'em
locallyAccessible(); // "proxified accessible."
this.publiclyAccessible(); // "publicly accessible."
};
(new MyConstructor);
// will log:
//
// proxified accessible.
// publicly accessible.
This special pattern also is the underlying base for composing pure
function based Traits that rely on conflict resolution functionality
provided by "proxified" Mixins that won't expose this functionality
into public.
And for not ending up that theoretical there will be a "real world example",
composing a Queue module out of various reusable mixins that entirely
worship the approach of DRY. It also should answer the OP's question about
how to achieve encapsulation and exposition build only upon the module
pattern and function based mixin composition.
var Enumerable_first_last_item = (function (global) {
var
parseFloat = global.parseFloat,
math_floor = global.Math.floor,
// shared code.
first = function () {
return this[0];
},
last = function () {
return this[this.length - 1];
},
item = function (idx) {
return this[math_floor(parseFloat(idx, 10))];
}
;
return function () { // [Enumerable_first_last_item] Mixin.
var enumerable = this;
enumerable.first = first;
enumerable.last = last;
enumerable.item = item;
};
}(window || this));
var Enumerable_first_last_item_proxified = function (list) {
Enumerable_first_last_item.call(list);
// implementing the proxified / bicontextual [Enumerable_first_last_item] Mixin.
var enumerable = this;
enumerable.first = function () {
return list.first();
};
enumerable.last = function () {
return list.last();
};
enumerable.item = function (idx) {
return list.item(idx);
};
};
var Allocable = (function (Array) {
var
array_from = ((typeof Array.from == "function") && Array.from) || (function (array_prototype_slice) {
return function (listType) {
return array_prototype_slice.call(listType);
};
}(Array.prototype.slice))
;
return function (list) { // proxified / bicontextual [Allocable] Mixin.
var
allocable = this
;
allocable.valueOf = allocable.toArray = function () {
return array_from(list);
};
allocable.toString = function () {
return ("" + list);
};
allocable.size = function () {
return list.length;
};
Enumerable_first_last_item_proxified.call(allocable, list);
};
}(Array));
var Queue = (function () { // [Queue] Module.
var
onEnqueue = function (queue, type) {
//queue.dispatchEvent({type: "enqueue", item: type});
},
onDequeue = function (queue, type) {
//queue.dispatchEvent({type: "dequeue", item: type});
}/*,
onEmpty = function (queue) {
//queue.dispatchEvent({type: "empty"});
}*/,
onEmpty = function (queue) {
//queue.dispatchEvent("empty");
},
Queue = function () { // [Queue] Constructor.
var
queue = this,
list = []
;
queue.enqueue = function (type) {
list.push(type);
onEnqueue(queue, type);
return type;
};
queue.dequeue = function () {
var type = list.shift();
onDequeue(queue, type);
(list.length || onEmpty(queue));
return type;
};
//Observable.call(queue); // applying the [Observable] Mixin.
Allocable.call(queue, list); // applying the bicontextual [Allocable] Mixin.
},
isQueue = function (type) {
return !!(type && (type instanceof Queue));
},
createQueue = function () { // [Queue] Factory.
return (new Queue);
}
;
return { // [Queue] Module.
isQueue : isQueue,
create : createQueue
};
}());
var q = Queue.create();
//q.addEventListener("enqueue", function (evt) {/* ... */});
//q.addEventListener("dequeue", function (evt) {/* ... */});
//q.addEventListener("empty", function (evt) {/* ... */});
console.log("q : ", q); // { .., .., .., }
console.log("q.size() : ", q.size()); // 0
console.log("q.valueOf() : ", q.valueOf()); // []
"the quick brown fox jumped over the lazy dog".split(/\s+/).forEach(function (elm/*, idx, arr*/) {
console.log("q.enqueue(\"" + elm + "\")", q.enqueue(elm));
});
console.log("q.size() : ", q.size()); // 9
console.log("q.toArray() : ", q.toArray()); // [ .., .., .., ]
console.log("q.first() : ", q.first()); // "the"
console.log("q.last() : ", q.last()); // "dog"
console.log("q.item(2) : ", q.item(2)); // "brown"
console.log("q.item(5) : ", q.item(5)); // "over"
console.log("q.dequeue()", q.dequeue()); // "the"
console.log("q.dequeue()", q.dequeue()); // "quick"
console.log("q.dequeue()", q.dequeue()); // "brown"
console.log("q.dequeue()", q.dequeue()); // "fox"
console.log("q.dequeue()", q.dequeue()); // "jumped"
console.log("q.size() : ", q.size()); // 4
console.log("q.toArray() : ", q.toArray()); // [ .., .., .., ]
console.log("q.first() : ", q.first()); // "over"
console.log("q.last() : ", q.last()); // "dog"
console.log("q.item(2) : ", q.item(2)); // "lazy"
console.log("q.item(5) : ", q.item(5)); // undefined
.as-console-wrapper { max-height: 100%!important; top: 0; }
I am having trouble getting this code structure to survive obfuscation with the Google Closure Compiler. Here's some sample code:
var MyModule = (function()
{
function myModule()
{
// Constructor
}
function moduleFoo(url)
{
// Method
}
function moduleBar()
{
// Method
}
myModule.prototype = {
constructor: myModule,
foo: moduleFoo,
bar: moduleBar
};
return myModule;
})();
Elsewhere in my code I need be able to write things like the following:
var myMod = new MyModule();
myMod.foo();
myMod.bar();
However the compiler is renaming everything (as expected). How can I make the prototype that I have defined available elsewhere in my code after obfuscation? I have tried exporting as follows:
// In place of the prototype object above
myModule.prototype['constructor'] = myModule;
myModule.prototype['foo'] = moduleFoo;
myModule.prototype['bar'] = moduleBar;
window['myModule'] = myModule;
But things seem to break down either when the prototype methods are called or when their corresponding closures are executed.
Any help is appreciated.
This exact pattern does not work well with Closure-compiler using ADVANCED_OPTIMIZATIONS. Instead, you will need to slightly refactor your code:
/** #constructor */
function MyModule()
{
// Constructor
}
(function() {
function moduleFoo(url)
{
// Problem using "this" keyword. Will require #this annotation.
}
MyModule.prototype = {
foo: moduleFoo
};
MyModule.prototype.bar = function() {
// "this" keyword works fine.
};
})();
Or like:
/** #const */
var MyNamespace = {};
(function() {
/** #constructor */
MyNamespace.MyModule = function() {};
MyNamespace.MyModule.prototype = {
constructor: function() {},
foo: function(url) {},
bar: function() {}
};
})();
With either of the above methods your exports should work correctly.
Note: The second option will only work with a compiler built from the latest source as it involves a bug that was just fixed last week.
Let's say I made use of the following module-kind pattern in JavaScript:
var myModule = (function () {
var Foo = function () { /* ... */ };
var Bar = function () {
this.foo = new Foo();
};
Bar.prototype.someMethod = function () {
this.foo.someMethod();
};
return {
'Bar': Bar
};
})();
Is it advisable and if yes - how can I expose Foo for unit testing? Is there some common technique or pattern for doing this?
I don't think you should really need to unit test the private members. As long as you have comprehensive tests on the public members, any errors within the private members will manifest themselves as errors on the public members. You can then use good ol' debugging to find out what the exact problem was.
Alternatively, if you have your tests run on a separate build to production, you could expose the enclosing object, and test against that. You'd need to remember to remove the reference to the enclosing object before deployment - or you could automate it somehow. Honestly though, I generally wouldn't bother removing it, unless you're packaging a library for public consumption.
var myModule = (function () {
var _this = this;
var Foo = function () { /* ... */ };
var Bar = function () {
this.foo = new Foo();
};
Bar.prototype.someMethod = function () {
this.foo.someMethod();
};
return {
'Bar': Bar,
'__private__': _this
};
})();
function test_foo(obj) {
var foo = obj.__private__.Foo;
assert(foo.prop, 10)
}
For an inhouse system, being able to access the private data/functions is usually a non-issue, if it is clearly understood that accessing private members should not be done. This is highlighted by providing a reference to the enclosing object with a name like __private__. (Can you tell I'm kinda into Python? ;) )