Modern JavaScript development programming style Idiomatic omatic. Js guide Chinese version
- 2020-03-30 03:05:53
- OfStack
The style you choose for your project should be of the highest standard. Place it in your project as a description and link to the document as a guarantee of code style consistency, readability, and maintainability.
A blank,
Second, beautify grammar
A. Braces, curly braces, line breaks
//If /else/for/while/try usually has braces, curly braces, and multiple lines
//This helps to be readable
// 2.A.1.1
//Examples of audible grammar (cramped syntax)
if(condition) doSomething();
while(condition) iterating++;
for(var i=0;i<100;i++) someIterativeFn();
// 2.A.1.1
//Use whitespace to improve readability
if ( condition ) {
// statements
}
while ( condition ) {
// statements
}
for ( var i = 0; i < 100; i++ ) {
// statements
}
//Better practices:
var i,
length = 100;
for ( i = 0; i < length; i++ ) {
// statements
}
//Or...
var i = 0,
length = 100;
for ( ; i < length; i++ ) {
// statements
}
var prop;
for ( prop in object ) {
// statements
}
if ( true ) {
// statements
} else {
// statements
}
B. Assignment, declaration, function (named function, function expression, build function)
// 2.B.1.1
// variable
var foo = "bar",
num = 1,
undef;
//Literal identity:
var array = [],
object = {};
// 2.B.1.2
//Using only one 'var' in a scope (function) can help improve readability
//And get your statement list organized (and save you a few keystrokes)
// bad
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 its scope
//Also applicable to constants from ECMAScript 6
// bad
function foo() {
//There are statements before variables
var bar = "",
qux;
}
// good
function foo() {
var bar = "",
qux;
//All statements are after variables
}
// 2.B.2.1
//Named function declaration
function foo( arg1, argN ) {
}
//Method of use
foo( arg1, argN );
// 2.B.2.2
//Named function declaration
function square( number ) {
return number * number;
}
//Method of use
square( 10 );
//A very unnatural style of continuation passing
function square( number, callback ) {
callback( number * number );
}
square( 10, function( square ) {
//Content of the callback
});
// 2.B.2.3
//Functional expression
var square = function( number ) {
//Returns valuable, relevant content
return number * number;
};
//A function expression with an identifier
//This preferred form has additional functionality that allows it to invoke itself
//And it has 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;
}
//Method of use
var fooBar = new FooBar({ a: "alpha" });
fooBar.options;
// { a: "alpha" }
C. exceptions and details
// 2.C.1.1
//Bring back the function of the call
foo(function() {
//Note: there is no space in the parentheses and 'function' of the first function call
});
//The function takes' array 'as an argument, with no space
foo([ "alpha", "beta" ]);
// 2.C.1.2
//The function takes' object 'as an argument, with no space
foo({
a: "alpha",
b: "beta"
});
//The function takes the literal of 'string' as an argument, with no Spaces
foo("bar");
//Inside the brackets used for grouping, there is no space
if ( !("foo" in obj) ) {
}
D. Consistency Always Wins
In section 2.a-2.c, white space is presented as A recommendation for A simple, higher purpose: unity. It is worth noting that formatting preferences such as "internal white space" must be optional, but only one must exist in the source code of the entire project.
// 2.D.1.1
if (condition) {
// statements
}
while (condition) {
// statements
}
for (var i = 0; i < 100; i++) {
// statements
}
if (true) {
// statements
} else {
// statements
}
E. quotes
It doesn't matter whether you choose single or double quotes, in JavaScript they make no difference in terms of parsing. What is absolutely mandatory is consistency. Never mix two quotes in the same project. Choose one and keep it consistent.
F. End of line and blank line
White space breaks the distinction and USES changes that are unreadable. Consider including a pre-committed hook that automatically deletes the Spaces at the end of the line and in the blank line.
Iii. Type detection (from jQuery Core Style Guidelines)
A. direct Types (Actual Types, Actual Types)
String:
typeof variable === "string"
Number:
typeof variable === "number"
Boolean:
typeof variable === "boolean"
Object:
typeof variable === "object"
Array:
Array.isArray( arrayLikeObject )
( If possible )
The Node:
elem.nodeType === 1
Null:
variable === null
Null or undefined:
variable == null
Undefined:
Global variables:
typeof variable === "undefined"
Local variables:
variable === undefined
Properties:
object.prop === undefined
object.hasOwnProperty( prop )
"prop" in object
B. Coerced, Coerced Types
Consider the implications of the following...
The given HTML:
<input type="text" id="foo-input" value="1">
// 3.B.1.1
//'foo' has been given the value '0', of type 'number'
var foo = 0;
// typeof foo;
// "number"
...
//In the following code, you need to update 'foo' to give it the new value in the input element
foo = document.getElementById("foo-input").value;
//If you now test 'typeof foo', the result will be 'string'
//This means that you detect 'foo' in the if statement with logic similar to this:
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 types to solve the problem:
foo = +document.getElementById("foo-input").value;
// The ^ + unary operator converts the operator to its right to 'number'
// typeof foo;
// "number"
if ( foo === 1 ) {
importantTask();
}
// `importantTask()` Will be called
Here are a few examples of casts:
// 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's important to note that these are all "unnecessarily clever"
//Use an explicit scheme to compare the returned values
//As indexOf:
if ( array.indexOf( "a" ) >= 0 ) {
// ...
}
// 3.B.2.3
var num = 2.5;
parseInt( num, 10 );
//Equivalent to...
~~num;
num >> 0;
num >>> 0;
//It's going to be 2
//Keep in mind that negative values will be treated differently...
var neg = -2.5;
parseInt( neg, 10 );
//Equivalent to...
~~neg;
neg >> 0;
//It's going to be minus 2
//But...
neg >>> 0;
// The result is 4294967294
Contrast operation
// 4.1.1
//When simply determining whether an array has a length, as opposed to using this:
if ( array.length > 0 ) ...
//. To determine authenticity, use this:
if ( array.length ) ...
// 4.1.2
//When simply determining whether an array is empty, as opposed to using this:
if ( array.length === 0 ) ...
//. To determine authenticity, use this:
if ( !array.length ) ...
// 4.1.3
//When just determining whether a string is empty, as opposed to using this:
if ( string !== "" ) ...
//. To determine authenticity, use this:
if ( string ) ...
// 4.1.4
//When just judging a string to be empty, as opposed to using this:
if ( string === "" ) ...
//. To determine authenticity, use this:
if ( !string ) ...
// 4.1.5
//When just judging a reference to be true, as opposed to using this:
if ( foo === true ) ...
//. Judge just as you think, to enjoy the benefits of the built-in functionality:
if ( foo ) ...
// 4.1.6
//When just judging a reference to be false, as opposed to using this:
if ( foo === false ) ...
//. Use an exclamation point to convert it to true
if ( !foo ) ...
//. Note that this will match 0, "", null, undefined, NaN
//If you _ must _ be false of Boolean type, use this:
if ( foo === false ) ...
// 4.1.7
//If you want to evaluate a reference it might be null or undefined, but not false, "" or 0,
//As opposed to using this:
if ( foo === null || foo === undefined ) ...
//. Enjoy the benefits of == type casting, like this:
if ( foo == null ) ...
//Remember, using == will make 'null' match 'null' and 'undefined'
//But not 'false', "" or 0
null == undefined
Always judge the best and most accurate values, and the above are guidelines rather than dogmas.
// 4.2.1
//Description of type conversion and comparison operations
//First '===', '==' next (unless comparison of loose types is required)
//'===' is never cast, which means:
"1" === 1;
// false
//'==' converts the type, which means:
"1" == 1;
// true
// 4.2.2
//Boolean, true & false
//Boolean:
true, false
// true :
"foo", 1
// pseudo :
"", 0, null, undefined, NaN, void 0
Five, practical style
// 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() {
//I get the value of 'data'
return data;
},
setData: function( value ) {
//Returns the assigned value of 'data'
return ( data = value );
}
};
})();
//Some of the others will show up 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 );
};
//Instead of using 'new' to call the constructor, you might do something like this:
var ctor = function( foo ) {
return new Ctor( foo );
};
//Make our builder a global object
global.ctor = ctor;
})( this );
Six, named
A. you are not A human compiler/compressor, so try to be one.
Here's a copy of the code with the same logic, but with a more robust, aptly named (and a readable structure) :
// 6.A.2.1
//Improved named sample 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:
// 6.A.3.1
//Named string
`dog` Is a string
// 6.A.3.2
//Naming the arrays
`['dogs']` Is a contain `dog A string of array
// 6.A.3.3
//Named functions, objects, instances, etc
camlCase; function and var The statement
// 6.A.3.4
//Name builders, prototypes, etc
PascalCase; Build a function
// 6.A.3.5
//Named regular expression
rDesc = //;
// 6.A.3.6
//From Google Closure Library Style Guide
functionNamesLikeThis;
variableNamesLikeThis;
ConstructorNamesLikeThis;
EnumNamesLikeThis;
methodNamesLikeThis;
SYMBOLIC_CONSTANTS_LIKE_THIS;
B. in the face of this
In addition to using the well-known call and apply, always prefer.bind(this) or a functionally equivalent to it. Create the BoundFunction declaration for subsequent calls, and use the alias when no better option is available.
// 6.B.1
function Device( opts ) {
this.value = null;
//Create a new asynchronous stream, which will be called continuously
stream.read( opts.path, function( data ) {
//Use the stream to return the latest value of the data and update the value of the instance
this.value = data;
}.bind(this) );
//Controls how often events are triggered
setInterval(function() {
//Issue a controlled event
this.emit("event");
}.bind(this), opts.freq || 100 );
}
// Suppose we have inherited the event sender ( EventEmitter ) ;)
When not running, the equivalent of.bind is available in most modern JavaScript libraries.
// 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: the jQuery. The 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: the 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 and create an alias for this with self as the identifier. This is very buggy and should be avoided if possible.
// 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 of the prototype methods in ES 5.1 have a special thisArg tag built in, and use it as much as possible
// 6.C.1
var obj;
obj = { f: "foo", b: "bar", q: "qux" };
Object.keys( obj ).forEach(function( key ) {
//|this| is now 'obj'
console.log( this[ key ] );
}, obj ); //<-- the last parameter is' thisArg '
//Print it 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.
Seven, Misc
The ideas and ideas to be explained in this section are not dogma. Instead, it encourages curiosity about existing practices to try to provide a better solution to common JavaScript programming tasks.
A. Avoid using switch. Method tracing will blacklist functions with switch expressions.
It seems that both the latest versions of Firefox and Chrome have significant improvements to the switch statement. 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
// 7.A.1.1
//Switch statement example
switch( foo ) {
case "alpha":
alpha();
break;
case "beta":
beta();
break;
default:
//The default branch
break;
}
// 7.A.1.2
//One way to support composition and reuse is to use an object to store "cases,"
//Delegate using a function:
var cases, delegator;
//The return value is for explanatory purposes only
cases = {
alpha: function() {
// statements
//A return value
return [ "Alpha", arguments.length ];
},
beta: function() {
// statements
//A return value
return [ "Beta", arguments.length ];
},
_default: function() {
// statements
//A return value
return [ "Default", arguments.length ];
}
};
delegator = function() {
var args, key, delegate;
//Convert 'argument' into an array
args = [].slice.call( arguments );
//Extract the last value from 'argument'
key = args.shift();
//Invoke the default branch
delegate = cases._default;
//Delegate a method from an object
if ( cases.hasOwnProperty( key ) ) {
delegate = cases[ key ];
}
//The scope of an arg can be set to a specific value,
//In this case, |null| will do
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 'case' key can be easily replaced with any value
var caseKey, someUserInput;
//Could it be some form of input?
someUserInput = 9;
if ( someUserInput > 10 ) {
caseKey = "alpha";
} else {
caseKey = "beta";
}
//Or...
caseKey = someUserInput > 10 ? "alpha" : "beta";
//And then...
delegator( caseKey, someUserInput );
// [ "Beta", 1 ]
//Of course you can do it this way...
delegator();
// [ "Default", 0 ]
B. The early return value improves the readability of the code without much performance difference
// 7.B.1.1
//Bad:
function returnLate( foo ) {
var ret;
if ( foo ) {
ret = "foo";
} else {
ret = "quux";
}
return ret;
}
// good :
function returnEarly( foo ) {
if ( foo ) {
return "foo";
}
return "quux";
}
8. Native & Host Objects
The basic principle is:
Don't do anything stupid, things will get better.
To reinforce this idea, 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
Nine, comments,
Single-line note release above the code is preferred
Multiple lines are fine
End-of-line comments should be avoided!
The JSDoc approach is also good, but it takes a lot of time
Use only one language
No matter what language the maintainer (or team) dictates, the program should be written in the same language.
The appendix
Comma First
All projects that use this document as a basic style guide do not allow a code format with commas in front of it, unless explicitly specified or requested by the author.