Closed phamann closed 11 years ago
Multi-line your define statement as it's easier to diff,
define([
'common',
'reqwest',
...
], function (
common,
reqwest,
...
) {
A modules should only be called using the 'new' constructor if there needs to be multiple instances on the page such tabs.
How about just one module pattern.
Given the object based one doesn't support multiple instances can we use this [below] for everything?
function Foo(opts) { // --- pass options in to constructor, not init()
// variable declaration etc.
var options = opt,
foo = options || false;
// code to do with dom manipulation and user interaction goes in here
this.view = {
x: function() { }
}
// code to manipulate the data etc.
this.x = { };
this.y = { };
// bindings
common.mediator.on('module:xxx', this.view.x);
// initialise
this.init = function() { };
return Foo;
}
Iterators are easier to read than for loops,
Boo!
for (var i = 0, j = list.length; i<j; ++i) {
document.cookie = list[i] + "=;path=/;expires=Thu, 01 Jan 1970 00:00:01 GMT;";
}
Yay!
list.forEach(function(item) {
document.cookie = item + "=;path=/;expires=Thu, 01 Jan 1970 00:00:01 GMT;";
});
Boo!
var foo = [1,2,3], query = '';
for (var k = 0, l = foo.length; k<l; ++k) {
query += "a=" + foo[k] + "&";
}
Yay!
var query = [1,2,3].map(function(i){
return "a=" + i;
}).join('&')
Using a docblock will get you shot, apparently.
Though it's quite useful when it comes to opts style arguments,
/*
@param {Object} options hash of configuration options:
prependTo : {DOMElement} DOM element to prepend component to
competitions: {Array} Ordered list of competetions to query
path : {String} Used to overide endpoint path
contextual : {Boolean} Whether or not component links should be contextual
numVisible : {Number} Number of items to show when contracted
*/
The forEach()
syntax ties us to IE9+, which is my only concern, but then maybe we don't care about this...
This one line, is currently stopping JS getting to < IE9 browsers anyway.
Although - looking at that - the only part that returns false is the addEventListener
, and Bean does a good normalising events and falling back to attachEvent
instead. So we may want to remove. Thoughts?
But yes forEach()
and map()
will definitely fix us to IE9+
Emissions,
emit("modules:name:event", [param1, param_2]) // Nb. use an array for any parameters
Logs errors,
emit('module:error', 'message', 'file.js');
Sometimes, when your code is dealing with multiple instances it might make sense to include the id and state in the emission,
common.mediator.emit('modules:name:event:' + id + ':' + state);
I'm not 100% sure this is a good thing.
Lowercase all modules dependencies (even vendor ones) and name them after the module, camel-cased if necessary,
define(['common', 'modules/detect','modules/adverts/audience-science'], function (common, detect, audienceScience) {
DH - Feels odd saying new audienceScience()
. I think it's useful to differentiate between objects and classes, e.g. camelCase for qwery
, CamelCase for AudienceScience
Don't use underscores to denote variable/method privacy.
Always allow document roots to be injected.
It's easier to write tests for, and lets us scope the selector to a small part of the DOM, which is better for performance.
Boo!
var f = function() {
document.getElementById('foo')
}
Yay!
var f = function(opts) {
var doc = opts.document || window.document;
doc.getElementById('foo');
}
Boo!
var foo = 1;
var bar = 2;
Yay!
var foo = 1,
bar = 2;
Hipster!
var foo = 1
, bar = 2;
Misc.
jshint
picks up on multiple var
declarations, right? Doesn't have a isHipster
setting though
RE: Jasmine spec's
Must have a corresponding test named after the module.
Programmatically create fixture HTML using the fixtures helper
Don't chain your tests. A new instance for each test of whatever you are testing is clearer.
waitsFor is more obvious than waits
Keep everything inside beforeEach (otherwise you risk tests bleeding in to each other)
Use sinon spying over jasmine (it's got a better feature-set)
Clear the mediator listeners before all tests.
Think about why you are using waits(500) - would the test be clearer if you linearised the logic?
Reading globals - Eg, location, document - via injection Vs. common amd module vs read directly?
Have moved this discussion into a dedicated page (https://github.com/guardian/frontend/wiki/JavaScript-guidelines) -- closing this, let's move discussion over there instead!
Below are some minor observations gathered during refactoring our JS bootstraping and modules. Some of which are consistent and others which need to be decided upon and then normalised across the modules and we can create a document or github page by which we can reference for future development.
Discussion on these conventions is encouraged ;) and please feel free to add more to the list!
Module initialising:
over
Naming conventions:
Events:
This is a controversial one:
Logging: