【译】JavaScript规范
译自:https://github.com/airbnb/javascript
类型
-
原始值: 相当于传值
1
2
3
4
5
6
7
8
9
10
11
|
string number boolean null undefined var foo = 1, bar = foo; bar = 9; console.log(foo, bar); // => 1, 9 |
复杂类型: 相当于传引用
-
123456789
object
array
function
var
foo = [1, 2],
bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]);
// => 9, 9
对象
-
使用字面值创建对象
12345// bad
var
item =
new
Object();
// good
var
item = {};
-
不要使用保留字 reserved words 作为键
12345678910111213// bad
var
superman = {
class
:
‘superhero‘
,
default
: { clark:
‘kent‘
},
private
:
true
};
// good
var
superman = {
klass:
‘superhero‘
,
defaults: { clark:
‘kent‘
},
hidden:
true
};
数组
-
使用字面值创建数组
12345// bad
var
items =
new
Array();
// good
var
items = [];
-
如果你不知道数组的长度,使用push
12345678var
someStack = [];
// bad
someStack[someStack.length] =
‘abracadabra‘
;
// good
someStack.push(
‘abracadabra‘
);
-
当你需要拷贝数组时使用slice. jsPerf
1234567891011var
len = items.length,
itemsCopy = [],
i;
// bad
for
(i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
itemsCopy = items.slice();
-
使用slice将类数组的对象转成数组.
1234function
trigger() {
var
args = Array.prototype.slice.call(arguments);
...
}
字符串
-
对字符串使用单引号
‘‘
1234567891011// bad
var
name =
"Bob Parr"
;
// good
var
name =
‘Bob Parr‘
;
// bad
var
fullName =
"Bob "
+
this
.lastName;
// good
var
fullName =
‘Bob ‘
+
this
.lastName;
-
超过80个字符的字符串应该使用字符串连接换行
-
注: 如果过度使用,长字符串连接可能会对性能有影响. jsPerf & Discussion
12345678910111213141516171819// 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.‘
;
-
编程时使用join而不是字符串连接来构建字符串,特别是IE: jsPerf.
1234567891011121314151617181920212223242526272829303132333435363738var
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] = messages[i].message;
}
return
‘<ul><li>‘
+ items.join(
‘</li><li>‘
) +
‘</li></ul>‘
;
}
<函数
-
函数表达式:
1234567891011121314// 匿名函数表达式
var
anonymous =
function
() {
return
true
;
};
// 有名函数表达式
var
named =
function
named() {
return
true
;
};
// 立即调用函数表达式
(
function
() {
console.log(
‘Welcome to the Internet. Please follow me.‘
);
})();
-
绝对不要在一个非函数块里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同。
-
注: ECMA-262定义把
块
定义为一组语句,函数声明不是一个语句。阅读ECMA-262对这个问题的说明.12345678910111213// bad
if
(currentUser) {
function
test() {
console.log(
‘Nope.‘
);
}
}
// good
if
(currentUser) {
var
test =
function
test() {
console.log(
‘Yup.‘
);
};
}
-
绝对不要把参数命名为
arguments
, 这将会逾越函数作用域内传过来的arguments
对象.123456789// bad
function
nope(name, options, arguments) {
// ...stuff...
}
// good
function
yup(name, options, args) {
// ...stuff...
}
属性
-
当使用变量访问属性时使用中括号.
12345678910var
luke = {
jedi:
true
,
age: 28
};
function
getProp(prop) {
return
luke[prop];
}
var
isJedi = getProp(
‘jedi‘
);
变量
-
总是使用
var
来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。12345// bad
superPower =
new
SuperPower();
// good
var
superPower =
new
SuperPower();
-
使用一个
var
以及新行声明多个变量,缩进4个空格。123456789// bad
var
items = getItems();
var
goSportsTeam =
true
;
var
dragonball =
‘z‘
;
// good
var
items = getItems(),
goSportsTeam =
true
,
dragonball =
‘z‘
;
-
最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。
1234567891011121314151617// bad
var
i, len, dragonball,
items = getItems(),
goSportsTeam =
true
;
// bad
var
i, items = getItems(),
dragonball,
goSportsTeam =
true
,
len;
// good
var
items = getItems(),
goSportsTeam =
true
,
dragonball,
length,
i;
-
在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253// 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
;
}
条件表达式和等号
- 适当使用
===
和!==
以及==
和!=
. -
条件表达式的强制类型转换遵循以下规则:
- 对象 被计算为 true
- Undefined 被计算为 false
- Null 被计算为 false
- 布尔值 被计算为 布尔的值
- 数字 如果是 +0, -0, or NaN 被计算为 false , 否则为 true
- 字符串 如果是空字符串
‘‘
则被计算为 false, 否则为 true
1234if
([0]) {
// true
// An array is an object, objects evaluate to true
}
-
使用快捷方式.
12345678910111213141516171819// bad
if
(name !==
‘‘
) {
// ...stuff...
}
// good
if
(name) {
// ...stuff...
}
// bad
if
(collection.length > 0) {
// ...stuff...
}
// good
if
(collection.length) {
// ...stuff...
}
-
阅读 Truth Equality and JavaScript 了解更多
块
-
给所有多行的块使用大括号
12345678910111213141516171819// bad
if
(test)
return
false
;
// good
if
(test)
return
false
;
// good
if
(test) {
return
false
;
}
// bad
function
() {
return
false
; }
// good
function
() {
return
false
;
}
注释
-
使用
/** ... */
进行多行注释,包括描述,指定类型以及参数值和返回值123456789101112131415161718192021222324252627// 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;
}
-
使用
//
进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.12345678910111213141516171819202122232425// 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
或TODO
帮助其他人迅速理解1234567891011121314function
Calculator() {
// FIXME: shouldn‘t use a global here
total = 0;
return
this
;
}
function
Calculator() {
// TODO: total should be configurable by an options param
this
.total = 0;
return
this
;
}
空白
-
将tab设为4个空格
1234567891011121314// bad
function
() {
??
var
name;
}
// bad
function
() {
?
var
name;
}
// good
function
() {
????
var
name;
}
-
大括号前放一个空格
123456789101112131415161718192021// 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‘
});
-
在做长方法链时使用缩进.
1234567891011121314151617181920212223242526// bad
$(
‘#items‘
).find(
‘.selected‘
).highlight().end().find(
‘.open‘
).updateCount();
// good
$(
‘#items‘
)
.find(
‘.selected‘
)
.highlight()
.end()
.find(
‘.open‘
)
.updateCount();
// bad
var
leds = stage.selectAll(
‘.led‘
).data(data).enter().append(
‘svg:svg‘
).
class
(
‘led‘
,
true
)
.attr(
‘width‘
, (radius + margin) * 2).append(
‘svg:g‘
)
.attr(
‘transform‘
,
‘translate(‘
+ (radius + margin) +
‘,‘
+ (radius + margin) +
‘)‘
)
.call(tron.led);
// good
var
leds = stage.selectAll(
‘.led‘
)
.data(data)
.enter().append(
‘svg:svg‘
)
.
class
(
‘led‘
,
true
)
.attr(
‘width‘
, (radius + margin) * 2)
.append(
‘svg:g‘
)
.attr(
‘transform‘
,
‘translate(‘
+ (radius + margin) +
‘,‘
+ (radius + margin) +
‘)‘
)
.call(tron.led);
逗号
-
不要将逗号放前面
12345678910111213141516171819202122232425// 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‘
};
-
不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。
123456789101112131415161718192021// bad
var
hero = {
firstName:
‘Kevin‘
,
lastName:
‘Flynn‘
,
};
var
heroes = [
‘Batman‘
,
‘Superman‘
,
];
// good
var
hero = {
firstName:
‘Kevin‘
,
lastName:
‘Flynn‘
};
var
heroes = [
‘Batman‘
,
‘Superman‘
];
分号
-
语句结束一定要加分号
1234567891011121314151617// bad
(
function
() {
var
name =
‘Skywalker‘
return
name
})()
// good
(
function
() {
var
name =
‘Skywalker‘
;
return
name;
})();
// good
;(
function
() {
var
name =
‘Skywalker‘
;
return
name;
})();
类型转换
- 在语句的开始执行类型转换.
-
字符串:
12345678910111213// => 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
并且总是带上类型转换的基数.123456789101112131415161718192021222324252627var
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;
-
布尔值:
12345678910var
age = 0;
// bad
var
hasAge =
new
Boolean(age);
// good
var
hasAge = Boolean(age);
// good
var
hasAge = !!age;
命名约定
-
避免单个字符名,让你的变量名有描述意义。
123456789// bad
function
q() {
// ...stuff...
}
// good
function
query() {
// ..stuff..
}
-
当命名对象、函数和实例时使用驼峰命名规则
123456789101112131415// 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‘
});
-
当命名构造函数或类时使用驼峰式大写
1234567891011121314151617// 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‘
});
-
命名私有属性时前面加个下划线
_
123456// bad
this
.__firstName__ =
‘Panda‘
;
this
.firstName_ =
‘Panda‘
;
// good
this
._firstName =
‘Panda‘
;
-
当保存对
this
的引用时使用_this
.1234567891011121314151617181920212223// 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);
};
}
存取器
- 属性的存取器函数不是必需的
-
如果你确实有存取器函数的话使用getVal() 和 setVal(‘hello‘)
1234567891011// bad
dragon.age();
// good
dragon.getAge();
// bad
dragon.age(25);
// good
dragon.setAge(25);
-
如果属性是布尔值,使用isVal() 或 hasVal()
123456789// bad
if
(!dragon.age()) {
return
false
;
}
// good
if
(!dragon.hasAge()) {
return
false
;
}
-
可以创建get()和set()函数,但是要保持一致
12345678910111213function
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];
};
构造器
-
给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。
1234567891011121314151617181920212223function
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
帮助方法可链。1234567891011121314151617181920212223242526272829// 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);
-
可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。
123456789101112function
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();
};
事件
-
当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器
12345678// bad
$(
this
).trigger(
‘listingUpdated‘
, listing.id);
...
$(
this
).on(
‘listingUpdated‘
,
function
(e, listingId) {
// do something with listingId
});
更好:
12345678// good
$(
this
).trigger(
‘listingUpdated‘
, { listingId : listing.id });
...
$(
this
).on(
‘listingUpdated‘
,
function
(e, data) {
// do something with data.listingId
});
模块
- 模块应该以
!
开始,这保证了如果一个有问题的模块忘记包含最后的分号在合并后不会出现错误 - 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致
- 加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它
-
总是在模块顶部声明
‘use strict‘;
123456789101112131415161718// fancyInput/fancyInput.js
!
function
(global) {
‘use strict‘
;
var
previousFancyInput = global.FancyInput;
function
FancyInput(options) {
this
.options = options || {};
}
FancyInput.noConflict =
function
noConflict() {
global.FancyInput = previousFancyInput;
return
FancyInput;
};
global.FancyInput = FancyInput;
}(
this
);
jQuery
-
缓存jQuery查询
12345678910111213141516171819202122// 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‘
});
}
-
对DOM查询使用级联的
$(‘.sidebar ul‘)
或$(‘.sidebar ul‘)
,jsPerf -
对有作用域的jQuery对象查询使用
find
1234567891011121314151617// bad
$(
‘.sidebar‘
,
‘ul‘
).hide();
// bad
$(
‘.sidebar‘
).find(
‘ul‘
).hide();
// good
$(
‘.sidebar ul‘
).hide();
// good
$(
‘.sidebar > ul‘
).hide();
// good (slower)
$sidebar.find(
‘ul‘
);
// good (faster)
$($sidebar[0]).find(
‘ul‘
);
ECMAScript 5兼容性
-
参考Kangax的 ES5 compatibility table
性能
- On Layout & Web Performance
- String vs Array Concat
- Try/Catch Cost In a Loop
- Bang Function
- jQuery Find vs Context, Selector
- innerHTML vs textContent for script text
- Long String Concatenation
-
Loading...
资源
Read This
其它规范
- Google JavaScript Style Guide
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
其它风格
- Naming this in nested functions - Christian Johansen
- Conditional Callbacks
阅读更多
- Understanding JavaScript Closures - Angus Croll
书籍
- JavaScript: The Good Parts - Douglas Crockford
- JavaScript Patterns - Stoyan Stefanov
- Pro JavaScript Design Patterns - Ross Harmes and Dustin Diaz
- High Performance Web Sites: Essential Knowledge for Front-End Engineers - Steve Souders
- Maintainable JavaScript - Nicholas C. Zakas
- JavaScript Web Applications - Alex MacCaw
- Pro JavaScript Techniques - John Resig
- Smashing Node.js: JavaScript Everywhere - Guillermo Rauch
标签:
原文地址:http://www.cnblogs.com/ziye/p/4415176.html