var foo = 1;
var bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9
复合类型 Objects
创建对象,使用literal syntax
// bad
var item = new Object();
// good
var item = {};
不要使用保留字reserved words
// bad
var superman = {
default: { clark: 'kent' },
private: true
};
// good
var superman = {
defaults: { clark: 'kent' },
hidden: true
};
使用可读性强的同义词代替保留字
// bad
var superman = {
class: 'alien'
};
// bad
var superman = {
klass: 'alien'
};
// good
var superman = {
type: 'alien'
};
数组 Arrays
创建对象,使用literal syntax
// bad
var items = new Array();
// good
var items = [];
使用push方法
var someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
需要复制数组时,使用slice
var len = items.length;
var itemsCopy = [];
var i;
// bad
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
itemsCopy = items.slice();
使用slice将对象转换为数组
function trigger() {
var args = Array.prototype.slice.call(arguments);
...
}
字符串 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.';
以编程方式创建字符串的时应该使用Array的join方法而不是通过连接符,尤其是在IE中
var items;
var messages;
var length;
var 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++) {
// use direct assignment in this case because we're micro-optimizing.
items[i] = 'li' + messages[i].message + 'li';
}
return 'ul' + items.join('') + 'ul';
}
函数 Functions
函数表达式
// 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.');
})();
不要再非函数块(if,while)中声明函数
// bad
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// good
var test;
if (currentUser) {
test = function test() {
console.log('Yup.');
};
}
不要命名一个参数为arguments,否则它将优先于传递给每个函数作用域中的arguments对象
// bad
function nope(name, options, arguments) {
// ...stuff...
}
// good
function yup(name, options, args) {
// ...stuff...
}
属性 Properties
使用点表示法访问属性
var luke = {
jedi: true,
age: 28
};
// bad
var isJedi = luke['jedi'];
// good
var isJedi = luke.jedi;
用变量访问属性时要使用下标表示法([])
var luke = {
jedi: true,
age: 28
};
function getProp(prop) {
return luke[prop];
}
var isJedi = getProp('jedi');
变量 Variables
总是使用var声明变量,不然其将变为全局变量。我们要想办法避免全局空间污染
// bad
superPower = new SuperPower();
// good
var superPower = new SuperPower();
使用var声明每个变量,这样很容易添加新的变量声明
// bad
var items = getItems(),
goSportsTeam = true,
dragonball = 'z';
// bad
// (compare to above, and try to spot the mistake)
var items = getItems(),
goSportsTeam = true;
dragonball = 'z';
// good
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';
最后声明未赋值的变量,这对于你需要根据之前已经赋值的变量对其他变量进行赋值时是很有帮助的
// bad
var i, len, dragonball,
items = getItems(),
goSportsTeam = true;
// bad
var i;
var items = getItems();
var dragonball;
var goSportsTeam = true;
var len;
// good
var items = getItems();
var goSportsTeam = true;
var dragonball;
var length;
var i;
在作用域顶端对变量赋值
// 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 - unnessary function call
function() {
var name = getName();
if (!arguments.length) {
return false;
}
this.setFirstName(name);
return true;
}
// good
function() {
var name;
if (!arguments.length) {
return false;
}
name = getName();
this.setFirstName(name);
return true;
}
声明 Hoisting
变量声明是在作用域顶端,但并未赋值
Variable declarations get hoisted to the top of their scope, but their assignment does not.
// 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 interpreter 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;
}
匿名表达式可以提升变量,但不能提升函数
Anonymous function expressions hoist their variable name, but not the function assignment.
命名表达式会提升变量,而不是函数名或者函数体
function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is not a function
var anonymous = function() {
console.log('anonymous function expression');
};
}
函数声明会提升变量和函数
Named function expressions hoist the variable name, not the function name or the function body.Function declarations hoist their name and the function body.
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');
}
}
运算符 Comparison Operators & Equality
使用===和!==代替==和!=
比较运算符进行计算时会利用ToBoolean方法进行强制转换数据类型,并遵从以下规则
Objects的计算值是true
Undefined的计算值是false
Boolean的计算值是本身
Numbers如果是-0,+0或者NaN,则计算值是false反之是true
Strings如果是空,则计算值是false,反之是true
if ([0]) {
// true
// An array is an object, objects evaluate to true
}
Tips
// bad
if (name !== '') {
// ...stuff...
}
// good
if (name) {
// ...stuff...
}
// bad
if (collection.length > 0) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
语句块 Blocks
对多行语句块使用大括号brace
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function() { return false; }
// good
function() {
return false;
}
对于if-else语句块,把if的右括号和else的左括号放在同一行
// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
注释 Comments
多行注释使用/*…/,需包含一个描述,所有参数的具体类型,值和返回值
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {
// ...stuff...
return element;
}
// good
/**
\* make() returns a new element
\* based on the passed in tag name
\*
\* @param {String} tag
\* @return {Element} element
*/
function make(tag) {
// ...stuff...
return element;
}
单行注释使用//,注释放在语句的上一行,并在注释之前留空行
// 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';
return type;
}
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
var type = this._type || 'no type';
return type;
}
如果你指出的问题需要重新定位或者提出一个待解决的问题需要实现,给注释添加 FIXME or TODO 前缀有利于其他开发者快速理解。这些注释不同于通常的注释,因为它们是可实施的。这些实施措施就是 FIXME – need to figure this out or TODO – need to implement
function Calculator() {
// FIXME: shouldn't use a global here
total = 0;
return this;
}
使用 //TODO: 给问题解决方案作注释
function Calculator() {
// TODO: total should be configurable by an options param
this.total = 0;
return this;
}
空白 Whitespace
设置制表符为两个空格soft tabs
在左大括号前留一个空格
// 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'
});
在控制语句中(if, while etc),左括号之前留一个空格。函数的参数列表之前不要有空格
// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}
// bad
var story = [
once
, upon
, aTime
];
// good
var story = [
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'
};
不要有多余的逗号
分号 Semicolons
Yup
// bad
(function() {
var name = 'Skywalker'
return name
})()
// good
(function() {
var name = 'Skywalker';
return name;
})();
// good (guards against the function becoming an argument when two files with IIFEs are concatenated)
;(function() {
var name = 'Skywalker';
return name;
})();
类型分配和强制转换 Type casting & Coercion
在声明时进行类型转换
Strings
// => 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';
使用parseInt对Numbers进行转换,不要省略进制参数
var inputValue = '4';
// bad
var val = new Number(inputValue);
// bad
var val = +inputValue;
// bad
var val = inputValue >> 0;
// bad
var val = parseInt(inputValue);
// good
var val = Number(inputValue);
// good
var val = parseInt(inputValue, 10);
// good
/**
\* parseInt was the reason my code was slow.
\* Bitshifting the String to coerce it to a
\* Number made it a lot faster.
*/
var val = inputValue >> 0;
var age = 0;
// bad
var hasAge = new Boolean(age);
// good
var hasAge = Boolean(age);
// good
var hasAge = !!age;
命名规范
避免单字母名称,使其具有描述性
// bad
function q() {
// ...stuff...
}
// good
function query() {
// ..stuff..
}
使用驼峰法命名变量、函数和类名
// bad
var OBJEcttsssss = {};
var this_is_my_object = {};
var o = {};
function c() {}
// good
var thisIsMyObject = {};
function thisIsMyFunction() {}
命名私有属性时使用前置下划线underscore
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
// good
this._firstName = 'Panda';
this引用使用_this变量
// bad
function() {
var self = this;
return function() {
console.log(self);
};
}
// bad
function() {
var that = this;
return function() {
console.log(that);
};
}
// good
function() {
var _this = this;
return function() {
console.log(_this);
};
}
命名函数时,下面方式有利于堆栈跟踪
// bad
var log = function(msg) {
console.log(msg);
};
// good
var log = function log(msg) {
console.log(msg);
};
如果文件单独包含一个类,文件名应该和类名保持一致
// file contents
class CheckBox {
// ...
}
module.exports = CheckBox;
// in some other file
// bad
var CheckBox = require('./checkBox');
// bad
var CheckBox = require('./check_box');
// good
var CheckBox = require('./CheckBox');
存取器 Accessors
对于属性,访问器函数不是必须的
如果定义了存取器函数,应参照 getVal() 和 setVal(‘hello’) 格式
// bad
dragon.age();
// good
dragon.getAge();
// bad
dragon.age(25);
// good
dragon.setAge(25);
如果属性是boolean,格式应为 isVal() 和 hasVal()
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
// bad
$('ul', '.sidebar').hide();
// bad
$('.sidebar').find('ul').hide();
// good
$('.sidebar ul').hide();
// good
$('.sidebar > ul').hide();
// good
$sidebar.find('ul').hide();