JavaScript 编码规范(二)
命名规则
避免使用一个字母命名
eslint
// bad
function q() {
// ...
}
// good
function query() {
// ...
}
使用小驼峰式命名对象、函数、实例
eslint
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
使用大驼峰式命名类
eslint
// bad
function user(options) {
this.name = options.name;
}
const bad = new user({
name: 'nope',
});
// good
class User {
constructor(options) {
this.name = options.name;
}
}
const good = new User({
name: 'yup',
});
不要使用前置或后置下划线(除非引入的第三方库本身使用)
eslint
JavaScript 没有私有属性或私有方法的概念。尽管前置下划线通常的概念上意味着“private”,事实上,这些属性是完全公有的,因此这部分也是你的API的内容。这一概念可能会导致开发者误以为更改这个不会导致崩溃或者不需要测试。 如果你想要什么东西变成“private”,那就不要让它在这里出现。
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
this._firstName = 'Panda';
// good
this.firstName = 'Panda';
不要保存引用 this
用箭头函数或函数绑定——Function#bind
// bad
function foo() {
const self = this;
return function () {
console.log(self);
};
}
// bad
function foo() {
const that = this;
return function () {
console.log(that);
};
}
// good
function foo() {
return () => {
console.log(this);
};
}
保证文件名、export
模块名以及 import
模块名一致
// file 1 contents
class CheckBox {
// ...
}
export default CheckBox;
// file 2 contents
export default function fortyTwo() { return 42; }
// file 3 contents
export default function insideDirectory() {}
// in some other file
// bad
import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
// bad
import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
import forty_two from './forty_two'; // snake_case import/filename, camelCase export
import inside_directory from './inside_directory'; // snake_case import, camelCase export
import index from './inside_directory/index'; // requiring the index file explicitly
import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
// good
import CheckBox from './CheckBox'; // PascalCase export/import/filename
import fortyTwo from './fortyTwo'; // camelCase export/import/filename
import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
// ^ supports both insideDirectory.js and insideDirectory/index.js
export default
一个函数时、函数名小驼峰式,文件与函数名一致
function makeStyleGuide() {
// ...
}
export default makeStyleGuide;
当 export
一个结构体、类、单例、函数库或者对象时,使用大驼峰式
const Helpers = {
guid: () => return uuid(),
};
export default Helpers;
简称或缩写应该全部大写或者全部小写
名字是给人读的,不是为了适应电脑的算法
// bad
import SmsContainer from './containers/SmsContainer';
// bad
const HttpRequests = [
// ...
];
// good
import SMSContainer from './containers/SMSContainer';
// good
const HTTPRequests = [
// ...
];
// best
import TextMessageContainer from './containers/TextMessageContainer';
// best
const Requests = [
// ...
];
使用全大写字母设置静态变量
- 导出变量
- 是
const
定义的, 保证不能被改变 - 这个变量是可信的,他的子属性都是不能被改变的
一般我们都将项目的全局参数使用这种 全大写+下划线分隔的常量 来定义一些系统配置参数导出,比如
const LIST_VIEW_PAGE_SIZE = 10
可以表示列表页每次加载10条数据;如果导出项目是一个对象,那么必须保证这个对象的所有属性都是不可变的,同时,它的属性不再是全大写,而是使用小写驼峰式。
// bad
const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file';
// bad
export const THING_TO_BE_CHANGED = 'should obviously not be uppercased';
// bad
export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables';
// ---
// allowed but does not supply semantic value
export const apiKey = 'SOMEKEY';
// better in most cases
export const API_KEY = 'SOMEKEY';
// ---
// bad - unnecessarily uppercases key while adding no semantic value
export const MAPPING = {
KEY: 'value'
};
// good
export const MAPPING = {
key: 'value'
};
访问器
若非必要,不要使用访问器
由于 JavaScript 的 getters/setters
是有副作用的,而且会让他人在查看代码的时候难以理解,后期也会难以维护,所以不推荐使用访问器函数,如果非要使用,可以使用自己实现的 getVal()
与 setVal()
。
// bad
class Dragon {
get age() {
// ...
}
set age(value) {
// ...
}
}
// good
class Dragon {
getAge() {
// ...
}
setAge(value) {
// ...
}
}
如果属性或者方法是一个布尔判断值,那么使用 isVal()
或者 hasVal()
。
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
如果非要使用 get()
与 set()
,那么它们两者必须同时使用
class Jedi {
constructor(options = {}) {
const lightsaber = options.lightsaber || 'blue';
this.set('lightsaber', lightsaber);
}
set(key, val) {
this[key] = val;
}
get(key) {
return this[key];
}
}
事件
当你需要向事件附加数据时,将数据封装成为一个对象,而不是使用原始值,这会使得以后可以很方便的增加附加值的字段。
// bad
$(this).trigger('listingUpdated', listing.id);
// ...
$(this).on('listingUpdated', (e, listingID) => {
// do something with listingID
});
而是:
// good
$(this).trigger('listingUpdated', { listingID: listing.id });
// ...
$(this).on('listingUpdated', (e, data) => {
// do something with data.listingID
});
jQuery
为所有 jQuery 对象加上 $
前缀
// bad
const sidebar = $('.sidebar');
// good
const $sidebar = $('.sidebar');
// good
const $sidebarBtn = $('.sidebar-btn');
缓存 jQuery 结果
// bad
function setSidebar() {
$('.sidebar').hide();
// ...
$('.sidebar').css({
'background-color': 'pink',
});
}
// good
function setSidebar() {
const $sidebar = $('.sidebar');
$sidebar.hide();
// ...
$sidebar.css({
'background-color': 'pink',
});
}
使用级联查询 $('.sidebar ul')
或者子父级查询 $('.sidebar > ul')
在 jQuery 对象查询作用域下使用 find
方法
// bad
$('ul', '.sidebar').hide();
// bad
$('.sidebar').find('ul').hide();
// good
$('.sidebar ul').hide();
// good
$('.sidebar > ul').hide();
// good
$sidebar.find('ul').hide();
评论已关闭