JavaScript 风格指南
我们使用 Airbnb JavaScript 风格指南 及其配套的 linter 来管理我们的大部分 JavaScript 风格规范。
除了 Airbnb 设定的风格指南外,我们还有一些特定的规则 如下所述。
你可以通过运行 yarn run lint:eslint:all 或 yarn run lint:eslint $PATH_TO_FILE 来本地运行 ESLint。
避免使用 forEach
在修改数据时避免使用 forEach。在修改数据时,使用 map、reduce 或 filter 替代 forEach。
这可以最小化函数中的修改,符合 Airbnb 风格指南 的要求。
// bad
users.forEach((user, index) => {
user.id = index;
});
// good
const usersWithId = users.map((user, index) => {
return Object.assign({}, user, { id: index });
});限制参数数量
如果你的函数或方法有超过 3 个参数,请使用对象作为参数 替代。
// bad
function a(p1, p2, p3, p4) {
// ...
};
// good
function a({ p1, p2, p3, p4 }) {
// ...
};避免使用类处理 DOM 事件
如果类的唯一目的是绑定 DOM 事件和处理回调,优先 使用函数。
// bad
class myClass {
constructor(config) {
this.config = config;
}
init() {
document.addEventListener('click', () => {});
}
}
// good
const myFunction = () => {
document.addEventListener('click', () => {
// 在这里处理回调
});
}将元素容器传递给构造函数
当你的类操作 DOM 时,将元素容器作为参数接收。 这样更易于维护且性能更好。
// bad
class a {
constructor() {
document.querySelector('.b');
}
}
// good
class a {
constructor(options) {
options.container.querySelector('.b');
}
}将字符串转换为整数
将字符串转换为整数时,Number 在语义上更清晰且可读性更好。两者都可以使用,但 Number 有轻微的可维护性优势。
parseInt 必须包含 基数参数。
// bad (缺少基数参数)
parseInt('10');
// good
parseInt("106", 10);
// good
Number("106");// bad (缺少基数参数)
things.map(parseInt);
// good
things.map(Number);如果字符串可能表示非整数(包含小数点的数字),不要使用 parseInt。考虑使用 Number 或 parseFloat。
CSS 选择器 - 使用 js- 前缀
如果 CSS 类仅在 JavaScript 中用作元素的引用,请为
类名添加 js- 前缀。
// bad
<button class="add-user"></button>
// good
<button class="js-add-user"></button>ES 模块语法
对于大多数 JavaScript 文件,使用 ES 模块语法来导入或导出模块。 优先使用命名导出,因为它们可以提高名称一致性。
// bad (有例外,见下文)
export default SomeClass;
import SomeClass from 'file';
// good
export { SomeClass };
import { SomeClass } from 'file';在少数特定情况下可以使用默认导出:
- Vue 单文件组件 (SFCs)
- Vuex mutation 文件
更多信息请参见 RFC 20。
CommonJS 模块语法
我们的 Node 配置要求使用 CommonJS 模块语法。优先使用命名导出。
// bad
module.exports = SomeClass;
const SomeClass = require('./some_class');
// good
module.exports = { SomeClass };
const { SomeClass } = require('./some_class');模块的绝对路径与相对路径
如果导入的模块在向上不超过两个层级,请使用相对路径。
// bad
import GitLabStyleGuide from '~/guides/GitLabStyleGuide';
// good
import GitLabStyleGuide from '../GitLabStyleGuide';如果导入的模块在向上两个或更多层级,请使用绝对路径:
// bad
import GitLabStyleGuide from '../../../guides/GitLabStyleGuide';
// good
import GitLabStyleGuide from '~/GitLabStyleGuide';此外,不要添加到全局命名空间。
不要在非页面模块中使用 DOMContentLoaded
导入的模块每次加载时应该表现相同。DOMContentLoaded
事件只允许在 /pages/* 目录中加载的模块上使用,因为那些
模块是使用 webpack 动态加载的。
避免 XSS
不要使用 innerHTML、append() 或 html() 来设置内容。这会带来太多
安全漏洞。
ESLint
ESLint 的行为可以在我们的 工具指南 中找到。
IIFEs
避免使用 IIFEs(立即调用函数表达式)。尽管 我们有很多将内容包装在 IIFEs 中的文件示例, 但在从 Sprockets 迁移到 webpack 后,这已不再必要。 不要再使用它们,在重构遗留代码时可以放心移除它们。
全局命名空间
避免添加到全局命名空间。
// bad
window.MyClass = class { /* ... */ };
// good
export default class MyClass { /* ... */ }副作用
顶层副作用
任何包含 export 的脚本中禁止顶层副作用:
// bad
export default class MyClass { /* ... */ }
document.addEventListener("DOMContentLoaded", function(event) {
new MyClass();
}避免在构造函数中使用副作用
避免在 constructor 中进行异步调用、API 请求或 DOM 操作。
将它们移到单独的函数中。这样更容易编写测试,
并且避免违反 单一职责原则。
// bad
class myClass {
constructor(config) {
this.config = config;
axios.get(this.config.endpoint)
}
}
// good
class myClass {
constructor(config) {
this.config = config;
}
makeRequest() {
axios.get(this.config.endpoint)
}
}
const instance = new myClass();
instance.makeRequest();纯函数和数据修改
努力编写许多小的纯函数,并最小化修改发生的位置
// bad
const values = {foo: 1};
function impureFunction(items) {
const bar = 1;
items.foo = items.a * bar + 2;
return items.a;
}
const c = impureFunction(values);
// good
var values = {foo: 1};
function pureFunction (foo) {
var bar = 1;
foo = foo * bar + 2;
return foo;
}
var c = pureFunction(values.foo);将常量作为基本类型导出
优先使用通用命名空间导出常量基本类型,而不是导出对象。这允许更好的编译时引用检查,并有助于避免运行时意外出现 undefined。此外,它有助于减少包大小。
只有当需要迭代常量时(例如,用于属性验证器),才将常量作为集合(数组或对象)导出。
// bad
export const VARIANT = {
WARNING: 'warning',
ERROR: 'error',
};
// good
export const VARIANT_WARNING = 'warning';
export const VARIANT_ERROR = 'error';
// good, 如果需要迭代这些常量
export const VARIANTS = [VARIANT_WARNING, VARIANT_ERROR];错误处理
对于服务器返回 500 的内部服务器错误,你应该返回
一个通用的错误消息。
当后端返回错误时,这些错误应该 适合向用户显示。
如果由于某种原因难以做到这一点,作为最后的手段,你可以 通过添加前缀来选择特定的错误消息:
-
确保后端为要显示的错误消息添加前缀:
Gitlab::Utils::ErrorMessage.to_user_facing('Example user-facing error-message') -
使用
app/assets/javascripts/lib/utils/error_message.js中包含的错误消息工具函数。
该工具接受两个参数:从服务器响应接收的错误对象和 默认错误消息。该工具检查错误对象中的消息是否有前缀, 指示该消息是否面向用户。如果消息面向用户,工具将按原样返回它。 否则,它返回作为参数传递的默认错误消息。
import { parseErrorMessage } from '~/lib/utils/error_message';
onError(error) {
const errorMessage = parseErrorMessage(error, genericErrorText);
}请注意,此前缀不能用于 API 响应。相反,请遵循 REST API 或 GraphQL 指南 来了解如何使用错误对象。