2

JavaScript Concatenator

I'm considering writing a JavaScript library to achieve Data Hiding under Modularization. I hope to get some inputs on whether this will be useful and what are the potential problems.

Let's me explain the problem first. What I'm trying to achieve are these:

Data Hiding

What I mean by data hiding is this kind of pattern:

!function(context) {
    var privateObj = {state: 'normal'};
    var privateFunc = function() {alert("I'm private")};

    var toggleState = function() {privateObj.state = 'emergency'};
}(window.myNamespace);

Here, curious users will not be able to change my private variables nor invoke my private functions.

Modularization

The above works as long as everything is in one js file. But once the js file becomes too big that I would like to modularize:

first.js:

!function(context) {
    var privateObj = {state: 'normal'};
    var privateFunc = function() {alert("I'm private")};
}(window.myNamespace);  

second.js:

!function(context) {
    // This won't work. I can't access privateObj as we are not in same closure
    var toggleState = function() {privateObj.state = 'emergency'};
}(window.myNamespace2);   

It won't work anymore. Sure I can put toggleState together with privateObj but there are always the need to communicate data across modules. This is just an illustration.

Is this a real problem?

Are there really cases when we want a function to be accessible by other modules but not accessible by the public? I think yes. A straight forward example is this:

var chartDrawingMod = function() {
    var drawChart = function(data) {// draw chart with data};
}; 

In this case, we should all agree that

  1. Chart-related stuff should be cohesive module in itself

  2. The method drawChart() should be invoked by my code in other modules to provide the data

  3. We don't want the user to arbiturarily invoke my drawChart() therefore it's not desirable to make it public

The MathJax project encountered this problem. Their solution is to use a bash script to concatenate all scripts before deploy. The reason they need to do this is that first the modules are inter-dependent so they need to be inside the same file, and second the file is simply too huge to managed if combined (30k LOC). Exactly the same issue here, so I believe this is a real problem.

Proposed solution- JS Concatenator

Put them in one closure, on the fly.

Here's how I imagine it should work. In HTML I have these:

<script src="concatenator.js"></script>
<script>
    Concat.concateIntoOneClosureWithContext(['/public/js/first.js', '/public/js/second.js'], window.myNamespace);
</script>

Then it should do something like this:

!function(context) {
    // dump the content of '/public/js/first.js'
    // dump the content of '/public/js/second.js'
}(window.myNamespace);

And first.js and second.js are stripped down to:

var privateObj = {state: 'normal'};
var privateFunc = function() {alert("I'm private")};

var toggleState = function() {privateObj.state = 'emergency'};

Will this work?

Will this proposed solution work? Am I missing out some important points? What are potential problems? How may I go about implementing it? Any suggestion is much appreciated!

Boyang
  • 2,520
  • 5
  • 31
  • 49
  • I don't see any benefits/differences to e.g. AMD or require.js. Private methods should stay private and not be called from other classes (that use case means that the method should be exposed). It would be a lot easier to simple emit events where necessary and handle those werever you need it instead of merging files in a common closure. – nietonfir Apr 30 '14 at 16:07
  • @nietonfir Private variables should stay private to the outside world but it should be accessible by my own code. Once it's splited even myself can't access it. – Boyang Apr 30 '14 at 16:10
  • But then your architectural decisions are wrong imho and you should definitely retink them. A private variable should only be accessed by its owning class (and there's no need to split that up) and not its e.g. parent module. You should strive for high cohesion and low coupling. In JS the most straight-forward way (currently afaik) are events. – nietonfir Apr 30 '14 at 16:14
  • @nietonfir I feel that `protected` variables are similar to what I want, and it's present in most OOP languages. A variable might be needed by child class, but can't be public at the same time. – Boyang Apr 30 '14 at 16:21
  • Have you looked into e.g. [Backgone](http://backbonejs.org/) or other libraries that provide inheritance? – nietonfir Apr 30 '14 at 16:35
  • A more straight forward example is this: `var chartDrawingMod = function() {var drawChart = function(data) {// draw chart with data};}` In this case, we should all agree that 1. This is a cohesive module in itself 2. The method drawChart() should be invoked by my code in other modules 3. We don't want the user to arbiturarily invoke my drawChart() therefore it's not desirable to make it public – Boyang Apr 30 '14 at 16:36
  • Well, your example (and therefore your problem?) is already solved imho, just look at e.g. [jQuery](https://github.com/jquery/jquery). Don't you think that requirejs together with grunt would do just fine for your use case? – nietonfir Apr 30 '14 at 17:02

0 Answers0