Writing a Javascript library that is code-completion and code-inspection friendly - javascript

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.

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.

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?

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.

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).

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/

Related

How to create a JavaScript "class" that adds methods to prototype AND uses 'this' correctly [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 8 years ago.
I've always been taught the correct way to simulate a class in JavaScript is by adding methods to the prototype outside the function that will be your class, like this:
function myClass()
{
this.myProp = "foo";
}
myClass.prototype.myMethod = function()
{
console.log(this);
}
myObj = new myClass();
myObj.myMethod();
I've been running into the issue that the this in my methods resolves to the global Window object, as explained best on quirksmode.
I've tried doing the var that = this; trick Koch mentions, but since my methods are outside my class, my that variable is no longer in scope. Perhaps I'm just not understanding it completely.
Is there a way I can create a class in JavaScript where methods are not recreated each implementation and this will always point to the object?
EDIT:
The simplified code above works but I've had many times where I declare a "class" exactly like above and when I call myObj.myMethod(), it comes back as a Window object. I've read over every explanation of this that I could find, such as the one I linked to and still don't understand why this problem sometimes happens. Any idea of a situation where the code could be written like above and this would refer to Window?
Here's the implementation I'm currently having problems with, but when I simplify it down like above into a few lines, I no longer have the problem:
HTML File:
<script type="text/javascript" src="./scripts/class.Database.js"></script>
<script type="text/javascript" src="./scripts/class.ServerFunctionWrapper.js"></script>
<script type="text/javascript" src="./scripts/class.DataUnifier.js"></script>
<script type="text/javascript" src="./scripts/main.js"></script>
class.DataUnifier.js:
function DataUnifier()
{
this._local = new Database();
this._server = new ServerFunctionWrapper();
this.autoUpdateIntervalObj = null;
}
DataUnifier.prototype.getUpdates = function()
{
this._server.getUpdates(updateCommands)
{
console.log(updateCommands);
if (updateCommands)
{
executeUpdates(updateCommands);
}
}
}
//interval is in seconds
DataUnifier.prototype.startAutoUpdating = function(interval)
{
this.stopAutoUpdating();
this.autoUpdateIntervalObj = setInterval(this.getUpdates,interval * 1000);
}
DataUnifier.prototype.stopAutoUpdating = function()
{
if (this.autoUpdateIntervalObj !== null)
{
clearInterval(this.autoUpdateIntervalObj);
this.autoUpdateIntervalObj = null;
}
}
main.js
var dataObj = new DataUnifier();
$(document).ready(function ev_document_ready() {
dataObj.startAutoUpdating(5);
}
I've cut out some code that shouldn't matter but maybe it does. When the page loads and dataObj.startAutoUpdating(5) is called, it breaks at the this.stopAutoUpdating(); line because this refers to the Window object. As far as I can see (and according to the link provided), this should refer to the DataUnifier object. I have read many sources on the this keyword and don't understand why I keep running into this problem. I do not use inline event registration. Is there any reason code formatted like this would have this problem?
EDIT 2: For those with similar issues, see "The this problem" half way down the page in this Mozilla docs page: http://developer.mozilla.org/en-US/docs/Web/API/Window.setInterval
My favorite way of defining classes is as follows:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
Using the defclass function you can define MyClass as follows:
var MyClass = defclass({
constructor: function () {
this.myProp = "foo";
},
myMethod: function () {
console.log(this.myProp);
}
});
BTW your actual problem is not with classes. It's the way you're calling this.getUpdates from setTimeout:
this.autoUpdateIntervalObj = setInterval(this.getUpdates, interval * 1000);
Instead it should be:
this.autoUpdateIntervalObj = setInterval(function (self) {
return self.getUpdates();
}, 1000 * interval, this);
Hence your DataUnifier class can be written as:
var DataUnifier = defclass({
constructor: function () {
this._local = new Database;
this._server = new ServerFunctionWrapper;
this.autoUpdateIntervalObj = null;
},
getUpdates: function () {
this._server.getUpdates(function (updateCommands) {
console.log(updateCommands);
if (updateCommands) executeUpdates(updateCommands);
});
},
startAutoUpdating: function (interval) {
this.stopAutoUpdating();
this.autoUpdateIntervalObj = setInterval(function (self) {
return self.getUpdates();
}, 1000 * interval, this);
},
stopAutoUpdating: function () {
if (this.autoUpdateIntervalObj !== null) {
clearInterval(this.autoUpdateIntervalObj);
this.autoUpdateIntervalObj = null;
}
}
});
Succinct isn't it? If you need inheritance then take a look at augment.
Edit: As pointed out in the comments passing additional parameters to setTimeout or setInterval doesn't work in Internet Explorer versions lesser than 9. The following shim can be used to fix this problem:
<!--[if lt IE 9]>
<script>
(function (f) {
window.setTimeout = f(window.setTimeout);
window.setInterval = f(window.setInterval);
})(function (f) {
return function (c, t) {
var a = [].slice.call(arguments, 2);
return f(function () {
c.apply(this, a);
}, t);
};
});
</script>
<![endif]-->
Since the code is only executed conditionally on Internet Explorer versions lesser than 9 it is completely unobtrusive. Just include it before all your other scripts and your code will work on every browser.
The Answer
The problem is not with this.stopAutoUpdating();, it is with:
setInterval(this.getUpdates, interval * 1000);
When you pass a function like this to setInterval it will be called from the event loop, with no knowledge of the this you have here. Note that this has nothing to do with how a function is defined, and everything to do with how it is called. You can get around it by passing in an anonymous function:
var self = this;
setInterval(function(){ self.getUpdates(); }, interval * 1000);
In any modern engine you can use the much nicer bind:
setInterval(this.getUpdates.bind(this), interval * 1000);
You can also use bind in older engines if you shim it first.
Understanding the Problem
I recommend that you read about call and apply for a better understanding.
Note that when you call a function normally, without using bind, call, or apply, then the this will just be set to whichever object context the function was called from (that is, whatever comes before the .).
Hopefully this helps you understand what I said about this not being about how the function is defined, rather how it is called. Here is an example, where you might not expect this to work, but it does:
// This function is not defined as part of any object
function some_func() {
return this.foo;
}
some_func(); // undefined (window.foo or an error in strict mode)
var obj = {foo: 'bar'};
// But when called from `obj`'s context `this` will refer to obj:
some_func.call(obj); // 'bar'
obj.getX = some_func;
obj.getX(); // 'bar'
An example where you might expect it to work, but it doesn't, along with a couple solutions to make it work again:
function FooBar() {
this.foo = 'bar';
}
FooBar.prototype.getFoo = function() {
return this.foo;
}
var fb = new FooBar;
fb.getFoo(); // 'bar'
var getFoo = fb.getFoo;
// getFoo is the correct function, but we're calling it without context
// this is what happened when you passed this.getUpdates to setInterval
getFoo(); // undefined (window.foo or an error in strict mode)
getFoo.call(fb); // bar'
getFoo = getFoo.bind(fb);
getFoo(); // 'bar'
There is no "correct" way to simulate classes. There are different patterns you could use.
You could stick with the one you are using right now. The code you posted works correctly. Or you could switch to another pattern.
For example Douglas Crockford advocates doing something like this
function myClass() {
var that = {},
myMethod = function() {
console.log(that);
};
that.myMethod = myMethod;
return that;
}
Watch his talk on youtube.
http://youtu.be/6eOhyEKUJko?t=48m25s
I use the style bellow:
function MyClass(){
var privateFunction = function(){
}
this.publicFunction = function(){
privateFunction();
}
}
For me this is much more intuitive than using the prototype way, but you'll reach a similar result combining apply() method.
Also, you have another good patterns, Literal Object Notation, Revealing Module Pattern
But, if you want to change the reference to this associate of a function use the Function.prototype.apply(), you can see at this sample a way to change the global this to your object.

Object litterals vs Module pattern

I would like to understand clearly the difference between those two following patterns. In fact, the second one allows to mimic public and private method, but is there any other difference ?
var myModule = {
myProperty: "someValue",
...
myMethod: function () {
console.log( "Anything" );
}
};
myModule.myMethod();
and this :
var myModule = (function(){
var myProperty= "someValue";
...
return {
myMethod: function(){
console.log('something');
}
}
})();
myModule.myMethod();
The second one is essentially just like the first, except that it also provides for a closure around the object where "private" variables can be kept.
Specifically, if you set up an example like the second such that it had no local variables and no parameters to the anonymous function, it'd be exactly like not having the anonymous function at all.

Javascript namespacing - is this particular method good practice?

I'm a javascript newbie, and I've come up with the following scheme for namespacing:
(function() {
var ns = Company.namespace("Company.Site.Module");
ns.MyClass = function() { .... };
ns.MyClass.prototype.coolFunction = function() { ... };
})();
Company.namespace is a function registered by a script which simply creates the chain of objects up to Module.
Outside, in non-global scope:
var my = new Company.Site.Module.MyClass();
I'm particularly asking about the method by which I hide the variable ns from global scope - by a wrapping anonymous function executed immediately. I could just write Company.Site.Module everywhere, but it's not DRY and a little messy compared to storing the ns in a local variable.
What say you? What pitfalls are there with this approach? Is there some other method that is considered more standard?
You dont need to scope classes like that, its only necessary if you have global variables outside of the class. I use this approach...
MyApp.MyClass = function() {
};
MyApp.MyClass.prototype = {
foo: function() {
}
};
Also note that I use a object literal for a cleaner prototype declaration
However if you need to scope global variables then you can do
(function() {
var scopedGlobalVariable = "some value";
MyApp.MyClass = function() {
};
MyApp.MyClass.prototype = function() {
foo: function() {
}
};
})();
Your approach looks fine to me.
However, you can also do this slightly different, by returning the "class" from the self-executing function:
Company.Site.Module.MyClass = (function() {
var MyClass = function() { ... };
MyClass.prototype.foo = function() { ... };
return MyClass;
})();
This strips at least all the ns. prefixes. The namespace function can still be utilized to create the objects, but outside of the self-executing function.

Difference between two JavaScript object types

I see objects in JavaScript organized most commonly in the below two fashions. Could someone please explain the difference and the benefits between the two? Are there cases where one is more appropriate to the other?
Really appreciate any clarification. Thanks a lot!
First:
var SomeObject;
SomeObject = (function() {
function SomeObject() {}
SomeObject.prototype.doSomething: function() {
},
SomeObject.prototype.doSomethingElse: function() {
}
})();
Second:
SomeObject = function() {
SomeObject.prototype.doSomething: function() {
},
SomeObject.prototype.doSomethingElse: function() {
}
}
Both of those examples are incorrect. I think you meant:
First:
var SomeObject;
SomeObject = (function() {
function SomeObject() {
}
SomeObject.prototype.doSomething = function() {
};
SomeObject.prototype.doSomethingElse = function() {
};
return SomeObject;
})();
(Note the return at the end of the anonymous function, the use of = rather than :, and the semicolons to complete the function assignments.)
Or possibly you meant:
function SomeObject() {
}
SomeObject.prototype.doSomething = function() {
};
SomeObject.prototype.doSomethingElse = function() {
};
(No anonymous enclosing function.)
Second:
function SomeObject() {
}
SomeObject.prototype = {
doSomething: function() {
},
doSomethingElse: function() {
}
};
(Note that the assignment to the prototype is outside the SomeObject function; here, we use : because we're inside an object initializer. And again we have the ; at the end to complete the assignment statement.)
If I'm correct, there's very little difference between them. Both of them create a SomeObject constructor function and add anonymous functions to its prototype. The second version replaces the SomeObject constructor function's prototype with a completely new object (which I do not recommend), where the first one just augments the prototype that the SomeObject constructor function already has.
A more useful form is this:
var SomeObject;
SomeObject = (function() {
function SomeObject() {
}
SomeObject.prototype.doSomething = doSomething;
function doSomething() {
}
SomeObject.prototype.doSomethingElse = doSomethingElse;
function doSomethingElse()
}
return SomeObject;
})();
There, the functions we assign to doSomething and doSomethingElse have names, which is useful when you're walking through code in a debugger (they're shown in call stacks, lists of breakpoints, etc.). The anonymous function wrapping everything is there so that the doSomething and doSomethingElse names don't pollute the enclosing namespace. More: Anonymouses anonymous
Some of us take it further:
var SomeObject;
SomeObject = (function() {
var p = SomeObject.prototype;
function SomeObject() {
}
p.doSomething = SomeObject$doSomething;
function SomeObject$doSomething() {
}
p.doSomethingElse = SomeObject$doSomethingElse;
function SomeObject$doSomethingElse()
}
return SomeObject;
})();
...so that not only do we see doSomething, but SomeObject$doSomething in the lists. Sometimes that can get in the way, though, it's a style choice. (Also note I used the anonymous function to enclose an alias for SomeObject.prototype, to make for less typing.)
First off, both snippets will not parse for me (Chrome) - you should use = in place of :. That said, my humble opinion follows.
The latter snippet is slightly strange, because you actually define methods on SomeObject's prototype at the time of the object construction, rather than at the parse time. Thus, if you have re-defined some method on SomeObject.prototype, it will get reverted to the original version once a new object is constructed. This may result in unexpected behavior for existing objects of this type.
The former one looks fine, except that the (function { ...} ())() wrapper may not be necessary. You can declare just:
function SomeObject() {}
SomeObject.prototype.doSomething = function() {}
SomeObject.prototype.doSomethingElse = function() {}
The actual difference between first and second in your questions is just:
var o = (function () {})(); # call this (A)
and
var o = function () {}; # call this (B)
Unfortunately, neither of the examples that you gave are written correctly and, while I don't think either will actually give an error at parse-time, both will break in interesting ways when you try to do things with the result.
To give you an answer about the difference between (A) and (B), (A) is the immediate function application pattern. The JavaScript Patterns book has a good discussion, which I recommend.
The actual problems in your code have been explained by other people while I was writing this. In particular T.J. Crowder points out important things.

