Airbnb JavaScript代码规范(一)

github英文文档github中文文档,建议看英文文档。

1.引用

1)对所有的引用使用const,而不用var。

确保你不会对引用重新赋值,也不会导致出现bug,或难以理解。

//bad
var a=1;
var b=2;

//better
const a=1;
const b=2;

2)如果你一定要用到可变动的引用,使用let,不要用var。

因为let是块级作用域,而var是函数作用域。

//bad
var count = 1;
if(true){
 count+=1;
}

//better
let count=1;
if(true){
 count += 1;
}

3)注意let和const都是块级作用域。

{
 let a = 1;
 const b = 1;
}
console.log(a);//ReferenceError
console.log(b);//ReferenceError

2.对象

1)使用对象字面量创建对象。eslint:no-new-object

//bad
const item = new Object();

//better
const item = {}

2)当创建具有动态属性名的对象时,要使用计算属性名。
这允许你在一个地方定义一个对象的所有属性。

function getKey(k){
 return `a key named ${k}`;
}

//bad 
const obj = {
 id: 5,
 name: 'Anne',
};
obj[getKey('enabled')] = true;

//good
const obj = {
 id: 5,
 name:'Anne',
 [getKey('enabled')]: true,
};

3)使用对象方法的简写。eslint:object-shorthand

//bad
const atom = {
 value: 1,
 addValue: function (value){
  return atom.value+value;
 }
};

//better
const atom = {
 value: 1,
 addValue(value){//already remove the word 'function'
  return atom.value+value;
 }
};

4)使用属性值的简写。eslint:object-shorthand

这样写起来和描述起来比较简短。

const lukeSkywalker = 'Luke Skywalker';
//bad 
const obj = {
 lukeSkywalker: lukeSkywalker,
};

//better
const obj = {
 lukeSkywalker,
}

5) 在描述对象的开头就将所有的简写属性一次性写完。

这样能清楚地知晓哪些属性是简写的

const anakinSkywalker = 'Anne';
const lukeSkywalker = 'Bob';

//bad
const obj = {
 esOne: 1,
 two: 2,
 lukeOne,
 anakinS: 3,
};

//better
const obj = {
 lukeSkywalker,
 anakinSkywalker,
 eesOne: 1,
 mayOne: 2,
 mayThree: 3,
};

6)只在非法标识符上使用引号。eslint:quote-props

通常,我们主观上认为这样做更易读,有助于语法高亮,对js引擎来说也更容易优化。

//bad
const bad = {
 'foo': 3,
 'bar': 4,
 'data-blad': 5,
}

//better
const good = {
 foo: 3,
 bar: 4,
 'data-blad': 5,
}

7)不要直接调用Object.prototype方法,比如hasOwnPrototype,prototypeIsEnumerable,和isPrototypeOf。

这些方法可能被相关对象的属性影响。想一想{ hasOwnProperty: false },或者,对象可能是个空对象(Ooject.create(null))

//bad 
console.log(object.hasOwnProperty(key));

//good
console.log(Object.prototype.hasOwnProperty.call(object,key));

//best
const has = Object.prototype.hasOwnProperty;
console.log(has.call(object,key));
/*or*/
import has from 'has'; //https://www.npmjs.com/package/has
console.log(has.call(object,key));

8)优先使用扩展运算符,弃用只能浅复制的Object.assign方法。

const original = { a: 1,b: 2 };
const copy = Object.assign(original, { c: 3 });//这个操作修改了original
delete copy.a;//这个操作也修改了original

//bad
const orignal = { a: 1,b: 2 };
const copy = Object.assign({},original,{ c: 3 });//定义了一个新的对象copy => { a: 1,b: 2,c: 3 }

//good 
const original = { a: 1,b: 2 };
const copy = {...original,c: 3 };//copy => { a: 1,b: 2,c: 3 }

const { a, ...noA } = copy; //noA => { b: 2,c: 3 }

3.数组

1)创建数组时使用对象语法。eslint:no-array-constructor

//bad
const items = new Array();
//good
const items = [];

向数组添加元素时使用Array#push替代直接赋值

const somestack = [];
//bad
somestack[somestack.length] = '1bfefff';

//good
somestack.push('1jjhhj');

3) 使用扩展运算符...复制数组

//bad
const len = items.length;
const itemsCopy = [];
let i;

for(i =0;i<len;i++){
 itemsCopy[i] = items[i];
}

//good
const itemsCopy = [...items];

4) 使用扩展运算符(spread)将类数组对象转换为数组,弃用Array.from

