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.


Related articles: