Closure Compiler #extends doesn't work when using "Class" container objects - javascript

I'm in the process of annotating all my javascript for closure compiler, however -- the code I have currently heavily depends on defining classes within objects i.e:
Class.SomeClass = function() {};
Class.SomeOtherClass = function() {};
rather than:
function SomeClass() {};
SomeClass.prototype = {};
However, it gives me an warning when trying to annotate an extends ... the compiler is stating that i can't determine what type Class.SomeClass is:
JSC_TYPE_PARSE_ERROR: Bad type annotation. Unknown type Class.SomeObject
* #extends Class.SomeObject
Paste the following code below into closure compiler with ADVANCED_OPTIMIZATIONS:
// ==ClosureCompiler==
// #output_file_name default.js
// #compilation_level ADVANCED_OPTIMIZATIONS
// ==/ClosureCompiler==
(function($) {
"use strict";
var Class = {};
/**
* #constructor
*/
Class.ObjectA = function() {};
Class.ObjectA.prototype = {};
/**
* #constructor
* #extends Class.ObjectA
*/
Class.ObjectB = function() {};
Class.ObjectB.prototype = $.extend(new Class.ObjectA(), {
initialize: function() {}
});
window.test = new Class.ObjectB();
window.test.initialize();
})(jQuery);

The answer isn't obvious. You simply need to add an #const to your Class namespace.
/** #const */
var Class = {};

well the easiest, since you will be compiling it in advance mode anyway is to maybe use goo.provide and just link the base.js in. then obviously you should use goog.inherits for your inheritance since advanced mode understand the base.js functions a lot better than say $.extends.
so my code to achieve the same would look like this:
// ==ClosureCompiler==
// #output_file_name default.js
// #compilation_level ADVANCED_OPTIMIZATIONS
// #use_closure_library true
// ==/ClosureCompiler==
goog.provide('Class.ObjectA')
/**
* #constructor
*/
Class.ObjectA = function() {};
goog.provide('Class.ObjectB');
/**
* #constructor
* #extends Class.ObjectA
*/
Class.ObjectB = function() {};
Class.ObjectB.prototype =
{
initialize: function() {}
}
goog.inherits(Class.ObjectB, Class.ObjectA);
window.test = new Class.ObjectB();
window.test.initialize();
In the compiler ui, you have to select the option to add the closure library which will add goog.base.
Now you also have several jqueury style foo's in your approach like (function($) {})(jQuery); which i would reassess the use of if you are starting down the advanced compilation route (i would personally reasses the use of jquery versus the closure library, but I do know of people who continued using jquery with advanced). going down the advanced mode I would also recomend that you look at a build system like plovr.

Related

Closure Compiler Externs for Function with static fields

What is the correct type for a constructor function that also has properties on the function object with Google's closure compiler?
Here's a runnable first attempt on the Closure compiler debugger.
Application Code
const Mocha = /** #type {!MochaJS} */ (require('mocha'));
const mochaInstance = new Mocha();
const Suite = Mocha.Suite;
Closure Externs
/** #constructor */
const MochaJS = function() {};
/** #type {!MochaJS.Suite} */
MochaJS.prototype.Suite;
/** #record */
MochaJS.Suite = function() {};
The difficulty comes because Closure-compiler doesn't handle external module definitions well. Also, dont' confuse the constructor/namespace with an instance. They are different.
Application
// A constructor type for Mocha
const Mocha = /** #type {!function(new:MochaJS)} */ (require('mocha'));
const mochaInstance = new Mocha();
const Suite = /** #type {!MochaJSSuite} */ (Mocha.Suite);
Externs
/** #constructor */
const MochaJS = function() {};
/** #function */
MochaJSSuite = function() {};
This is just rough guesses for the types - I'm not familiar enough with Mocha to write the externs without going to hunt down the documentation reference. Hopefully it will point you in the right direction though.

Closure compiler annotations for an object containing a constructor function