How can I avoid using this snippet in Javascript closures?

I use this snippet in Javascript like 100 times a day to have a closure on the enclosing object:
Class.prototype.Method = function(arg){
var Ta = this;
var e = function(){
Ta.doSomething(arg);
};
};
it there a way to avoid the Ta variable and still refere to the "outer" (is this word correct?) object?
I don't know that I'd advocate this as superior, but you could use ".bind()":
var e = function() {
this.doSomething(arg);
}.bind(this);
That ensures that the this value inside function "e" will always be the this value of the surrounding context. The .bind() function is available in newer browsers, or via a polyfill like the one on the MDC site.
I rather like keeping those local variables around, especially in complicated functions that set up event handlers and stuff like that; it helps clarify the relationships between layers of code.
a) You could continue using this approach with more meaningful variable names. Using that is a common convention -- it's indicative that your variable is just another "this" value, but for another function scope.
b) You can use a function bind utility. Some JavaScript libraries come with one. Or you can simply roll your own:
function bind(fn, scope) {
return function () {
fn.apply(scope, arguments);
};
}
// for your example:
Class.prototype.Method = function(arg) {
var e = bind(function() {
this.doSomething(arg);
}, this);
};
// Alternatively, extend the Function prototype (may raise some eyebrows):
Function.prototype.bind = function (scope) {
var fn = this;
return function () {
fn.apply(scope, arguments);
};
};
// for your example:
Class.prototype.Method = function(arg) {
var e = function() {
this.doSomething(arg);
}.bind(this);
};
Update:
As #Pointy noted, bind is actually part of a new version of the JavaScript spec, getting picked up by modern browsers already: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
I don't believe there is. I do the same thing all the time.
I use a small home-made framework to easily use prototype inheritance, and in this framework I have about the same piece of code. I think there's no way to do without this.
Now the question is : Why not doing this ? do you think it's a bad practice, and why ?
The piece of code I use :
function getCallback(obj, methodName) {
var method = obj[methodName];
function callback() {
if (obj[methodName] === callback) {
return method.apply(obj, arguments);
}
return obj[methodName].apply(obj, arguments);
}
return callback;
}

Categories

Resources