const foo = document.querySelectorAll('.foo');
//good
const nodes = Array.from(foo);
//best
const nodes = [...foo];

5)使用Array.from对可迭代对象进行映射(map),因为可以避免创建一个中间数组。

//bad 
const baz = [..foo].map(bar);//foo是可迭代的对象,bar是foo里的单个元素

//good
const baz = Array.from(foo,bar);

6)在数组回调方法中使用return语句。如果函数体仅包含一个返回无副作用的单句,避免return。参考8.2eslint:array-callback-return。

//good 多个句子要有return语句
[1,2,3].map((x) => {
 const y = x + 1;
 return x*y;
})

//good 单句不用加return
[1,2,3].map((x) => x + 1);

//bad
[[0,1],[2,3],[4,5]].reduce((acc,item,index) => {
 const flatten = acc.concat(item);
 acc[index] = flatten;
});

//good 
[[0,1],[2,3],[4,5]].reduce((acc,item,index) => {
 const flatten = acc.concat(item);
 acc[index] = flatten;
 return flatten;
});

//bad
inbox.filter((msg) => {
 const { subject, author } = msg;
 if(subject === 'Mockingbird'){
  return author === 'Harper Lee';
 } else {
  return false;
 }
});

//good
inbox.filter((msg) => {
 const { subject,author } = msg;
 if(subject === 'Mockingbird'){
  return autohr === 'Harper Lee';
 }
 return false;
});

如果数组有多行,请在打开数组括号之后和关闭数组括号之前使用换行符。

//bad
const arr = [
 [0,1],[2,3],[4,5],
];
//good
const arr = [[0,1],[2,3],[4,5]];

//bad
const numerInArray = [
 1,2,
];
//good
const numberInArray = [
 1,
 2,
];

//bad
const objectInArray = [{
 id: 1,
},{
 id: 2,
}];
//good
const objectInArray = [
 {
  id: 1,
 },
 {
  id: 2,
 },
];

4.解构(Destructuring)

1) 存取和使用对象的多个属性时请使用对象解构

因为对象解构能减少创建临时引用。

//bad
function getFullName(user){
 const firstName = user.firstName;
 cosnt lastName = user.lastName;

 return `${firstName} ${lastName}`;
}

//good
function getFullName(user){
 const { firstName, lastName } = user;
 return `${firstName} ${lastName}`;
}
//best
function getFullName({ firstName,lastName }){
 return `${firstName} ${lastName}`;
}

2)使用数组解构。eslint:prefer-destructuring

const arr = [1,2,3];

//bad
const first = arr[0];
const second = arr[1];

//good
const [first,second] = arr;
console.log(first);//=>1

3)需要返回多个值时,使用对象解构,不要用数组解构。

因为以后你添加新的属性或者改变顺序不会改变函数内部本有的顺序。

//bad
function processInput(input){
 return [left,right,top,bottom];
}
//需要考虑函数的顺序
const [left,__,top] = processInput(input);

//good
function processInput(input){
 return { left,right,top,bottom };
}
//调用时只选择需要的数据,不用考虑顺序
const { left, right } = processInput(input);

5.字符串Strings

1) 字符串使用单引号。eslint:quotes

//bad
const name = "hh";
//bad 模板字符必须包含插值或者新行。
const name = `jjjmn'n'n`;

//good
const name = 'jjj';

2) 超过100个字符的字符串不应该使用字符串连接跨多行写入。
分割的字符串使得处理起来很痛苦,并且降低了代码的可搜索性。(过多的字符连接符号也会对性能造成影响)

const 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
const 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
const 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.';

3)程序化生成字符串时,使用模板字符串而不是字符串拼接。eslint:prefer-template-template-curly-sapcing

模板字符串可读性更高,拥有简洁的语法,适当的换行和字符插值功能。

//bad 
function sayHi(name){
 return 'how are you,'+name+'?';
}
function sayHi(name){
 return ['how are you,',name,'?'].join();
}
function sayHi(name){
 return `how are you,${ name }?`;//多两个空格
}
//good
function sayHi(name){
 return `how are you,${name}?`;//少了个空格
}

4) 不要在字符串上使用eval(),它会打开很大漏洞。eslint:no-eval

5) 不要毫无意义地去转义字符。eslint:no-useless-escape

//bad
const foo = '\'this\' \i\s \"quotes\"';//is没有必要转义,双引号也没有必要转义
//good
const foo = '\'this\' is "quoted"';
const foo = `my name if '${name}'`;

6.函数

1)使用命名函数表达式代替函数声明。eslint:func-style