I'm trying to typecheck a library that returns an Object of constructor functions. With the following code Closure errors with:
./my-app.js:11: ERROR - Cannot call non-function type Foo.Wheel
const wheel = new Foo.Wheel();
^
Here's the code structure:
my-app-code.js - The code I'm using
const Foo = /** #type{!Foo.Module} */ require('foo');
const wheel = new Foo.Wheel();
wheel.rotate();
externs-foo.js - Closure externs for the Foo library
/** #const */
const Foo = {};
/** #record */
Foo.Module = function() {};
/** #type {!Foo.Wheel} */
Foo.Module.prototype.Wheel;
/** #constructor */
Foo.Wheel = function() {};
/**
* #returns {void}
*/
Foo.Wheel.prototype.rotate = function() {};
foo/index.js - corresponds to Foo.Module type.
module.exports = {
Wheel: require("./wheel"),
};
foo/wheel.js - corresponds to Foo.Wheel.
function Wheel() {}
Wheel.prototype.rotate = function() {};
module.exports = Wheel;
I tried one variation on externs-foo.js with the following results.
Make Foo.module.prototype.Wheel a function
/** #return {!Foo.Wheel} */
Foo.Module.prototype.Wheel = function() {};
Errors with:
my-app.js:11: ERROR - Expected a constructor but found type function(this:Foo.Module):Foo.Wheel.
const wheel = new Foo.Wheel();
my-app.js:13: ERROR - Property rotate never defined on module$myapp_Foo of type Foo.Module
wheel.rotate();
I'm aware of two solutions to this issue:
Declaring Foo.Module.prototype.Wheel = Foo.Wheel; in the externs file.
Use #type {function(new:Foo.Wheel)}, which says that the function is in fact a constructor that instantiates a Foo.Wheel object.
I prefer solution #1 because it declares a reference to the constructor function, so the compiler will allow me to access properties of the constructor (e.g. static methods). IIRC this can't be done in solution #2.
The annotations #type {!Foo.Wheel} and #return {!Foo.Wheel} won't work because they refer to an instance of Foo.Wheel and what you actually want is the constructor itself.

CommonJS module pattern

I have taken this from
Flux architecture
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var TodoConstants = require('../constants/TodoConstants');
var assign = require('object-assign');
var CHANGE_EVENT = 'change';
var _todos = {}; // collection of todo items
/**
* Create a TODO item.
* #param {string} text The content of the TODO
*/
function create(text) {
// Using the current timestamp in place of a real id.
var id = Date.now();
_todos[id] = {
id: id,
complete: false,
text: text
};
}
/**
* Delete a TODO item.
* #param {string} id
*/
function destroy(id) {
delete _todos[id];
}
var TodoStore = assign({}, EventEmitter.prototype, {
/**
* Get the entire collection of TODOs.
* #return {object}
*/
getAll: function() {
return _todos;
},
emitChange: function() {
this.emit(CHANGE_EVENT);
},
/**
* #param {function} callback
*/
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
/**
* #param {function} callback
*/
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
},
dispatcherIndex: AppDispatcher.register(function(payload) {
var action = payload.action;
var text;
switch(action.actionType) {
case TodoConstants.TODO_CREATE:
text = action.text.trim();
if (text !== '') {
create(text);
TodoStore.emitChange();
}
break;
case TodoConstants.TODO_DESTROY:
destroy(action.id);
TodoStore.emitChange();
break;
// add more cases for other actionTypes, like TODO_UPDATE, etc.
}
return true; // No errors. Needed by promise in Dispatcher.
})
});
where it says
There are a few important things to note in the above code. To start, we are maintaining a private data structure called _todos. This object contains all the individual to-do items. Because this variable lives outside the class, but within the closure of the module, it remains private — it cannot be directly changed from outside of the module. This helps us preserve a distinct input/output interface for the flow of data by making it impossible to update the store without using an action.
The bold part is unclear to me. How can js interpreter know that all those code is inside a module closure and not in the globals scope?
From where the module closure start and where ends?
As far as I know
The scope of a variable declared with var is its current execution context, which is either the enclosing function or, for variables declared outside any function, global.
Any explanation?
You're actually missing the last line from the extract you quoted :
module.exports = TodoStore;
CommonJS is an API to define modules that use the following conventions :
Every file defines a module and is executed in an isolated environment ; that is to say that the variables it defines won't be available from outside the module.
To allow importing other modules, a global variable require is made available to the module, allowing it to import other modules
In the same way, the variable module is made available to the module so that it can set its exports attribute to define what should be exported by your module ; the value you set for module.exports in your module a.js is exactly what require('./a') will return.
Every JS environment that implements CommonJS has to know these rules. That includes Node.js, of course, but also bundlers like Browserify and Webpack that will package your codes so that these conventions are respected.
This way, you can control which part of your module will be exported.
P.S. : note that you can also use the exports var to define your exports, and that its use is slightly different from module.exports. See this StackOverflow question and answer for details
Common JS pattern uses the constructor function to define your utilities.
It is defined in the form of class.
var moduleName = function() {
// private variables
// public functions
this.method1 = function() {
// logic1 goes here
};
this.method2 = function() {
// logic2 goes here
};
};
So we are going to export the class to other modules using
module.exports = moduleName;
So that other modules can import it, instantiate it and then use the functionality.
How to use it?
var module = require('moduleName'); //importing the module created above
Here the module definition is fetched,executed and then available in 'module' variable.
This variable name can be anything
var objectOfModule = new module(); //instance is created
objectOfModule .method1(); //use1
console.log(objectOfModule .method2()); //use2
Thanks.

