JavaScript代码规范
Posted zero13_小葵司
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript代码规范相关的知识,希望对你有一定的参考价值。
类型
基本类型: 直接存取基本类型。
字符串
数值
布尔类型
null
undefined
const foo = 1;
let bar = foo; bar = 9; console.log(foo, bar); // => 1, 9
复杂类型: 通过引用的方式存取复杂类型。
对象
数组
函数
const foo = [1, 2];
const bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // => 9, 9
引用
对所有的引用使用 const ;不要使用 var。
为什么?这能确保你无法对引用重新赋值,也不会导致出现 bug 或难以理解。
// bad
var a = 1;
var b = 2;
// good
const a = 1;
const b = 2;
如果你一定需要可变动的引用,使用 let 代替 var。
为什么?因为 let 是块级作用域,而 var 是函数作用域。
// bad
var count = 1;
if (true)
count += 1;
// good, use the let.
let count = 1;
if (true)
count += 1;
注意 let 和 const 都是块级作用域。
// const 和 let 只存在于它们被定义的区块内。
let a = 1;
const b = 1;
console.log(a); // ReferenceError
console.log(b); // ReferenceError
对象
使用字面值创建对象。
// bad
const item = new Object();
// good
const item = ;
如果你的代码在浏览器环境下执行,别使用 保留字 作为键值。这样的话在 IE8 不会运行。 更多信息。 但在 ES6 模块和服务器端中使用没有问题。
// bad
const superman =
default: clark: 'kent' ,
private: true,
;
// good
const superman =
defaults: clark: 'kent' ,
hidden: true,
;
使用同义词替换需要使用的保留字。
// bad
const superman =
class: 'alien',
;
// bad
const superman =
klass: 'alien',
;
// good
const superman =
type: 'alien',
;
创建有动态属性名的对象时,使用可被计算的属性名称。
为什么?因为这样可以让你在一个地方定义所有的对象属性。
function getKey(k)
return `a key named $k`;
// bad
const obj =
id: 5,
name: 'San Francisco',
;
obj[getKey('enabled')] = true;
// good
const obj =
id: 5,
name: 'San Francisco',
[getKey('enabled')]: true,
;
使用对象方法的简写。
// bad
const atom =
value: 1,
addValue: function (value)
return atom.value + value;
,
;
// good
const atom =
value: 1,
addValue(value)
return atom.value + value;
,
;
使用对象属性值的简写。
为什么?因为这样更短更有描述性。
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj =
lukeSkywalker: lukeSkywalker,
;
// good
const obj =
lukeSkywalker,
;
在对象属性声明前把简写的属性分组。
为什么?因为这样能清楚地看出哪些属性使用了简写。
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj =
episodeOne: 1,
twoJedisWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3,
mayTheFourth: 4,
anakinSkywalker,
;
// good
const obj =
lukeSkywalker,
anakinSkywalker,
episodeOne: 1,
twoJedisWalkIntoACantina: 2,
episodeThree: 3,
mayTheFourth: 4,
;
数组
使用字面值创建数组。
// bad
const items = new Array();
// good
const items = [];
向数组添加元素时使用 Arrary#push 替代直接赋值。
const someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
使用拓展运算符 … 复制数组。
// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i++)
itemsCopy[i] = items[i];
// good
const itemsCopy = [...items];
使用 Array#from 把一个类数组对象转换成数组。
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);
解构
使用解构存取和使用多属性对象。
为什么?因为解构能减少临时引用属性。
// bad
function getFullName(user)
const firstName = user.firstName;
const lastName = user.lastName;
return `$firstName $lastName`;
// good
function getFullName(obj)
const firstName, lastName = obj;
return `$firstName $lastName`;
// best
function getFullName( firstName, lastName )
return `$firstName $lastName`;
对数组使用解构赋值。
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
需要回传多个值时,使用对象解构,而不是数组解构。
为什么?增加属性或者改变排序不会改变调用时的位置。
// bad
function processInput(input)
// then a miracle occurs
return [left, right, top, bottom];
// 调用时需要考虑回调数据的顺序。
const [left, __, top] = processInput(input);
// good
function processInput(input)
// then a miracle occurs
return left, right, top, bottom ;
// 调用时只选择需要的数据
const left, right = processInput(input);
Strings
字符串使用单引号 。
// bad
const name = "Capt. Janeway";
// good
const name = 'Capt. Janeway';
字符串超过 80 个字节应该使用字符串连接号换行。
注:过度使用字串连接符号可能会对性能造成影响。jsPerf 和 讨论.
// 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.';
// 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.';
程序化生成字符串时,使用模板字符串代替字符串连接。
为什么?模板字符串更为简洁,更具可读性。
// bad
function sayHi(name)
return 'How are you, ' + name + '?';
// bad
function sayHi(name)
return ['How are you, ', name, '?'].join();
// good
function sayHi(name)
return `How are you, $name?`;
函数
使用函数声明代替函数表达式。
为什么?因为函数声明是可命名的,所以他们在调用栈中更容易被识别。此外,函数声明会把整个函数提升(hoisted),而函数表达式只会把函数的引用变量名提升。这条规则使得[arrow-functions 箭头函数]可以取代函数表达式。
// bad
const foo = function ()
;
// good
function foo()
函数表达式:
// 立即调用的函数表达式 (IIFE)
(() =>
console.log('Welcome to the Internet. Please follow me.');
)();
永远不要在一个非函数代码块(if、while 等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。
注意: ECMA-262 把 block 定义为一组语句。函数声明不是语句。阅读 ECMA-262 关于这个问题的说明。
// bad
if (currentUser)
function test()
console.log('Nope.');
// good
let test;
if (currentUser)
test = () =>
console.log('Yup.');
;
永远不要把参数命名为 arguments。这将取代原来函数作用域内的 arguments 对象。
// bad
function nope(name, options, arguments)
// ...stuff...
// good
function yup(name, options, args)
// ...stuff...
不要使用 arguments。可以选择 rest 语法 … 替代。
为什么?使用 … 能明确你要传入的参数。另外 rest 参数是一个真正的数组,而 arguments 是一个类数组。
// bad
function concatenateAll()
const args = Array.prototype.slice.call(arguments);
return args.join('');
// good
function concatenateAll(...args)
return args.join('');
直接给函数的参数指定默认值,不要使用一个变化的函数参数。
// really bad
function handleThings(opts)
// 不!我们不应该改变函数参数。
// 更加糟糕: 如果参数 opts 是 false 的话,它就会被设定为一个对象。
// 但这样的写法会造成一些 Bugs。
//(译注:例如当 opts 被赋值为空字符串,opts 仍然会被下一行代码设定为一个空对象。)
opts = opts || ;
// ...
// still bad
function handleThings(opts)
if (opts === void 0)
opts = ;
// ...
// good
function handleThings(opts = )
// ...
直接给函数参数赋值时需要避免副作用。
为什么?因为这样的写法让人感到很困惑。
var b = 1;
// bad
function count(a = b++)
console.log(a);
count(); // 1
count(); // 2
count(3); // 3
count(); // 3
箭头函数
当你必须使用函数表达式(或传递一个匿名函数)时,使用箭头函数符号。
为什么?因为箭头函数创造了新的一个 this 执行环境(译注:参考 Arrow functions - javascript | MDN 和 ES6 arrow functions, syntax and lexical scoping),通常情况下都能满足你的需求,而且这样的写法更为简洁。
为什么不?如果你有一个相当复杂的函数,你或许可以把逻辑部分转移到一个函数声明上。
// bad
[1, 2, 3].map(function (x)
const y = x + 1;
return x * y;
);
// good
[1, 2, 3].map((x) =>
const y = x + 1;
return x * y;
);
如果一个函数适合用一行写出并且只有一个参数,那就把花括号、圆括号和 return 都省略掉。如果不是,那就不要省略。
为什么?语法糖。在链式调用中可读性很高。
为什么不?当你打算回传一个对象的时候。
// good
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].reduce((total, n) =>
return total + n;
, 0);
构造器
总是使用 class。避免直接操作 prototype 。
为什么? 因为 class 语法更为简洁更易读。
// bad
function Queue(contents = [])
this._queue = [...contents];
Queue.prototype.pop = function()
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
// good
class Queue
constructor(contents = [])
this._queue = [...contents];
pop()
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
使用 extends 继承。
为什么?因为 extends 是一个内建的原型继承方法并且不会破坏 instanceof。
// bad
const inherits = require('inherits');
function PeekableQueue(contents)
Queue.apply(this, contents);
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function()
return this._queue[0];
// good
class PeekableQueue extends Queue
peek()
return this._queue[0];
方法可以返回 this 来帮助链式调用。
// bad
Jedi.prototype.jump = function()
this.jumping = true;
return true;
;
Jedi.prototype.setHeight = function(height)
this.height = height;
;
const luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined
// good
class Jedi
jump()
this.jumping = true;
return this;
setHeight(height)
this.height = height;
return this;
const luke = new Jedi();
luke.jump()
.setHeight(20);
可以写一个自定义的 toString() 方法,但要确保它能正常运行并且不会引起副作用。
class Jedi
constructor(options = )
this.name = options.name || 'no name';
getName()
return this.name;
toString()
return `Jedi - $this.getName()`;
模块
总是使用模组 (import/export) 而不是其他非标准模块系统。你可以编译为你喜欢的模块系统。
为什么?模块就是未来,让我们开始迈向未来吧。
// bad
const AirbnbStyleGuide = require以上是关于JavaScript代码规范的主要内容,如果未能解决你的问题,请参考以下文章