编写可维护的javascript

每个人都有固定的一套编码习惯,但在团队协作过程中,则需要每个人都遵守统一的编码约定和编程方法。

编程风格

  • 基本的格式化
    1、缩进层级
    (1)不好的习惯

    if( con == ''){
    console.log('是不是分不清层级')}
    else{ console.log('没有主次')}
    

    (2)好的习惯

    if( con == ''){
        console.log('层级很清晰');
    }
    else{ 
        console.log('简单明了');
     }
    

    2、语句结尾
    (1)不好的习惯

    function getVal(){
          return 
          {
              title:'jialin',
              age:23
          }
    }
    //分析器会将他理解为
       function getVal(){
          return; //这样的return返回的是undefined,我们想要的是返回数据对象
          {
              title:'jialin',
              age:23
          }
    }
    

    (2)好的习惯

      function getVal(){
            return  {  //将return和花括号放置一行
                title:'jialin',
                age:23
            }
      }
    

    3、变量和函数的命名

    • 采取小驼峰命名,如:getName,setVal...
    • 命名有意义,体现出类型,如:count、length、size表示数字类型,name、title等表示字符串类型。

    4、null

    • null是一个特殊值,不要将它和undefined高混淆,undefined派生于null,但它们的数据类型不相等
    适用于null的场景
     - 用来初始化一个变量
     - 用来和一个已经初始化的变量比较
     - 当函数的参数期望是对象时,用作参数传入
     - 当函数的返回值期望是对象时,用作返回值传出
    
    不适于null
    - 不要使用null来检测是否传入了某个参数
    - 不要使用null来检测一个未初始化的变量
    
微信截图_20170806001017.png
理解null的最好方式将他当做占位符,对于全局维护性来说至关重要

5、undefined

//不好的写法
var val;
console.log(typeof val);    //undefined
console.log(typeof name); //undefined  会报错, 返回值和typeof容易混淆

以下是我们老大分享的代码规范,在这里分享给你们

js代码规范

文档

JavaScript 文件使用无 BOM 的 UTF-8 编码。
在文件结尾处,保留一个空行。
使用 2 个空格做为一个缩进层级,不允许使用 4 个空格 或 tab 字符。
每个独立语句结束后必须换行。每行不得超过 120 个字符。
运算符处换行时,运算符必须在新行的行首。
// good
if (user.isAuthenticated()
    && user.isInRole('admin')
    && user.hasAuthority('add-admin')
    || user.hasAuthority('delete-admin')
) {
    // Code
}

var result = number1 + number2 + number3
    + number4 + number5;


// bad
if (user.isAuthenticated() &&
    user.isInRole('admin') &&
    user.hasAuthority('add-admin') ||
    user.hasAuthority('delete-admin')) {
    // Code
}

var result = number1 + number2 + number3 +
    number4 + number5;
在函数声明、函数表达式、函数调用、对象创建、数组创建、for语句等场景中,不允许在 , 或 ; 前换行。
// good
var obj = {
  a: 1,
  b: 2,
  c: 3
};

foo(
  aVeryVeryLongArgument,
  anotherVeryLongArgument,
  callback
);


// bad
var obj = {
  a: 1
  , b: 2
  , c: 3
};

foo(
  aVeryVeryLongArgument
  , anotherVeryLongArgument
  , callback
);
不同行为或逻辑的语句集,使用空行隔开,更易阅读。
当参数过多时,将每个参数独立写在一行上,并将结束的右括号 ) 独立一行。所有参数必须增加一个缩进。
foo(
  aVeryVeryLongArgument,
  anotherVeryLongArgument,
  callback
);
也可以按逻辑对参数进行组合。

比如angularjs的服务注入,可以将框架提供的服务、自定义服务、常量、提供器分开。

