views:

302

answers:

5

I recently made my own Javascript library and I initially used the following pattern:

var myLibrary = (function () {

  var someProp = "...";

  function someFunc() {
    ...
  }

  function someFunc2() {
    ...
  }

  return {
     func: someFunc,
     fun2: someFunc2,
     prop: someProp;
  }

}());

The problem with this is that I can't really use code completion because the IDE doesn't know about the properties that the function literal is returning (I'm using IntelliJ IDEA 9 by the way).

I've looked at jQuery code and tried to do this:

(function(window, undefined) {
    var myLibrary = (function () {

      var someProp = "...";

      function someFunc() {
        ...
      }

      function someFunc2() {
        ...
      }

      return {
         func: someFunc,
         fun2: someFunc2,
         prop: someProp;
      }

    }());

    window.myLibrary = myLibrary;
}(window));

I tried this, but now I have a different problem. The IDE doesn't really pick up on myLibrary either.

The way I'm solving the problem now is this way:

var myLibrary = {
   func: function() { },
   func2: function() { },
   prop: ""
};

myLibrary = (function () {

  var someProp = "...";

  function someFunc() {
    ...
  }

  function someFunc2() {
    ...
  }

  return {
     func: someFunc,
     fun2: someFunc2,
     prop: someProp;
  }

}());

But that seems kinda clunky, and I can't exactly figure out how jQuery is doing it. Another question I have is how to handle functions with arbitrary numbers of parameters.

For example, jQuery.bind can take 2 or 3 parameters, and the IDE doesn't seem to complain. I tried to do the same thing with my library, where a function could take 0 arguments or 1 argument. However, the IDE complains and warns that the correct number of parameters aren't being sent in. How do I handle this?

EDIT

I'm starting to wonder if this is an Idea9 issue because jQuery has the same problem. I don't seem to have this problem in other projects though.

+2  A: 

I'm using IDEA with yahoo module pattern and my autocomplete works. Google for yahoo module pattern.

http://www.yuiblog.com/blog/2007/06/12/module-pattern/

http://ajaxian.com/archives/a-javascript-module-pattern


TEST = function() {
    var SOME_CONSTANT='asd';

    function privateStuff(){
        var a = 'asd';
        return a;
    }

    return{
        someArray:[],

        someMethod: function(foo, bar){

            var foo = *1
        }
        ,

        myProperty:'test'
    }
}();

TEST.*2

with *1 and *2 i marked places where i tried auto complete.

in *1 i get SOME_CONSTANT and privateStuff method, and if i put this.(autocomplete) i get access to all the methods and properties inside of return {} block

when i try autocomplete on *2 i get all the methods and properties inside return {} block. SOME_CONSTANT and privateStuff method are invisibile there, because they are "private".

For me that level of autocomplete is quite fine.

kodisha
The OPs code sample is already using the module pattern.
Crescent Fresh
i really didn't see his return {} blocks :). I edited my answer.
kodisha
Doesn't solve my problem (which might be an idea issue), but it generally answers my question! :)
Vivin Paliath
A: 

I recommend that you don't use private variables, but I understand you want them hidden from the intellisense. This is how I would do it:

(function(){
    var privateVar = "shhhh!";
    var privateMethod = function(){}


    myLibray = {
        prop:42,
        foo: function(){
            return privateMethod()
        },
        bar: function(){
            return privateVar;
        }
    }

})();

This way you can have your private stuff in a closure and your library should be accessible.

[ edited. I clumsily did not include myLibrary in the anonymous function and it could not see the private vars. oops. ]

BTW, my reasons for private variables being bad: http://clubajax.org/javascript-private-variables-are-evil/

mwilcox
Does this work? Won't the local vars in the closure be out of scope after?
Zack Mulgrew
I'm not sure how this would work. `privateVar` and `privateMethod` will not be accessible to `myLibrary`, would they?
Vivin Paliath
This won't work. `privateVar` and `privateMethod` will be in their own little world; nothing will be able to access them.
Matt
+1  A: 

I think will be great if you read something about Douglas Crockford. He is THE architect in yahou YUI framework. And after that you can have a better idea to how build a great framework. And for the parameter there are 2 options. 1.- send via object example

{ option :{ var1 : "value" , var2:"value"}, var3 : "value" }

And the you can check if the option exist.

The second one not to great is check if the parameter is undefined.

function foo(var1,var2){
   var var1_this = null;
     if(var1 != undefined)
      var1_this = var1;
}

and just a comment why build a new javascript framework? use Prototype, JQuery, Mootols, YUI. why reinventing the wheel?

nahum silva
Probably to learn. That is when reinventing the wheel is okay.
Hugo Estrada
also dont forget that your app should only use Prototype, jQ and stuff for low level stuff, if you are writing new, lets say visualization framework, you should use Prototype as your base framework, and all the charts and stuff should be in another FW which is built on top of of Prototype, jQ, etc...
kodisha
Yeah, I'm not trying to re-invent the wheel as far as jQuery or Prototype goes. I was working on a validation framework.
Vivin Paliath
A: 

I write my libraries like this:

function MyLibrary() {
    // code
}
MyLibrary.prototype.memberFunc = function() {
    // code
}
MyLibrary.prototype.memberVar = 5;

new MyLibrary();

This way, in Geany (which uses CTAGS) MyLibrary is well recognized (for the most part, for example, memberVar is recognized as a function) and autocompletion seems to work. I don't know about IDEA9, but you could try it this way (I have a hunch it's a bit more evolved than CTAGS).

Felix
I've seen this pattern as well. Are there any advantages to this method over the singleton pattern?
Vivin Paliath
Being able to use multiple instances of the same object? :) Also, code is a lot more readable IMO.
Felix
Of course :) I'm wondering if it would make sense for me to have multiple instances in this case! I'll keep working at this to figure out what's happening.
Vivin Paliath
+1  A: 

This is in reply to the comments to mwilcox's post.

That example will actually work. Since myLibrary is defined without var, it is automatically put into the global namespace and accessible as such. Through the closure created by the self-executing function, the private variables and methods are still accessible in the myLibrary methods. You can easily try this out by putting it into Firebug or Rhino.

These days, I do not tend to hide my variables, i.e. I use the Pseudoclassical pattern or the Prototypal pattern and prefix my intended private methods with an _:

// Pseudoclassical pattern
function Hello() {}
Hello.prototype = {
    method1: function() {},
    method2: function() {},
    _pseudeoPrivate: function() {}
};

/* Prototypal pattern. To create multiple instances of this object,
   you need a helper function such as
    function beget(o) {
        var F = function() {};
        F.prototype = o;
        return new F;
    }
    var instance = beget(world);
*/
var world = {
    method1: function() {},
    method2: function() {}
};

To prevent my code from polluting the global namespace, I have a build process that wraps my modules in a closure and exports the public api to the namespace. This technique is also used by jQuery. You can see that in their source code (look at intro.js & outro.js) on Github.

This would allow you to use a pattern that allows your IDE (or ctags with vim) to see your api, whilst also preventing the pollution of the global namespace.

elduderino78