求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
 
我要提问 
Javascript 风格向导
 

发布于2013-5-23

 

大部分针对Javascript最合理的方法归纳。

类型

原始类型:我们可以直接使用值。

  • string
  • number
  • boolean
  • null
  • undefined
var foo = 1,
    bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9

复合类型:我们通过`引用`对值进行间接访问。

  • object
  • array
  • function

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 = [];

  • 如果你不知道数组长度,使用Array#push。

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,这样将快速帮助开发者快速明白代码意图。

  • 使用 // FIXME: 注释问题
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;
}

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();
};

 




Android手机开发(一)
理解Javascript
非典型ajax实践
彻底的Ajax
javascript 使用Cookies
使用 jQuery 简化 Ajax 开发
更多...   


Struts+Spring+Hibernate
基于J2EE的Web 2.0应用开发
J2EE设计模式和性能调优
Java EE 5企业级架构设计
Java单元测试方法与技术
Java编程方法与技术


某航空公司IT部 JavaScript实践
某电视软件 HTML5和JavaScript
中航信 JavaScript高级应用开发
大庆油田 web界面Ajax开发技术
和利时 使用AJAX进行WEB应用开发
更多...