Nested Methods in sidebar of JSDoc

Thanks to the answer found here:
https://stackoverflow.com/a/19336366/592495
My JavaScript documentation is well-organized and well-formatted. Each namespace is a "parent" of methods contained within. However, navigation is not quite as granular as I would like.
After compiling/rendering using the node.js tool via a simple command (jsdoc file1.js file2.js), the docs are generated into a default template. This default template displays my namespaces in the sidebar navigation, but it does NOT show methods that each contains.
You can fake a list of methods by adding the #class directive to each method, but as we know, they are not really classes.
I would love to see a sidebar navigation like this:
My Project
- namespace 1
- method.a
- method.b
- method.c
-namespace 2
- method.d
- method.e
Any direction to documentation I have overlooked would be greatly appreciated.
[edit to add:]
Upon experimentation, #class does almost exactly what I want but with some exceptions:
It lists classes above namespaces. I don't like that since the namespaces are the "parents" as it were.
JavaScript doesn't have classes in that sense. Not ones that are called "classes" with that nomenclature. It creates a weird disconnect when reading the document to see a list of "classes".
It adds the "new" operator automagically. Not all of the methods have constructors... you can see the problem!
[edit: sample code]
So here's the current structure. Before I annotate it with JSDoc comments, here's the basic approach:
var app = app || {};
app.utils = {
whizbang: function() {},
geegolly: function() {}
};
app.render = {
thestuff: function(params) {},
thethings: function(params) {}
}
}
So, using object literal notation, the top level is a "namespace" for the whole application, but within there are sub-namespaces for different purposes. Here, I have a sub-namespace specific to utilities, and another one specific to rendering. Each can have properties, but more importantly they each contain functions. It is these functions which should appear in the sidebar. Now to flesh it out with my current pattern for JSDoc:
/**
* #file MyApp.js This is an awesome description of MyApp.js
*
* #version 0.1
* #author Greg Pettit
* #copyright 2015
*
*/
/**
* Description of my main namespace!
*
* #namespace app
*/
var app = app || {};
/**
* This is a description of my sweet utilities namespace!
*
* #memberof app
* #type {object}
* #namespace app.utils
*/
app.utils = {
/**
* app.utils.whizbang is an awesome function with magical powers. I sure wish
* it would appear in the sidebar as a member of app.utils!
*
* #memberof app.utils
* #method whizbang
*
* #param {method} [successCallback] Method invoked on successful attempt.
* #param {method} [errorCallback] Method invoked on unsuccessful attempt.
*
*/
whizbang: function(successCallback, errorCallback) { // do utility stuff! }
}
/**
* This is a description of the best rendering namespace ever.
*
* #memberof app
* #type {object}
* #namespace app.render
*/
app.render = {
/**
* app.render.thethings renders the things! I wish it would render to the sidebar...
*
* #memberof app.render
* #method thethings
*
* #param {method} node The node to which thethings are rendered
*
*/
thethings: function(node) { // do rendering stuff! }
}
Have you tried using the #lends tag? An example of your code and doc comments would be helpful here.
Since I don't know what your code looks like, I'll just give an example of how I use JSDoc with our in-house framework, which has lots of idiosyncracies (hey, I didn't write it, I just have to use it).
Just to give some context, we have a context object that can create apps and modules (apps are just modules with a start method):
/** #namespace MyApp */
var MyApp = context.app('myApp').use('module1', 'module2', 'underscore');
We have a dependency injection system for backbone that uses an angular-style pattern for expressing dependencies:
/**
* The constructor for MyModel
* #memberof MyApp
* #param {object?} attrs
* #param {object?} options
* #param {AppUtils} appUtils
* #constructor
*/
MyApp.MyModel = function(attrs, options, appUtils) {
this.options = options;
this.utils = appUtils;
}
// This is injected by the dependency resolver at instantiation time
// No additional JSDoc comments are necessary, it actually gets this right
MyApp.MyModel.prototype = {
idAttribute: 'customId',
defaults: {
customId: '',
name: '',
birthday: null
}
};
// Registers MyModel with the IOC container as 'myModelName'
MyApp.model('myModelName', [
'attrs',
'options',
'appUtils'
MyApp.MyModel
]);
And then a different file can have an instance of myModelName injected by adding it to that dependency array at the bottom.
Funny thing is, JSDoc actually does a pretty good job of understanding that particular arrangement, as long as I don't try to get too fancy... but the following pattern is apparently too confusing for it:
/**
* #memberof MyApp
* #param {MyApp.MyModel} myModel
* #param {urlParser} urlParser
* #constructor
*/
MyApp.SomeService = function(myModel, urlParser) {
return {
foo: function() {
//whatever
},
bar: function() {
//whatever
}
};
};
MyApp.service('someModuleName', [
'myModelName',
'urlParser',
MyApp.SomeService
]);
The only thing that I've found that gives me anything close to the desired output is using the #lends tag to tell JSDoc that a particular object/property/method is "lended" as a different property. For example, to document the attributes property of a backbone model (which is ostensibly defined by its defaults property), we do this:
MyApp.MyModel.prototype = {
idAttribute: 'customId',
/** #lends MyApp.MyModel.prototype.attributes */
defaults: {
customId: '',
name: '',
birthday: null
}
};
And for that case where the service is returning an object, the only way we've found to get those object properties documented is like this:
/**
* #memberof MyApp
* #param {MyApp.MyModel} myModel
* #param {urlParser} urlParser
* #constructor
*/
MyApp.SomeService = function(myModel, urlParser) {
/** #lends MyApp.SomeService.prototype */
return {
foo: function() {
//whatever
},
bar: function() {
//whatever
}
};
};
I have no idea if any of that was useful, but maybe it'll give you some ideas for things you could try with #lends. If you can provide some example code, I can possibly give you a more useful answer.

Why was my javascript code not accepted at interview?

The interviewer told me that I have to follow javascript "patterns" and write "clean code". He also said that I should follow the prototype pattern. Here is my code sample:
//namespace declrations
var MyNamespace = {};
MyNamespace.UCs = {};
MyNamespace.Pages = {};
//function declarations
MyNamespace.UCs.test = function () { alert('this is a test function in user control namespace.'); }
MyNamespace.Pages.test = function () { alert('this is a test function in web page namespace.'); }
So can anybody point me to why this code is not ok? I mean, I have declared namespaces first and then added my members and functions like the above sample. So does it really have issues or am I missing something?
Well when you are writing code in a large environment, lots of problems can start happening. So it's important to separate your class definitions from how you use those classes. Which also means you have to make classes that can be unit tested to prove that they do what you say they do. Javascript is not a true object orientated language and as such there are several ways to "fake" it. But because the language has a lot of flexibility, we can duplicate some approaches.
One thing we want to stay away from is something called function scope simply because it can cause unintended "features" later down the road when 3 or 4 other programmers start making assumptions about what your code is doing. If they don't know a global variable was overwritten one or two function closures ago, it will make finding that problem more difficult. So I would suggest using a small class created by John Resig as it provides a very simple approach that gives you alot of the functionality you need.
So let's write some code.
var myNamespace = myNamespace || { }
/**
* Used to store a single entry in the log
*
* #class
*/
var myNamespace.LogEntry = Class.extend({
/**
* Used to track the beginning of the page load
*
* #private
* #static
*/
PAGE_LOAD_TIME = new Date().getTime(),
/**
* Used to store the current time
*
* #type int
*/
time : undefined,
/**
* The message of this log entry
*
* #type string
*/
msg : undefined,
/**
* #constructor
*
* #param {string} msg The message of this log entry
*/
init : function (msg) {
this.time = new Date().getTime() - this.PAGE_LOAD_TIME;
this.msg = msg
},
/**
* Displays this log entry in a single string
*
* #return {string} String representation of this log entry
*/
toString : function () {
return this.time + ": " + this.msg;
}
});
/**
* Used to store a log entry that has data associated with it.
*
* #class
* #extends myNamespace.LogEntry
*/
var myNamespace.DataEntry = myNamespace.LogEntry.extend({
/**
* Used to store data associated with this log entry
*
* #type object
*/
data : undefined,
/**
* #constructor
*
* #param {string} msg The message that describes this log entry
* #param {object} data The data associated with this entry
*/
init : function (msg, data) {
this._super(msg);
this.data = data;
},
/**
* #return {string} The string representation of this log entry
*/
toString : function () {
// Uses a JSON library to stringify the data into a json string.
return this._super() + JSON.stringify(this.data);
}
});
/**
* Provides an interface to log messages
*
* #class
*/
var myNamespace.Log = Class.extend({
/**
* Stores log entries
*
* #type myNamespace.LogEntry[]
*/
log : undefined,
/**
* #constructor
*/
init : function () {
this.log = [ ];
},
/**
* Logs a message into the log
*
* #param {string} msg The message you want to log
*/
msg : function (msg) {
this.log.push(new myNamespace.LogEntry(msg));
},
/**
* Log a message and data into the log
*
* #param {string} msg The message of this log entry
* #param {object} data The data associated with this log entry
*/
data : function(msg, data) {
this.log.push(new myNamespace.DataEntry(msg, data));
}
});
Ok, there is lots of stuff going on here. The main part is that this is all definitions of classes. I don't actually use anything up there. The program only stores the current time in LogEntry.PAGE_LOAD_START which is declared #static so the behavior will be expected. I've used lots of jsDocs here to make everything clear about what the intentions are. A program like intelliJ can use those to give your code feedback if you aren't using the classes the way you've documentated them.
This program will let you create and store log entries with possibly logging data. There are alot of other ways to do this. I declare everything before the constructor instead of inside the constructor so that I can document the types and whether they are private.
A programmer that has to use the log will know exactly how to use it and if they want to create or extend these classes, they can do so without unintended effects from function closure.
Here's how to use it:
var anotherNamespace = anotherNamespace || {};
var anotherNamespace = new myNamespace.Log();
...
anotherNamespace.log.msg("This is a test");
...
anotherNamespace.log.data("Test msg with data", data);
Of course the obvious thing missing here is a way to display all the data. But that could be in another class that iterates through the Log.log array and spits out the toString() into a web page or file. The point here is that the classes and their functions are simple, unit testable, and definition only.
FIrst of all, make use of object literals, all those assignments are a waste lines.
Second, you don't have the prototype "pattern" implemented anywhere, also I'd go for some encapsulation if you have full control over the namespaces:
(function() { // anonymous wrapper
function Foo(a) { // i can haz prototype "Pattern"
this.memberVal = a;
}
Foo.prototype = {
someMethod: function(value) {
console.log(value, this.memberVal);
},
yam: function() {
}
};
// Let's assume we have full control here, otherwise Alnitak's answer is fine too.
window.namespace = {
test: {
Foo: Foo
}
};
})();
var test = new namespace.test.Foo(123);
test.someMethod('bla');
Maybe the interviewer literally meant you should be using the 'namespace' method?
Tutorial with example of usage:
http://elegantcode.com/2011/01/26/basic-javascript-part-8-namespaces/
Your code looks (mostly) fine, if the intent was to just put utility functions in a shared namespace, without any object orientation or data encapsulation.
I would have made one change, on the initial name space declarations:
var MyNamespace = MyNamespace || {};
MyNamespace.UCs = MyNamespace.UCs || {};
MyNamespace.Pages = Mynamespace.Pages || {};
to ensure that the code didn't obliterate any existing methods in those namespaces.

Categories