The style you choose for your project should be the highest criterion. Place it as a description in your project and link it to this document as a guarantee of code style consistency, readability and maintainability.
1. Blank
1. Never mix spaces and tabs.
2. Start a project, select soft indent (space) or Tab (as indentation method) before writing the code and use it as the highest criterion.
a). For readability, I always recommend designing 2 letter width indentation in your edits - this is equivalent to two spaces or two spaces instead of a Tab.
3. If your editor supports it, always turn on the "Show Invisible Characters" setting. The benefits are:
a). Ensure consistency
b). Remove the spaces at the end of the line
c). Remove blank spaces
d). Submission and comparison are more readable
2. Beautify grammar
A. Braces, Braces, Line Breaks
The code copy is as follows:
// if/else/for/while/try usually has braces, curly braces and multiple lines
// This helps readable
// 2.A.1.1
// Example of difficult syntax
if(condition) doSomething();
while(condition) iterating++;
for(var i=0;i<100;i++) someIterativeFn();
// 2.A.1.1
// Use spaces to improve readability
if ( condition ) {
// Statement
}
while ( condition ) {
// Statement
}
for ( var i = 0; i < 100; i++ ) {
// Statement
}
// Better practice:
var i,
length = 100;
for ( i = 0; i < length; i++ ) {
// Statement
}
// or...
var i = 0,
length = 100;
for ( ; i < length; i++ ) {
// Statement
}
var prop;
for ( prop in object ) {
// Statement
}
if ( true ) {
// Statement
} else {
// Statement
}
B. Assign, declaration, function (named functions, function expressions, constructor functions)
The code copy is as follows:
// 2.B.1.1
// Variable
var foo = "bar",
num = 1,
undef;
// Literal identification:
var array = [],
object = {};
// 2.B.1.2
// Using only one `var` within a scope (function) helps improve readability
// And make your statement list orderly (also saves you a few keyboard typing)
// not good
var foo = "";
var bar = "";
var qux;
// good
var foo = "",
bar = "",
quux;
// or..
var // Comments on these variables
foo = "",
bar = "",
quux;
// 2.B.1.3
// The `var` statement must always be at the top of each scope (function)
// Also suitable for constants from ECMAScript 6
// not good
function foo() {
// There is a statement before the variable
var bar = "",
qux;
}
// good
function foo() {
var bar = "",
qux;
// All statements are after the variable
}
// 2.B.2.1
// Named function declaration
function foo( arg1, argN ) {
}
// How to use
foo( arg1, argN );
// 2.B.2.2
// Named function declaration
function square( number ) {
return number * number;
}
// How to use
square( 10 );
// Very unnatural continuation passing style
function square( number, callback ) {
callback( number * number );
}
square( 10, function( square ) {
// Callback content
});
// 2.B.2.3
// Function expression
var square = function( number ) {
// Return valuable and relevant content
return number * number;
};
// Function expression with identifier
// This preferred form has additional functions that allow it to call itself
// And there is an identifier in the stack
var factorial = function factorial( number ) {
if ( number < 2 ) {
return 1;
}
return number * factorial( number-1 );
};
// 2.B.2.4
// Constructor declaration
function FooBar( options ) {
this.options = options;
}
// How to use
var fooBar = new FooBar({ a: "alpha" });
fooBar.options;
// { a: "alpha" }
C. Exception, details
The code copy is as follows:
// 2.C.1.1
// Functions with callbacks
foo(function() {
// Note: There are no spaces in the brackets and `function` of the first function call
});
// The function accepts `array` as an argument, without spaces
foo([ "alpha", "beta" ]);
// 2.C.1.2
// The function accepts `object` as an argument, without spaces
foo({
a: "alpha",
b: "beta"
});
// The function accepts the `string` literal as an argument, without spaces
foo("bar");
// There are no spaces inside the brackets used for grouping
if ( !("foo" in obj) ) {
}
D. Consistency Always Wins
In Sections 2.A-2.C, blank space is proposed as a recommendation method, based on a simple, higher purpose: unification. It is worth noting that formatting preferences, such as "internal blank space" must be optional, but there must be only one type of source code of the entire project.
The code copy is as follows:
// 2.D.1.1
if (condition) {
// Statement
}
while (condition) {
// Statement
}
for (var i = 0; i < 100; i++) {
// Statement
}
if (true) {
// Statement
} else {
// Statement
}
E. Quotation marks
It doesn't matter whether you choose single or double quotes, they don't make a parsing difference in JavaScript. What absolutely needs to be mandated is consistency. Never mix two quotes in the same project, choose one, and keep it consistent.
F. End of line and empty line
Leaving blank will break the difference and use changes are unreadable. Consider including a pre-committed hook that automatically deletes spaces in the end of the line and blank lines.
3. Type detection (from jQuery Core Style Guidelines)
A. Direct type (actual type, Actual type)
String:
The code copy is as follows:
typeof variable === "string"
Number:
The code copy is as follows:
typeof variable === "number"
Boolean:
The code copy is as follows:
typeof variable === "boolean"
Object:
The code copy is as follows:
typeof variable === "object"
Array:
The code copy is as follows:
Array.isArray( arrayLikeObject )
(If possible)
Node:
The code copy is as follows:
elem.nodeType === 1
null:
The code copy is as follows:
variable === null
null or undefined:
The code copy is as follows:
variable == null
undefined:
Global variables:
The code copy is as follows:
typeof variable === "undefined"
Local variables:
The code copy is as follows:
variable === undefined
property:
The code copy is as follows:
object.prop === undefined
object.hasOwnProperty( prop )
"prop" in object
B. Convert type (coerced type, Coerced Types)
Consider the meaning of the following...
Given HTML:
The code copy is as follows:
<input type="text" id="foo-input" value="1">
// 3.B.1.1
// `foo` has been assigned a value of `0`, type `number`
var foo = 0;
// typeof foo;
// "number"
...
// In subsequent code, you need to update `foo` and assign a new value obtained in the input element
foo = document.getElementById("foo-input").value;
// If you test `typeof foo` now, the result will be `string`
// This means that you have logic similar to this when detecting `foo` in the if statement:
if ( foo === 1 ) {
importantTask();
}
// `importantTask()` will never be executed, even if `foo` has a value of "1"
// 3.B.1.2
// You can cleverly use the +/- unary operator to cast the type to solve the problem:
foo = +document.getElementById("foo-input").value;
// ^ + The unary operator converts the operation object to its right into `number`
// typeof foo;
// "number"
if ( foo === 1 ) {
importantTask();
}
// `importantTask()` will be called
Here are a few examples for casting:
The code copy is as follows:
// 3.B.2.1
var number = 1,
string = "1",
bool = false;
number;
// 1
number + "";
// "1"
string;
// "1"
+string;
// 1
+string++;
// 1
string;
// 2
bool;
// false
+bool;
// 0
bool + "";
// "false"
// 3.B.2.2
var number = 1,
string = "1",
bool = true;
string === number;
// false
string === number + "";
// true
+string === number;
// true
bool === number;
// false
+bool === number;
// true
bool === string;
// false
bool === !!string;
// true
// 3.B.2.3
var array = [ "a", "b", "c" ];
!!~array.indexOf("a");
// true
!!~array.indexOf("b");
// true
!!~array.indexOf("c");
// true
!!~array.indexOf("d");
// false
// It is worth noting that the above are all "unnecessary clever"
// Use a clear scheme to compare the returned values
// For example indexOf:
if ( array.indexOf( "a" ) >= 0 ) {
// ...
}
// 3.B.2.3
var num = 2.5;
parseInt( num, 10 );
// Equivalent to...
~~num;
num >> 0;
num >>> 0;
// The results are all 2
// Always keep in mind, negative values will be treated differently...
var neg = -2.5;
parseInt( neg, 10 );
// Equivalent to...
~~neg;
neg >> 0;
// The results are all -2
// but...
neg >>> 0;
// The result is 4294967294
4. Comparative operations
The code copy is as follows:
// 4.1.1
// When just judging whether an array has a length, relative to using this:
if ( array.length > 0 ) ...
// ...To determine the authenticity, please use this:
if ( array.length ) ...
// 4.1.2
// When just judging whether an array is empty, relative to using this:
if ( array.length === 0 ) ...
// ...To determine the authenticity, please use this:
if ( !array.length ) ...
// 4.1.3
// When just judging whether a string is empty, relative to using this:
if ( string !== "" ) ...
// ...To determine the authenticity, please use this:
if ( string ) ...
// 4.1.4
// When just judging that a string is empty, relative to using this:
if ( string === "" ) ...
// ...To determine the authenticity, please use this:
if ( !string ) ...
// 4.1.5
// When just judging that a reference is true, relative to using this:
if ( foo === true ) ...
// ...Judge just like you think, enjoy the benefits of built-in features:
if ( foo ) ...
// 4.1.6
// When just judging that a reference is false, relative to using this:
if ( foo === false ) ...
// ...Convert it to true using exclamation mark
if ( !foo ) ...
// ...It should be noted that this will match 0, "", null, undefined, NaN
// If you _must_ is a boolean type false, please use this:
if ( foo === false ) ...
// 4.1.7
// If you want to calculate a reference, it may be null or undefined, but it is not false, "" or 0,
// Relative to using this:
if ( foo === null || foo === undefined ) ...
// ... Enjoy the benefits of == type casting, like this:
if ( foo == null ) ...
// Remember that using == will make `null` match `null` and `undefined`
// But not `false`, "" or 0
null == undefined
Always judge the best and most precise values, the above is a guide rather than a dogma.
The code copy is as follows:
// 4.2.1
// Instructions for type conversion and comparison operations
// First time `===`, `==` followed (unless a loose type comparison is needed)
// `===` does not always do type conversion, which means:
"1" === 1;
// false
// `==` converts the type, which means:
"1" == 1;
// true
// 4.2.2
// Boolean, True & Fake
// Boolean:
true, false
// real:
"foo", 1
// Pseudo:
"", 0, null, undefined, NaN, void 0
5. Practical style
The code copy is as follows:
// 5.1.1
// A practical module
(function( global ) {
var Module = (function() {
var data = "secret";
return {
// This is a boolean value
bool: true,
// A string
string: "a string",
// an array
array: [ 1, 2, 3, 4 ],
// an object
object: {
lang: "en-Us"
},
getData: function() {
// Get the value of `data`
return data;
},
setData: function( value ) {
// Return the assigned value of `data`
return ( data = value );
}
};
})();
// Some others will appear here
// Turn your module into a global object
global.Module = Module;
})( this );
// 5.2.1
// A practical build function
(function( global ) {
function Ctor( foo ) {
this.foo = foo;
return this;
}
Ctor.prototype.getFoo = function() {
return this.foo;
};
Ctor.prototype.setFoo = function( val ) {
return ( this.foo = val );
};
// Don't use `new` to call the build function, you might do this:
var ctor = function( foo ) {
return new Ctor( foo );
};
// Turn our build function into a global object
global.ctor = ctor;
})( this );
6. Naming
A. You are not a human compiler/compressor, so try to transform into one.
The following code is an example of a very bad naming:
The code copy is as follows:
// 6.A.1.1
// Bad naming example code
function q(s) {
return document.querySelectorAll(s);
}
var i,a=[],els=q("#foo");
for(i=0;i<els.length;i++){a.push(els[i]);}
There is no doubt that you have written such code - hope it will not appear again from today.
Here is a code with the same logic, but with a more robust, apt naming (and a readable structure):
The code copy is as follows:
// 6.A.2.1
// Improved named example code
function query( selector ) {
return document.querySelectorAll( selector );
}
var idx = 0,
elements = [],
matches = query("#foo"),
length = matches.length;
for ( ; idx < length; idx++ ) {
elements.push( matches[ idx ] );
}
Some additional naming tips:
The code copy is as follows:
// 6.A.3.1
// Named string
`dog` is a string
// 6.A.3.2
// Name arrays
`['dogs']` is an array containing the `dog string
// 6.A.3.3
// Name functions, objects, instances, etc.
camlCase; function and var declarations
// 6.A.3.4
// Name the builder, prototype, etc.
PascalCase; build function
// 6.A.3.5
// Name regular expressions
rDesc = //;
// 6.A.3.6
// From Google Closure Library Style Guide
functionNamesLikeThis;
variableNamesLikeThis;
ConstructorNamesLikeThis;
EnumNamesLikeThis;
methodNamesLikeThis;
SYMBOLIC_CONSTANTS_LIKE_THIS;
B. Face this
In addition to using well-known call and apply, .bind( this ) or a functionally equivalent to it is always preferred. Create a BoundFunction declaration for subsequent calls, using alias when there is no better option.
The code copy is as follows:
// 6.B.1
function Device( opts ) {
this.value = null;
// Create a new asynchronous stream, this will be continuously called
stream.read( opts.path, function( data ) {
// Use stream to return the latest value of data and update the instance's value
this.value = data;
}.bind(this) );
// Control the frequency of event triggering
setInterval(function() {
// Publish a controlled event
this.emit("event");
}.bind(this), opts.freq || 100 );
}
// Suppose we have inherited the EventEmitter ;)
When it cannot be run, the equivalent of .bind is available in most modern JavaScript libraries.
The code copy is as follows:
// 6.B.2
// Example: lodash/underscore, _.bind()
function Device( opts ) {
this.value = null;
stream.read( opts.path, _.bind(function( data ) {
this.value = data;
}, this) );
setInterval(_.bind(function() {
this.emit("event");
}, this), opts.freq || 100 );
}
// Example: jQuery.proxy
function Device( opts ) {
this.value = null;
stream.read( opts.path, jQuery.proxy(function( data ) {
this.value = data;
}, this) );
setInterval( jQuery.proxy(function() {
this.emit("event");
}, this), opts.freq || 100 );
}
// Example: dojo.hitch
function Device( opts ) {
this.value = null;
stream.read( opts.path, dojo.hitch( this, function( data ) {
this.value = data;
}) );
setInterval( dojo.hitch( this, function() {
this.emit("event");
}), opts.freq || 100 );
}
Provide a candidate to create an alias for this, with self as the identifier. This is very likely to have bugs and should be avoided as much as possible.
The code copy is as follows:
// 6.B.3
function Device( opts ) {
var self = this;
this.value = null;
stream.read( opts.path, function( data ) {
self.value = data;
});
setInterval(function() {
self.emit("event");
}, opts.freq || 100 );
}
C. Use thisArg
Several prototype methods in ES 5.1 have a special thisArg tag built in, use it as much as possible
The code copy is as follows:
// 6.C.1
var obj;
obj = { f: "foo", b: "bar", q: "qux" };
Object.keys( obj ).forEach(function( key ) {
// |this| It's now `obj`
console.log( this[ key ] );
}, obj ); // <-- The last parameter is `thisArg`
// Print out...
// "foo"
// "bar"
// "qux"
ThisArg can be used in Array.prototype.every, Array.prototype.forEach, Array.prototype.some, Array.prototype.map, and Array.prototype.filter.
7. Misc
The ideas and ideas that this part will explain are not dogmatic. Instead, it is more encouraged to be curious about existing practices to try to provide a better solution to complete general JavaScript programming tasks.
A. Avoid using switch. Modern method tracing will blacklist functions with switch expressions.
It seems that both Firefox and Chrome have made significant improvements to switch statements. http://jsperf.com/switch-vs-object-literal-vs-module
It is worth noting that the improvement can be seen here: https://github.com/rwldrn/idiomatic.js/issues/13
The code copy is as follows:
// 7.A.1.1
// Switch statement example
switch( foo ) {
case "alpha":
alpha();
break;
case "beta":
beta();
break;
default:
// Default branch
break;
}
// 7.A.1.2
// A method that can support combination and reuse is to use an object to store "cases".
// Use a function to do delegation:
var cases, delegator;
// The return value is for explanation only
cases = {
alpha: function() {
// Statement
// A return value
return [ "Alpha", arguments.length ];
},
beta: function() {
// Statement
// A return value
return [ "Beta", arguments.length ];
},
_default: function() {
// Statement
// A return value
return [ "Default", arguments.length ];
}
};
delegator = function() {
var args, key, delegate;
// Convert `argument` to an array
args = [].slice.call( arguments );
// Extract the last value from `argument`
key = args.shift();
// Call the default branch
delegate = cases._default;
// Delegate the method from the object
if ( cases.hasOwnProperty( key ) ) {
delegate = cases[ key ];
}
// The scope of arg can be set to a specific value,
// In this case, |null| is fine
return delegate.apply( null, args );
};
// 7.A.1.3
// Use the API in 7.A.1.2:
delegator( "alpha", 1, 2, 3, 4, 5);
// [ "Alpha", 5 ]
// Of course, the value of the `case` key can be easily changed to any value
var caseKey, someUserInput;
// Is there any possible input of some form?
someUserInput = 9;
if ( someUserInput > 10 ) {
caseKey = "alpha";
} else {
caseKey = "beta";
}
// or...
caseKey = someUserInput > 10 ? "alpha" : "beta";
// Then...
delegator( caseKey, someUserInput);
// [ "Beta", 1 ]
// Of course, this can be done...
delegator();
// [ "Default", 0 ]
B. Return values in advance to improve the readability of the code without much performance difference
The code copy is as follows:
// 7.B.1.1
// not good:
function returnLate( foo ) {
var ret;
if ( foo ) {
ret = "foo";
} else {
ret = "quux";
}
return return;
}
// good:
function returnEarly( foo ) {
if ( foo ) {
return "foo";
}
return "quux";
}
8. Native & Host Objects (Note: I have always thought that Host Objects should not be translated, so I will translate it according to the general writing method)
The most basic principle is:
Don't do anything stupid, things will always get better.
To strengthen this concept, please watch this demonstration:
"Everything is allowed: native extension" by Andrew Dupont (JSConf2011, Portland, Oregon)
http://blip.tv/jsconf/jsconf2011-andrew-dupont-everything-is-permitted-extending-built-ins-5211542
9. Comments
Single line comments are placed above the code as the first choice
Multiple lines are OK
Comments at the end of the line should be avoided!
The JSDoc method is also good, but it takes more time
10. Use one language alone
Regardless of what language the program maintainer (or team) stipulates that the program is used, the program should be written in only the same language.
appendix
Comma First
All projects that use this document as a basic style guide do not allow for pre-comma code formats unless explicitly specified or required by the author.