function run(
  $log, $rootScope, $cookies, // 框架内提供
  serverConfig, CONFIG,  // 提供器、常量
  common, sgCommon,  // 自定义服务
);
三元运算符由3部分组成,因此其换行应当根据每个部分的长度不同,形成不同的情况。
var result = thisIsAVeryVeryLongCondition
    ? resultA : resultB;

var result = condition
    ? thisIsAVeryVeryLongResult
    : resultB;
对于 if...else...、try...catch...finally 等语句,推荐使用在 } 号后添加一个换行 的风格,使代码层次结构更清晰,阅读性更好。
if (condition) {
    // some statements;
}
else {
    // some statements;
}

try {
    // some statements;
}
catch (ex) {
    // some statements;
}
不得省略语句结束的分号。
在 if / else / for / do / while 语句中,即使只有一行,也不得省略块 {...}。
// good
if (condition) {
  callFunc();
}

// bad
if (condition) callFunc()
if (condition)
  callFunc()

命名

变量 使用 Camel命名法。
var loadingModules = {};
常量 使用 全部字母大写,单词间下划线分隔 的命名方式。
var HTML_ENTITY = {};
函数 使用 Camel命名法。
function stringFormat(source) {
}
类 使用 Pascal命名法。
function TextNode(options) {
}
枚举变量 使用 Pascal命名法,枚举的属性 使用 全部字母大写,单词间下划线分隔 的命名方式。
var TargetState = {
    READING: 1,
    READED: 2,
    APPLIED: 3,
    READY: 4
};
命名空间 使用 Camel命名法。
equipments.heavyWeapons = {};
类名 使用 名词。
函数名 使用 动宾短语。
function getStyle(element) {
}
boolean 类型的变量使用 is 或 has 开头。
Promise对象 用 动宾短语的进行时 表达。

注释

代码细节注释全部使用行注释,不可使用这样的/*...*/多行注释
为了便于代码阅读和自文档化,以下内容必须包含以 /**...*/ 形式的块注释。
  • 文件
  • namespace
  • 函数或方法
  • 类属性
  • 事件
  • 全局变量
  • 常量
注释中类型说明格式以{开始, 以}结束。

常用类型如:{string}, {number}, {boolean}, {Object}, {Function}, {RegExp}, {Array}, {Date}。

/**
 * 函数描述
 *
 * @param {string} p1 参数1的说明
 * @param {string} p2 参数2的说明,比较长
 *     那就换行了.
 * @param {number=} p3 参数3的说明(可选)
 * @return {Object} 返回值描述
 */
类型定义 语法示例 解释
String {string} --
Number {number} --
Boolean {boolean} --
Object {Object} --
Function {Function} --
RegExp {RegExp} --
Array {Array} --
Date {Date} --
单一类型集合 {Array.<string>} string 类型的数组
多类型 {(number|boolean)} 可能是 number 类型, 也可能是 boolean 类型
允许为null {?number} 可能是 number, 也可能是 null
不允许为null {!Object} Object 类型, 但不是 null
Function类型 {function(number, boolean)} 函数, 形参类型
Function带返回值 {function(number, boolean):string} 函数, 形参, 返回值类型
参数可选 @param {string=} name 可选参数, =为类型后缀
可变参数 @param {...number} args 变长参数, ...为类型前缀
任意类型 {*} 任意类型
可选任意类型 @param {*=} name 可选参数,类型不限
可变任意类型 @param {...*} args 变长参数,类型不限
文件注释

注释添加作者一项

/**
 * @file Describe the file
 * @author xiaozhao@domain.com
 */
命名空间注释
/**
 * 描述
 * @namespace
 */
var util = {};
使用 @class 标记类或构造函数。
/**
 * 描述
 *
 * @class
 */
function Developer() {
    // constructor body
}
使用 @extends 标记类的继承信息。
/**
 * 描述
 *
 * @class
 * @extends Developer
 */
