JavaScript最全编码规范(精)

类型 
1.基本类型:访问基本类型时,应该直接操作类型值

  • string

  • number

  • boolean

  • null

  • undefined

 

var foo = 1;

var bar = foo;

bar = 9;

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

2.复合类型:访问复合类型时,应该操作其引用

  • object

  • array

  • function

 

var foo = [1, 2];

var bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

对象

  • 使用字面量语法创建对象

 

// bad

var item = new Object();

 

// good

var item = {};

  • 不要使用保留字,在IE8中不起作用,更多相关信息

 

// 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'

};

数组

  • 使用字面量语法创建数组

 

// bad

var items = new Array();

 

// good

var items = [];

  • 添加数组元素时,使用push而不是直接添加

 

var someStack = [];

 

// bad

someStack[someStack.length] = 'abracadabra';

 

// good

someStack.push('abracadabra');

  • 需要复制数组时,可以使用slice,jsPerf的相关文章

 

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

...

}

字符串

  • 对字符串使用单引号

 

// 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.

 

// 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中:jsPerf.

 

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++) {

items[i] = '<li>' + messages[i].message + '</li>';

}

 

return '<ul>' + items.join('') + '</ul>';

}

函数

  • 函数表达式

 

// 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, etc)声明函数,尽管浏览器允许你分配函数给一个变量,但坏消息是,不同的浏览器用不同的方式解析它

  • 注意:ECMA-262把块定义为一组语句,但函数声明不是一个语句:Read ECMA-262’s note on this issue.

 

// 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...

}

属性

  • 使用点表示法访问属性

 

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');

变量

  • 总是使用var声明变量,不然其将变为全局变量。我们要想办法避免全局空间污染

 

// bad

superPower = new SuperPower();

 

// good

var superPower = new SuperPower();

  • 使用var声明每个变量,这样很容易添加新的变量声明,而不用去担心用a;替换a,

 

// 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

function() {

var name = getName();

 

if (!arguments.length) {

return false;

}

 

return true;

}

 

// good

function() {

if (!arguments.length) {

return false;

}

 

var name = getName();

 

return true;

}

声明提升

  • 变量声明是在作用域的顶端,但是赋值没有

 

// 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;

}

  • 匿名表达式能提升他们的变量名,但不能提升函数赋值

 

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');

};

}

 

// 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');

}

}

  • 函数声明会提升变量名和函数体

 

function example() {

superPower(); // => Flying

 

function superPower() {

console.log('Flying');

}

}

更多信息指引:JavaScript Scoping & Hoisting by Ben Cherry. 
比较运算符&相等

  • 使用===和!==代替==和!=

  • 比较运算符进行计算时会利用ToBoolean方法进行强制转换数据类型,并遵从一下规则

  • Objects的计算值是true

  • Undefined的计算值是false

  • Boolean的计算值是boolean的值

  • Numbers如果是-0,+0或者NaN,则计算值是false,反之是true

  • Strings如果是空,则计算值是false,反之是true

 

if ([0]) {

// true

// An array is an object, objects evaluate to true

}

  • 使用快捷方式

 

// bad

if (name !== '') {

// ...stuff...

}

 

// good

if (name) {

// ...stuff...

}

 

// bad

if (collection.length > 0) {

// ...stuff...

}

 

// good

if (collection.length) {

// ...stuff...

}

语句块

  • 对多行的语句块使用大括号

 

// 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的多行语句块,把else和if语句块的右大括号放在同一行

 

// bad

if (test) {

thing1();

thing2();

}

else {

thing3();

}

 

// good

if (test) {

thing1();

thing2();

} else {

thing3();

}

注释

  • 多行注释使用/** … */,需包含一个描述、所有参数的具体类型和值以及返回值

 

// 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.

  • 使用// 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;

}

空白

  • 使用软制表符设置两个空格

 

// bad

function() {

∙∙∙∙var name;

}

 

// bad

function() {

var name;

}

 

// good

function() {

∙∙var name;

}

  • 在左大括号之前留一个空格

 

// 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 x=y+5;

 

// good

var x = y + 5;

  • 用一个换行符结束文件

 

// bad

(function(global) {

// ...stuff...

})(this);

// bad

(function(global) {

// ...stuff...

})(this);↵

// good

(function(global) {

// ...stuff...

})(this);↵

  • 当调用很长的方法链时使用缩进,可以强调这行是方法调用,不是新的语句

 

// bad

$('#items').find('.selected').highlight().end().find('.open').updateCount();

 

// 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').classed('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')

.classed('led', true)

.attr('width', (radius + margin) * 2)

.append('svg:g')

.attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')

.call(tron.led);

  • 在语句块和下一个语句之前留一个空行

 

// bad

if (foo) {

return bar;

}

