序
大部分针对Javascript最合理的方法归纳。
类型
原始类型:我们可以直接使用值。
- string
- number
- boolean
- null
- undefined
var foo = 1,
bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9 |
复合类型:我们通过`引用`对值进行间接访问。
objects
//
bad
var item = new Object()
// good
var item = {}; |
// bad
var superman = {
class: 'superhero',
default: { clark: 'kent' },
private: true
};
// good
var superman = {
klass: 'superhero',
defaults: { clark: 'kent' },
hidden: true
};
|
Arrays
//
bad
var items = new Array();
// good
var items = []; |
var
someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra'); |
- 当你需要复制数组的时候,请使用Array#slice。
var
len = items.length,
itemsCopy = [],
i;
// bad
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
itemsCopy = items.slice(); |
Strings
//
bad
var name = "Bob Parr";
// good
var name = 'Bob Parr';
// bad
var fullName = "Bob " + this.lastName;
// good
var fullName = 'Bob ' + this.lastName; |
- 超过80个字符的字符串,我们使用串联符号(\),让字符串多行显示。
注意:如果过度使用带串联符号的字符可能会影响到性能。
//
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,
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>';
} |
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
if (currentUser) {
var test = function test() {
console.log('Yup.');
};
} |
- 绝对不要把一个参数命名为arguments,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; |
- 当以变量的方式访问属性的时候,用下标符号([])。——除非特殊需求,否则尽量避免使用obj[variable]的方式进行属性访问。
var
luke = {
jedi: true,
age: 28
};
function getProp(prop) {
return luke[prop];
}
var isJedi = getProp('jedi'); |
variables
- 总是使用var定义变量,否则会导致产生隐含全局变量。我们要尽量避免污染全局变量命名空间。
使用一个var定义多个变量,每个变量在一个新行上。
//
bad
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';
// good
var items = getItems(),
goSportsTeam = true,
dragonball = 'z'; |
- 用var定义多个变量的时候,把不进行赋值的变量放置到最后——这是相当有益的。尤其是当你的变量需要赋前面变量值的时候。
//
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; |
- 把你的赋值变量放置在当前作用域的顶端。这将避免变量声明和hoisting(悬置/置顶解析/预解析)的问题。
//
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;
} |
Hoisting
- 变量声明提升到当前作用域的顶端,而它们的赋值操作不一定要这么做。
function example() { console.log(notDefined); // => throws a ReferenceError }
function example() {
console.log(declaredButNotAssigned); // =>
undefined
var declaredButNotAssigned = true;
}
function example() {
var declaredButNotAssigned;
console.log(declaredButNotAssigned); // =>
undefined
declaredButNotAssigned = true;
}
|
- 匿名表达式会自动提升它们的变量名称(也就是说在var anonymous上面,example函数就已经知道有这个变量了),但是它们的函数体不会。
function example() { console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is
not a function
var anonymous = function() {
console.log('anonymous function expression');
};
} |
- 命名函数表达式也会提升它们的变量名称,而它们的函数名称和函数体不会这样做。
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');
};
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
var named = function named() {
console.log('named');
};
}
} |
- 注意:函数声明会提升它们的变量名称还有它们的函数体。
function
example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}
|
== 和 != 会进行隐式类型转换,所以建议使用===和!==。
- 强制使用对象的特性(ToBoolean)得到条件表达式的值,大致遵循以下简单规则。
Objects 得到的值是true。
Undefined得到的值是false。
Null得到的值是false。
Booleans得到的值是Boolean值(呵呵,当然)。
Numbers 得到的值是:如果是+0,-0,或者NaN就是false,否则就是true。
Strings 得到的值是:如果是'',就是false,否则就是true。
Blocks
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function() { return false; }
// good
function() {
return false;
} |
Comments
- 对于多行注释使用/** ... */。包含描述信息、参数类型和返回值。
private async void btnClick_Click(object sender, EventArgs e)
{
long length = await AccessWebAsync();
// 这里可以做一些不依赖回复的操作
OtherWork();
this.richTextBox1.Text += String.Format("\n 回复的字节长度为: {0}.\r\n", length);
txbMainThreadID.Text = Thread.CurrentThread.ManagedThreadId.ToString();
}
// 使用C# 5.0中提供的async 和await关键字来定义异步方法
// 从代码中可以看出C#5.0 中定义异步方法就像定义同步方法一样简单。
// 使用async 和await定义异步方法不会创建新线程,
// 它运行在现有线程上执行多个任务.
// 此时不知道大家有没有一个疑问的?在现有线程上(即UI线程上)运行一个耗时的操作时,
// 为什么不会堵塞UI线程的呢?
// 这个问题的答案就是 当编译器看到await关键字时,线程会
private async Task AccessWebAsync()
{
MemoryStream content = new MemoryStream();
// 对MSDN发起一个Web请求
HttpWebRequest webRequest = WebRequest.Create("http://msdn.microsoft.com/zh-cn/") as HttpWebRequest;
if (webRequest != null)
{
// 返回回复结果
using (WebResponse response = await webRequest.GetResponseAsync())
{
using (Stream responseStream = response.GetResponseStream())
{
await responseStream.CopyToAsync(content);
}
}
}
txbAsynMethodID.Text = Thread.CurrentThread.ManagedThreadId.ToString() ;
return content.Length;
}
private void OtherWork()
{
this.richTextBox1.Text += "\r\n等待服务器回复中.................\n";
} |
- 对于单行注释使用//。单行注释单独放置在一个新行上。在注释前面放置一个空行。
// 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,这样将快速帮助开发者快速明白代码意图。
function 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;
} |
Type Casting & Coercion
在声明之前执行强制类型转换。
// => 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,而且要带着类型转换的基数。
如果parseInt成为你的瓶颈,处于性能原因,需要你使用“位移”操作。那么请写下注释解释你这样做的原因
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 使我的代码变慢.
* 为了提高速度,使用位移操作让字符串强制转化为数字。
*/
var val = inputValue >> 0; |
var age = 0;
// bad
var hasAge = new Boolean(age);
// good
var hasAge = Boolean(age);
// good
var hasAge = !!age; |
constructors
用方法扩展对象,而不是用一个新对象。
function 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');
}; |
- 让对象的方法return this,这样有利于方法的链锁操作。
// 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()方法。——要确保它能正常运行,而且不会产生其他影响。
function 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();
}; |
|