函数声明会被提升,这意味着在它还为被定义在文档中前就会很容易被引用!这不利于可读性和可维护性。
如果你发现一个函数的定义很大或很复杂,以致于它会干扰理解文件的其他部分,那么也许是时候将它提取到它自己的模块中了!
不要忘记明确指定表达式的名称,而不管该名称是否从包含变量中推断出来(在现代浏览器中或在使用编译器(如Babel)时通常都是如此)。这消除了关于Error的调用堆栈的任何假设。

//bad
function foo(){
}
const foo = function(){};
//good
const short = function longUniqueMoreDescriptiveLexicalFoo(){
};

2)包裹立即调用表达式(IIFE)

一个立即调用表达式是一个独立的模块。

(funcition(){
 console.log('good');
}());

3)永远不要在非函数代码块中声明函数(比如if,while等),改为将函数的功能赋值给变量。浏览器允许你这么做,但是它们解析表现不一致。eslint:no-loop-func
4)ECMA-262将块定义为语句列表。函数声明不是一个语句。

//bad
if(currentUser){
 function test(){
  console.log('kk');
 }
}
//good
let test;
if(currentUser){
 test = () => {
  console.log('ll');
 }
}

5)永远不要命名参数为arguments。这将优先于每个函数作用域的
arguments对象。

//bad
function foo(name,options,arguments){
 //...
}
//good
function foo(name,options,args){
 //...
}

6)不要使用arguments,选择使用test语法...。eslint:prefer-rest-params

...明确你想要拉什么参数。另外,rest参数是一个真正的数组,而不仅仅是类数组一样的arguments。

//bad
function concatenateAll(){
 const args = Array.prototype.slice.call(arguments);
 return args.join('');
}
//good
function concatenateAll(...args){
 return args.join('');
}

7)使用默认得到参数语法而不是修改函数参数值。

function handleThings(opts){
 opts = opts || {};//不能这样修改参数值。假如opts是falsy,这就可能被设置成对象,可能你想要这样设,但是这会引入微妙的bug。
}
//still bad
function handleThings(opts){
 if(opts === voild 0){
  opts = {},
 }
}
//good
function handleThings(opts = {}){
 //...
}

8) 给参数赋默认值时避免副作用。

因为这样写让人感到困惑。

var b = 1;
//bad
function count(a = b++){
 console.log(a);
}
count();//1
count();//2
count(3);//3
count();//3

9) 总是吧默认参数放到最后

//bad
function handleThings(opts = {},name){
 //...
}
//good
function handleThings(name,opts ={}){
 //...
}

10) 不要使用构造函数创建函数。eslint:no-new-func

以这种方式类似于使用eval(),会打开漏洞。

//bad
var add = new Function('a','b','return a+b');
//stll bad
var substract = Function('a','b','return a+b');

11)在函数签名前后各空一格。eslint:space-before-function-paren

这样处理的话,一致性很好,在添加或者删除函数名的时候不用添加或删除空格。

//bad 
const f = function(){};
const f = function (){};
cost f = function() {};
//good
const f = function () {};
const f = function a(){};

12) 不要改变参数。eslint:no-param-reassign

操作作为参数传入的对象可能会在原调用方中导致不必要的变量副作用

//bad
function f1(obj) {
 obj.key = 1;
}
//good
function f2(obj) {
 const key = Object.prototype.hasOwnPrototype.call(obj,'key') ? obj.key : 1;
}

13) 不要重新赋值给参数。esliint:no-param-reassign

重新赋值会导致意外的行为,特别是在访问arguments对象的时候。这也会导致优化问题,特别是在V8引擎中。

//bad
function f1(a) {
 a = 1;
}
function f2(a) {
 if(!a){ a = 1; }
}
//good
function f3(a) {
 const b = a || 1;
}

14) 优先使用扩展运算符...来调用可变参数函数。esslint:prefer-spread

这样做更简洁,你不需要提供上下文,并且你使用apply无法轻松地创建new

//bad
const x = [1,2,3];
console.log.apply(console,x);
//good
console.log(...x);
//bad
new (Function.prototype.bind.apply(Date,[null,2016,8,5]));
//good
new Date(...[2016,8,5]);

15) 带有多行签名或调用的函数应该像本指南中的其他多行列表一样缩进:每个项目单独一行,最后一个项目尾随逗号。eslint:function-paren-newline

//bad 
function foo(bar,
             baz,
             quux){
}
//good
function foo(
 bar,
 baz,
 quu,
){
}
//bad
console.log(foo
  bar,
  baz);
//good
console.log(
 foo,
 bar,
 baz,
);

猜你喜欢

转载自blog.csdn.net/e_li_na/article/details/80337131