return baz;

 

// good

if (foo) {

return bar;

}

 

return baz;

 

// bad

var obj = {

foo: function() {

},

bar: function() {

}

};

return obj;

 

// good

var obj = {

foo: function() {

},

 

bar: function() {

}

};

 

return obj;

逗号

  • 不要在语句前留逗号

 

// 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'

};

  • 不要有多余逗号:这会在IE6、IE7和IE9的怪异模式中导致一些问题;同时,在ES3的一些实现中,多余的逗号会增加数组的长度。在ES5中已经澄清(source)

 

// bad

var hero = {

firstName: 'Kevin',

lastName: 'Flynn',

};

 

var heroes = [

'Batman',

'Superman',

];

 

// good

var hero = {

firstName: 'Kevin',

lastName: 'Flynn'

};

 

var heroes = [

'Batman',

'Superman'

];

分号

  • 恩,这也是规范一部分

 

// 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;

})();

阅读更多

类型分配&强制转换

  • 执行强制类型转换的语句。

  • 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);

  • 无论出于什么原因,或许你做了一些”粗野”的事;或许parseInt成了你的瓶颈;或许考虑到性能,需要使用位运算,都要用注释说明你为什么这么做

 

// 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;

  • 注意:当使用位运算时,Numbers被视为64位值,但是位运算总是返回32位整型(source)。对于整型值大于32位的进行位运算将导致不可预见的行为。Discussion.最大的有符号32位整数是2,147,483,647

 

2147483647 >> 0 //=> 2147483647

2147483648 >> 0 //=> -2147483648

2147483649 >> 0 //=> -2147483647

  • Booleans:

 

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 = {};

function c() {}

var u = new user({

name: 'Bob Parr'

});

 

// good

var thisIsMyObject = {};

function thisIsMyFunction() {}

var user = new User({

name: 'Bob Parr'

});

  • 当命名构造函数或类名时,使用驼峰式写法

 

// 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'

});

  • 命名私有属性时使用前置下划线

 

// 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);

};

  • 注意:IE8和怪异模式下命名函数表示,戳此:http://kangax.github.io/nfe/

  • 如果文件作为一个类被导出,文件名应该和类名保持一致

 

// 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');

存取器

  • 对于属性,访问器函数不是必须的

  • 如果定义了存取器函数,应参照getVal() 和 setVal(‘hello’)格式.

 

// bad

dragon.age();

 

// good

dragon.getAge();

 

// bad

dragon.age(25);

 

// good

dragon.setAge(25);

  • 如果属性时boolean,格式应为isVal() or hasVal().

 

// bad

if (!dragon.age()) {

return false;

}

 

// good

if (!dragon.hasAge()) {

return false;

}

  • 创建get() and set()函数时不错的想法,但是要保持一致

 

function 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];

};

构造函数

  • 在原型对象上定义方法,而不是用新对象重写它。重写使继承变为不可能:重置原型将重写整个基类

 

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');

};

  • 方法应该返回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();

};

事件

  • 当在事件对象上附加数据时(无论是DOM事件还是如Backbone一样拥有的私有事件),应传递散列对象而不是原始值,这可以让随后的贡献者给事件对象添加更多的数据,而不必去查找或者更新每一个事件处理程序。举个粟子,不要用下面的方式:

 

// bad

$(this).trigger('listingUpdated', listing.id);

$(this).on('listingUpdated', function(e, listingId) {

// do something with listingId

});

  • 应该按如下方式:

 

// good

$(this).trigger('listingUpdated', { listingId : listing.id });

$(this).on('listingUpdated', function(e, data) {

// do something with data.listingId

});

模块

  • 模块应该以 ! 开始,这能确保当脚本连接时,如果畸形模块忘记导入,包括最后一个分号,不会产生错误。Explanation

  • 文件应该以驼峰式命名,放在同名的文件夹中,和单出口的名称相匹配

  • 定义一个noConflict()方法来设置导出模块之前的版本,并返回当前版本。

  • 在模块的顶部申明’use strict’;

 

// 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对象变量使用前缀$

 

// bad

var sidebar = $('.sidebar');

 

// good

var $sidebar = $('.sidebar');

  • 缓存jQuery查询

 

// 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'

});

}

  • 使用级联('.sidebarul′)或父子(‘.sidebar > ul’)选择器进行DOM查询。jsPerf

  • 在范围内使用find进行jQuery对象查询

 

// bad

$('ul', '.sidebar').hide();

 

// bad

$('.sidebar').find('ul').hide();

 

// good

$('.sidebar ul').hide();

 

// good

$('.sidebar > ul').hide();

 

// good

$sidebar.find('ul').hide();

转载于:https://my.oschina.net/u/2306318/blog/861760

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值