A mostly reasonable approach to JavaScript
https://github.com/hshoff/javascript.git
A mostly reasonable approach to JavaScript
stringnumberbooleannullundefinedvar foo = 1,
bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9
objectarrayfunctionvar foo = [1, 2],
bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
[[β¬]](#TOC)
// bad
var item = new Object();
// good
var item = {};
// bad
var superman = {
class: 'superhero'
};
// good
var superman = {
klass: 'superhero'
};
// good
var superman = {
'class': 'superhero'
};
[[β¬]](#TOC)
// bad
var items = new Array();
// good
var items = [];
var len = items.length,
itemsCopy = [],
i;
// bad
for (i = 0; i < len; i++) {
itemsCopy.push(items[i])
}
// good
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
[[β¬]](#TOC)
'' for strings// bad
var name = "Bob Parr";
// good
var name = 'Bob Parr';
// bad
var fullName = "Bob" + this.lastName;
// good
var fullName = 'Bob' + this.lastName;
// bad
var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
// bad
var errorMessage = 'This is a super long error that \
was thrown because of Batman. \
When you stop to think about \
how Batman had anything to do \
with this, you would get nowhere \
fast.';
// good
var errorMessage = 'This is a super long error that ' +
'was thrown because of Batman.' +
'When you stop to think about ' +
'how Batman had anything to do ' +
'with this, you would get nowhere ' +
'fast.';
var items,
messages,
length, i;
messages = [{
state: 'success',
message: 'This one worked.'
},{
state: 'success',
message: 'This one worked as well.'
},{
state: 'error',
message: 'This one did not work.'
}];
length = messages.length;
// bad
function inbox(messages) {
items = '<ul>';
for (i = 0; i < length; i++) {
items += '<li>' + messages[i].message + '</li>';
}
return items + '</ul>';
}
// good
function inbox(messages) {
items = [];
for (i = 0; i < length; i++) {
items[i] = '<li>' + messages[i].message + '</li>';
}
return '<ul>' + items.join('') + '</ul>';
}
[[β¬]](#TOC)
// anonymous function expression
var anonymous = function() {
return true;
};
// named function expression
var named = function named() {
return true;
};
// immediately-invoked function expression (IIFE)
(function() {
console.log('Welcome to the Internet. Please follow me.');
})();
// bad
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// good
if (currentUser) {
var test = function test() {
console.log('Yup.');
};
}
// bad
function() {
var size;
if (!arguments.length) {
size = false;
} else {
size = arguments.length;
}
return size;
}
// good
function() {
if (!arguments.length) {
return false;
}
return arguments.length;
}
arguments, this will take precendence over the arguments object that is given to every function scope.// bad
function nope(name, options, arguments) {
// ...stuff...
}
// good
function yup(name, options, args) {
// ...stuff...
}
[[β¬]](#TOC)
var luke = {
jedi: true,
age: 28
};
// bad
var isJedi = luke['jedi'];
// good
var isJedi = luke.jedi;
[] when accessing properties with a variable.var luke = {
jedi: true,
age: 28
};
function getProp(prop) {
return luke[prop];
}
var isJedi = getProp('jedi');
[[β¬]](#TOC)
var to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that.// bad
superPower = new SuperPower();
// good
var superPower = new SuperPower();
var declaration for multiple variables and declare each variable on a newline.// bad
var items = getItems();
var goGiants = true;
var dragonball = 'z';
// good
var items = getItems(),
goGiants = true,
dragonball = 'z';
// bad
var i, len, dragonball,
items = getItems(),
goGiants = true;
// bad
var i, items = getItems(),
dragonball,
goGiants = true,
len;
// good
var items = getItems(),
goGiants = true,
dragonball,
i, length;
// bad
function() {
test();
console.log('doing stuff..');
//..other stuff..
var name = getName();
if (name === 'test') {
return false;
}
return name;
}
// good
function() {
var name = getName();
test();
console.log('doing stuff..');
//..other stuff..
if (name === 'test') {
return false;
}
return name;
}
// bad
function() {
var name = getName();
if (!arguments.length) {
return false;
}
return true;
}
// good
function() {
if (!arguments.length) {
return false;
}
var name = getName();
return true;
}
[[β¬]](#TOC)
// we know this wouldn't work (assuming there
// is no notDefined global variable)
function example() {
console.log(notDefined); // => throws a ReferenceError
}
// creating a variable declaration after you
// reference the variable will work due to
// variable hoisting. Note: the assignment
// value of `true` is not hoisted.
function example() {
console.log(declaredButNotAssigned); // => undefined
var declaredButNotAssigned = true;
}
// The interpretor is hoisting the variable
// declaration to the top of the scope.
// Which means our example could be rewritten as:
function example() {
var declaredButNotAssigned;
console.log(declaredButNotAssigned); // => undefined
declaredButNotAssigned = true;
}
function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is not a function
var anonymous = function() {
console.log('anonymous function expression');
};
}
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
superPower(); // => ReferenceError superPower is not defined
var named = function superPower() {
console.log('Flying');
};
// the same is true when the function name
// is the same as the variable name.
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
var named = function named() {
console.log('named');
};
}
}
function example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}
=== and !== over == and !=.ToBoolean method and always follow these simple rules:**true****false****false****false** if +0, -0, or NaN, otherwise **true****false if an empty string '', otherwise **true**if ([0]) {
// true
// An array is an object, objects evaluate to true
}
// bad
if (name !== '') {
// ...stuff...
}
// good
if (name) {
// ...stuff...
}
// bad
if (collection.length > 0) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
// bad
if (test) return false;
// good
if (test) {
return false;
}
// bad
function() { return false; }
// good
function() {
return false;
}
[[β¬]](#TOC)
/** ... */ for multiline comments. Include a description, specify types and values for all parameters and return values.// bad
// make() returns a new element
// based on the pased in tag name
//
// @param <String> tag
// @return <Element> element
function make(tag) {
// ...stuff...
return element;
}
// good
/**
* make() returns a new element
* based on the pased in tag name
*
* @param <String> tag
* @return <Element> element
*/
function make(tag) {
// ...stuff...
return element;
}
// for single line comments. Place single line comments on a newline above the subject of the comment. Put an emptyline before the comment.// bad
var active = true; // is current tab
// good
// is current tab
var active = true;
// bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
var type = this._type || 'no type';i
return type;
}
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
var type = this._type || 'no type';
return type;
}
[[β¬]](#TOC)
// bad
function() {
ββββvar name;
}
// bad
function() {
β var name;
}
// good
function() {
ββvar name;
}
// bad
function test(){
console.log('test');
}
// good
function test() {
console.log('test');
}
// bad
dog.set('attr',{
age: '1 year',
breed: 'Bernese Mountain Dog'
});
// good
dog.set('attr', {
age: '1 year',
breed: 'Bernese Mountain Dog'
});
// bad
(function(global) {
// ...stuff...
})(this);
// good
(function(global) {
// ...stuff...
})(this);
[[β¬]](#TOC)
// bad
var once
, upon
, aTime;
// good
var once,
upon,
aTime;
// bad
var hero = {
firstName: 'Bob'
, lastName: 'Parr'
, heroName: 'Mr. Incredible'
, superPower: 'strength'
};
// good
var hero = {
firstName: 'Bob',
lastName: 'Parr',
heroName: 'Mr. Incredible',
superPower: 'strength'
};
[[β¬]](#TOC)
// bad
(function() {
var name = 'Skywalker'
return name
})()
// good
(function() {
var name = 'Skywalker';
return name;
})();
// good
;(function() {
var name = 'Skywalker';
return name;
})();
[[β¬]](#TOC)
// => this.reviewScore = 9;
// bad
var totalScore = this.reviewScore + '';
// good
var totalScore = '' + this.reviewScore;
// bad
var totalScore = '' + this.reviewScore + ' total score';
// good
var totalScore = this.reviewScore + ' total score';
var inputValue = '4';
// bad
var val = new Number(inputValue);
// good
var val = Number(inputValue);
// good
var val = +inputValue;
var age = 0;
// bad
var hasAge = new Boolean(age);
// good
var hasAge = Boolean(age);
// good
var hasAge = !!age;
[[β¬]](#TOC)
// bad
function q() {
// ...stuff...
}
// good
function query() {
// ..stuff..
}
// bad
var OBJEcttsssss = {};
var this_is_my_object = {};
var this-is-my-object = {};
function c() {};
var u = new user({
name: 'Bob Parr'
});
// good
var thisIsMyObject = {};
function thisIsMyFunction() {};
var user = new User({
name: 'Bob Parr'
});
// bad
function user(options){
this.name = options.name;
}
var bad = new user({
name: 'nope'
});
// good
function User(options){
this.name = options.name;
}
var good = new User({
name: 'yup'
});
_ when naming private properties// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
// bad
var log = function(msg) {
console.log(msg);
};
// good
var log = function log(msg) {
console.log(msg);
};
[[β¬]](#TOC)
// bad
dragon.age();
// good
dragon.getAge();
// bad
dragon.age(25);
// good
dragon.setAge(25);
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
function Jedi(options) {
options || (options = {});
var lightsaber = options.lightsaber || 'blue';
this.set('lightsaber', lightsaber);
}
Jedi.prototype.set: function(key, val) {
this[key] = val;
};
Jedi.prototype.get = function(key) {
return this[key];
};
[[β¬]](#TOC)
function Jedi() {
console.log('new jedi');
}
// bad
Jedi.prototype = {
fight: function fight() {
console.log('fighting');
},
block: function block() {
console.log('blocking');
}
};
// good
Jedi.prototype.fight = function fight() {
console.log('fighting');
};
Jedi.prototype.block = function block() {
console.log('blocking');
};
this. This helps with method chaining which is often useful.// bad
Jedi.prototype.jump = function() {
this.jumping = true;
return true;
};
Jedi.prototype.setHeight = function(height) {
this.height = height;
};
var luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20) // => undefined
// good
Jedi.prototype.jump = function() {
this.jumping = true;
return this;
};
Jedi.prototype.setHeight = function(height) {
this.height = height;
return this;
};
var luke = new Jedi();
luke.jump()
.setHeight(20);
function Jedi(options) {
options || (options = {});
this.name = options.name || 'no name';
}
Jedi.prototype.getName = function getName() {
return this.name;
};
Jedi.prototype.toString = function toString() {
return 'Jedi - ' + this.getName();
};
[[β¬]](#TOC)
'use strict;' at the top of the module.// fancyInput/fancyInput.js
(function(global) {
'use strict';
var previousFancyInput = global.FancyInput;
function FancyInput(options) {
options || (options = {});
}
FancyInput.noConflict = function noConflict() {
global.FancyInput = previousFancyInput;
};
global.FancyInput = FancyInput;
})(this);
[[β¬]](#TOC)
$.// bad
var sidebar = $('.sidebar');
// good
var $sidebar = $('.sidebar');
// bad
function setSidebar() {
$('.sidebar').hide();
// ...stuff...
$('.sidebar').css({
'background-color': 'pink'
});
}
// good
function setSidebar() {
var $sidebar = $('.sidebar');
$sidebar.hide();
// ...stuff...
$sidebar.css({
'background-color': 'pink'
});
}
// bad
$('.sidebar ul').hide();
// bad
$('.sidebar > ul').hide();
// bad
$('.sidebar', 'ul').hide();
// good
$('.sidebar').find('ul').hide();
[[β¬]](#TOC)
function() {
return true;
}
[[β¬]](#TOC)
Read This
Other Styleguides Books(The MIT License)
Copyright (c) 2012 Harrison Shoff
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[[β¬]](#TOC)