function UserInfoController (){
  BaseController.call(this);
    
  this.init();
}
函数/方法注释必须包含函数说明,有参数和返回值时必须使用注释标识。
参数和返回值注释必须包含类型信息和说明。
/**
 * 函数描述
 *
 * @param {string} p1 参数1的说明
 * @param {string} p2 参数2的说明,比较长
 *     那就换行了.
 * @param {number=} p3 参数3的说明(可选)
 * @return {Object} 返回值描述
 */
function foo(p1, p2, p3) {
    var p3 = p3 || 10;
    return {
        p1: p1,
        p2: p2,
        p3: p3
    };
}
对 Object 中各项的描述, 必须使用 @param 标识。
/**
 * 函数描述
 *
 * @param {Object} option 参数描述
 * @param {string} option.url option项描述
 * @param {string=} option.method option项描述,可选参数
 */
function foo(option) {
    // TODO
}
重写父类方法时, 应当添加 @override 标识。如果重写的形参个数、类型、顺序和返回值类型均未发生变化,可省略 @param@return,仅用 @override 标识,否则仍应作完整注释。
必须使用 @event 标识事件,事件参数的标识与方法描述的参数标识相同。
/**
 * 值变更时触发
 *
 * @event
 * @param {Object} e e描述
 * @param {string} e.before before描述
 * @param {string} e.after after描述
 */
onchange: function (e) {
}
在会广播事件的函数前使用 @fires 标识广播的事件,在广播事件代码前使用 @event 标识事件。
常量注释

常量必须使用 @const 标记,并包含说明和类型信息。

/**
 * 常量说明
 *
 * @const
 * @type {string}
 */
var REQUEST_URL = 'myurl';

变量

变量在使用前必须通过 var 定义,每个 var 只能声明一个变量。变量必须 即用即声明,不得在函数或其它形式的代码块起始位置统一声明所有变量。
在 Equality Expression 中使用类型严格的 ===。仅当判断 null 或 undefined 时,允许使用 == null
尽可能使用简洁的表达式。
// 字符串为空

// good
if (!name) {
    // ......
}

// bad
if (name === '') {
    // ......
}
// 字符串非空

// good
if (name) {
    // ......
}

// bad
if (name !== '') {
    // ......
}
// 数组非空

// good
if (collection.length) {
    // ......
}

// bad
if (collection.length > 0) {
    // ......
}
// 布尔不成立

// good
if (!notTrue) {
    // ......
}

// bad
if (notTrue === false) {
    // ......
}
// null 或 undefined

// good
if (noValue == null) {
  // ......
}

// bad
if (noValue === null || typeof noValue === 'undefined') {
  // ......
}
不要在循环体中包含函数表达式,事先将函数提取到循环体外。
// good
function clicker() {
    // ......
}

for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    addListener(element, 'click', clicker);
}


// bad
for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    addListener(element, 'click', function () {});
}
对循环内多次使用的不变值,在循环外用变量缓存。
类型检测优先使用 typeof。对象类型检测使用 instanceofnullundefined 的检测使用 == null
// string
typeof variable === 'string'

// number
typeof variable === 'number'

// boolean
typeof variable === 'boolean'

// Function
typeof variable === 'function'

// Object
typeof variable === 'object'

// RegExp
variable instanceof RegExp

// Array
variable instanceof Array

// null
variable === null

// null or undefined
variable == null

// undefined
typeof variable === 'undefined'

类型转换

转换成 string 时,使用 + ''
转换成 number 时,通常使用 +
string 转换成 number,要转换的字符串结尾包含非数字并期望忽略时,使用 parseInt

var width = '200px';
parseInt(width, 10);

转换成 boolean 时,使用 !!
number 去除小数点,使用 Math.floor / Math.round / Math.ceil,不使用 parseInt
使用 数组+ 拼接字符串。

for in 遍历对象时, 使用 hasOwnProperty 过滤掉原型中的属性。
遍历数组不使用 for in
不会被调用的依赖模块,在文件开始处统一 require

网络请求

在懒加载、调用接口获取数据时,需要考虑长时间网络延迟的情况下显示加载动画。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容