语义化驼峰命名,常量使用大写命名。例:
1. 变量 正确:frontEndDevDocs 错误:frontEndDevelopementDocuments 错误:front_end_dev_docs 2. 常量 正确:REG_COMMENTS = /<!--[\s\S]*-->/; 错误:pi = 3.1415926; 3. 类名、构造函数 正确:function Dialog(){} 错误:function dialog(){}
原型方法、属性,私有方法前加下划线。例:
正确: Dialog.prototype.showMsg = function(){}; Dialog.prototype._showMsg = function(){}; Dialog.isVisible = true; Dialog._isVisible = true;
语义化命名变量、函数名、属性名。变量、属性表示陈述,应该用名词;函数表示动作,应该用动词。
// 错误:变量名应该用名词,如 namevar getName = 'Jack';// 函数名应该用动词,如 getNamefunction name(){ return 'Jack'; };
JavaScript 是没有变量类型之分的,因此需要根据变量的实际值进行区分命名。例:
// 布尔值,用`is`、`can`、`has`等前缀来表示。 isVisible canShowHisName // DOM 对象 $body // 表示 <body> 标签
分号不可省略,可以使用编辑器开启代码检查。例:
正确:var html = '<input type="text"/>'; 错误:var html = "<input type=\"text\"/>"
使用 1 个 tab(4 个空格)区分层级关系。例:
pro.push = function ($ele, to, options) { this._queueList.push({ $eles: selector.query($ele), to: to, options: options }); };
变量命名、不同行为之间必须使用空行分开。
function fnSample(element, property, value) { var abc = 123; if (element == null) { return; } element.style[property] = value; }
其余的空白,可使用编辑器alt+cmd+L
格式化。
使用单引号包围字符串。
正确:var html = '<input type="text"/>'; 错误:var html = "<input type=\"text\"/>";
在合适的地方进行变量申明,函数申明不能放在if
、switch
、for
循环等语句块内。例:
var abc = 123;if(abc === 123){ var def = 456; var links = document.links; for(var i = 1, j = links.length; i < j; i++){ // 禁止在循环语句内进行函数申明 links[i].onclick = function(){ alert(i); }; } return add(abc, def); }else{ // 禁止在语句块内进行函数申明 function add(a, b){ return a + b; } }return abc;
一个文件一个模块,模块遵循 CMD 规范(即在 CommonJS 规范外套一层define
)。例:
define(function (require, exports, module) { var selector = require('../alien/core/dom/selector.js'); var animation = require('../alien/core/dom/animation.js'); // ...});
为了更加合理的构建,需要将入口模块集中放置/static/js/app/目录下。
一个模块的出口是一个类(构造函数)。例:
define(function (require, exports, module) { 'use strict'; var klass = require('../alien/utils/class.js'); var Emitter = require('../alien/libs/emitter.js'); var defaults = { // 每一个 ui 模块都必须有一个默认参数 width: 100 }; // klass.extends klass.inherit 都可以 // klass.extends 在 IE9 以下会报错 var Dialog = klass.inherit(Emitter).create({ // 构造函数 constructor: function(){ // }, // 原型方法 init: function(){ // } }); Dialog.init = function(){ // 静态方法 }; // 默认参数导出 Dialog.defaults = defaults; // 模块出口 module.exports = Dialog; });
其中 UI 类需要包含CSS、HTML等文件。文件结构例:
- dialog - template.html - style.css - index.js - readme.md
统一以index.js
作为 Dialog UI 类的入口。例:
// dialog/index.jsdefine(function (require, exports, module) { 'use strict'; var klass = require('../alien/utils/class.js'); var template = require('./template.html', 'html'); var style = require('./style.css', 'css'); var Template = require('../alien/libs/Template.js'); var tpl = new Template(template); var modification = require('../alien/core/dom/modification.js'); var ui = require('../alien/ui/index.js); // ui 默认继承了 Emitter // create 参数与 klass.create 一致 var Dialog = ui.create(...); // 模块出口 module.exports = Dialog; // 导入样式 ui.importStyle(style); });
模块的readme.md
,尽可能的在 readme.md 里描述模块的用法和注意事项。
一个模块出口是多个方法、属性。例:
define(function (require, exports, module) { exports.sayName = function(){}; exports.sayAge = function(){}; });
合理的划分模块,禁止出现模块之间交叉引用。例如下文件结构:
- abc.js- def.js
例如下代码:
// abc.jsvar def = require('./def.js');// def.js// 不能交叉引用var abc = require('./abc.js');
像扩展 jquery
原型链一样无限制的扩展下去,就失去了模块化的本身含义。更合理的做法是:
var $ = require('jquery');module.exports = function(ele, options){ // do sth.};
YUI 注释已经成为了非官方标准,合理的注释有助于编辑器的识别、人为阅读、文档的形成。
// attribute.js/*! * 核心 dom 属性器 <= 当前模块的描述 * @autho 作者 <= 当前模块的作者 * @date 2014-09-16 18:30 <= 当前模块的时间 */define(function (require, exports, module) { /** * @module core/dom/attribute <= 模块ID * @requires utils/dato <= 被引用的模块 * @requires utils/typeis * @requires core/navigator/compatible * @requires core/dom/selector * @requires core/dom/see */
// attribute.js /** * 设置、获取元素的属性 * @param {HTMLElement|Node} ele 元素 * @param {String/Object/Array} key 特征键、键值对、键数组 * @param {String} [val] 特征值 * @returns {*} * * @example * // set * attribute.attr(ele, 'href', 'http://ydr.me'); * attribute.attr(ele, { * href: '', * title: '' * }); * * // get * attribute.attr(ele, 'href'); * attribute.attr(ele, ['href', 'title']); */ exports.attr = function (ele, key, val) { // ... });
/** * banner 索引变化之后 * @event change * @param index {Number} 索引 */ the.emit('change', index);
/** * @type {Object} * @property startX {Number} 开始触摸时的 x 坐标 * @property startY {Number} 开始触摸时的 y 坐标 * @property startTime {Number} 开始触摸时的时间戳 * @property startID {Number} 开始触摸时的 ID * @property startTarget {Object} 开始触摸时的 element */ var touch = {};
var makeStatic = function (tp) { /** * 快捷判断 * @name typeis * @property string {Function} * @property number {Function} * @property function {Function} * @returns {boolean} */ typeis[tp] = function (obj) { return typeis(obj) === tp; }; };
使用严格模式、严谨(全等)匹配。
'use strict';if ( a === '1' ){ // do...}
三目运算仅适合变量赋值,禁止将其作为if
替代语句。
// 正确var value = condition ? value1 : value2;// 禁止将其作为`if`替代语句condition ? doSomething() : doSomethingElse();
禁止在模块内声明全局变量。
全局变量仅能出现在业务入口。
全局变量不能超过 3 个。
约定的全局变量为APP
,指当前页面的配置。
$
开头的都为元素或元素的集合,指向 jQuery 对象。
_
开头的为私有原型方法。
options
为模块内的配置参数。
El
结尾的为元素。
避免多次获取同一个 DOM 元素,避免连续操作同一个 DOM 元素。
$('#demo').css(...);$('#demo').width(...);$('#demo').height(...);$('#demo').css(...);
尽量避免纯 JS 动画:
alien 里使用/core/dom/animation.js
donkey 里使用/core/dom/animation.js