前端必须要注意的规范(三)之js规范

上一章主要讲了css的书写顺序以及一些可以省略精简更优的写法,这一章主要讲述js的一些前端规范

 

// 一.空格///
//1.二元运算符必须有一个空格,一元运算符与操作对象之间不允许有空格
    var a = !arr.length;
    a++;
    a = b + c;
//2.用作代码块其实的左花括号 "{" 前必须有一个空格
    if (condition) {
        //code
    }

    function funName() {
        //code
    }
//3.if/else/for/while/function/switch/do/try/catch/finally关键词后,必须有一个空格
    if (condition) {
        //code
    }

    while (condition) {
        //code
    }

    (function () {
        //code
    })();
//4.在对象创建时,属性中的 ":"之后必须有空格,":"之前不允许有空格
    var obj = {
        a: 1,
        b: 2,
        c: 3
    };
//5.函数声明、具名函数表达式、函数调用中,函数名和 "(" 之间不允许有空格
    function funName() {
        //code
    }

    var funName = function funName() {
        //code
    };

    funName();
//6."," 和 ";"前不允许有空格。如果不位于行尾, ","和";"后必须跟一个空格
    callFunc(a, b);
//7.在函数调用、函数声明、括号表达式、属性访问、if/for/while/switch/catch等语句中,"()" 和 "[]" 内紧贴括号部分不允许有空格
    callFunc(param1, param2, param3);

    save(this.list[this.indexes[i]]);

    needInm && (variable += inm);

    if (name > list.length) {}

    while (len--) {}
//8.单行声明的数组与对象,如果包含元素,"{}" 和 "[]" 内紧贴括号部分不允许包含空格
    var arr1 = [];
    var arr2 = [1, 2, 3];
    var obj1 = {};
    var obj2 = {name: 'obj'};
    var obj3 = {
        name: 'obj',
        age: 20,
        sex: 1
    };
//9.行尾不允许有多余的空格
/二.换行/
//1.每个独立语句结束后必须换行
//2.每行不得超过120个字符(超长的不可分割的代码允许例外,比如复杂的正则表达式,长字符串不在例外之列)
//3.运算符处换行时,运算符必须在新行的行首
    if (user.isAuthenticated()
        && user.isInRole('admin')
        && user.hasAuthority('add-admin')
        || user.hasAuthority('delete-admin')
    ) {
        //code
    }

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

    foo(
        a,
        b,
        callback
    );
//5.[建议]不同行为或逻辑的语句集,使用空行隔开,更易阅读
    function setStyle(element, property, value) {
    if (element == null) {
        return;
    }

    element.style[property] = value;
    }
//6.在语句的行长度超过 120 时,根据逻辑条件合理缩进
//较复杂的逻辑条件组合,将每个条件独立一行,逻辑运算放置在行首进行分隔,或将部分逻辑组合进行分隔
//建议最终将右括号与左大括号独立一行,保证与'if'内语句块能容易视觉辨别
if (user.isAuthenticated()
    && user.isInRole('admin')
    && user.hasAuthority('add-admin')
    || user.hasAuthority('delete-admin')
) {
    //code
}

//按一定长度截断字符串,并使用+运算符进行连接
//分隔字符串尽量按语义进行,如不要在一个完整的名称中间断开
//特别的,对于HTML片段的拼接,通过缩进,保持和HTML相同的结构
var html = ''
    + '<article>'
    +   '<h1>Title here</h1>'
    +   '<p>This is a paragraph</p>'
    +   '<footer>Complete</footer>'
    + '</article>';

//也可使用数组来进行拼接,相对'+'更容易调整缩进
var html = [
    '<article>',
        '<h1>Title here</h1>',
        '<p>This is a paragraph</p>',
        '<footer>Complete</footer>',
    '</article>'
];
html = html.join('');

//可以按逻辑对参数进行组合
//最经典的baidu.format函数,调用时将参数分为"模板"和“数据”两块
baidu.format(
    dateFormatTemplate,
    year, month, date, hour, minute, second
);

//当参数调用时,如果有一个或以上参数跨越多行,应当每一个参数独立一行
setTimeout(
    function () {
        alert('hello');
    },
    200
);

order.data.read(
    'id=' + me.model.id,
    function (data) {
        me.attchToModel(data.result);
        callback();
    },
    300
);

//链式调用较长时采用缩进进行调整
$('#items')
    .find('.selected')
    .highlight()
    .end();

//三元运算符由3部分组成,因此其换行应当根据每个部分的长度不同,形成不同的情况
var result = thisIsAVeryLongCondition
    ? resultA : resultB;

var result = conditon
    ? thisIsAVeryLongResult
    : resultB;

//数组和对象初始化的混用,严格按照每个对象的"{"和"}"在独立一行的风格书写
var array = [
    {
    //    code
    },
    {
    //    code
    }
];

//[建议]对于if...else...,try...catch...finally等语句,推荐使用在“}”后添加一个换行的风格,使代码层次结构清晰,阅读性更好
if (condition) {
    //code
}
else{
    //code
}

try {
    //code
}
catch (ex) {
    //code
}

//语句//
//1.不得省略语句结束的分号
//2.在if/else/for/do/while语句中,即使只有一行,也不得省略块{...}
if (condition) {
    callFunc();
}
//3.函数定义结束不允许添加分号
function funName() {

}

//如果是函数表达式,分号不能省略
var funName = function () {

};

//4.IIFE 必须在函数表达式外添加"(",非IIFE不得在函数表达式外添加"("
//能够让代码在阅读的一开始就能判断函数是否立即被调用
var task = (function () {
    return result;
})();

var func = function () {

};

//命名//
//1.变量使用驼峰命名法
var loadingModules = {};
//2.常量使用全部子母大写,单词间下划线分隔的命名方式
var HTML_ENTITY = {};
//3.函数使用驼峰命名法
function stringFormat(source) {

}
//4.函数的参数使用驼峰命名法
function hear(theBells) {

}
//5.类使用Pascal命名法(帕斯卡命名法)
function TextNode(options) {

}
//6.类的方法/属性使用驼峰命名法
function TextNode(value, engine) {
    this.value = value;
    this.engine = engine;
}

TextNode.prototype.clone = function () {
    return this;
};
//7.枚举变量使用Pascal命名法,枚举的属性使用全部字母大写,单词下划线分隔的命名方式
var TargetState = {
    READING: 1,
    READED: 2,
    APPLIED: 3,
    READY: 4
};
//8.命名空间使用驼峰命名法
equipments.heavyWeapons = {};

//9.由多个单词组成的缩写词,在命名中,根据当前命名法和出现的位置,所有字母的大小写与首字母的大小写保持一致
function XMLParser() {

}
function insertHTML(element, html) {

}
var httpRequest = new HTTPRequest();

//10.类名使用名词
function Engine(options) {

}
//11.[建议]函数名使用动宾短语
function getStyle(element) {

}

//12.[建议]boolean类型的变量使用is或has开头
var isReady = false;
var hasMoreCommands = false;

//13.[建议]Promise对象用动宾短语的进行时表达
var loadingData = ajax.get('url');
loadingData.then(callback);


/注释//
//1.为了便于代码阅读和自文档化,下面内容必须包含以/**...*/形式的快注释中
//  1.文件 2.namespace 3.类 4.函数或方法 5.类属性 6.事件 7.全局变量 8.常量 9.AMD模块

//2.文档注释前必须空一行

//3.自文档化的文档说明what,而不是how


//4.类型定义都是以“{”开始,以"}"结束
//类型不仅局限于内置的类型,也可以是自定义类型
//对于基本类型{string},{number},{boolean},首字母必须小写

/**
 *
 *  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}  函数,形参,返回值类型
 *  Promise           Promise.<resoleType,rejectType>   Promise,成功返回的数据类型,失败返回的数据类型
 *  参数可选          @param{string=} name              可选参数,=为类型后缀
 *  可变参数          @param{...number} args            变长参数,...为类型前缀
 *  任意类型          {*}                               任意类型
 *  可选任意类型      @param{*=} name                   可选参数,类型不限
 *  可变任意类型      @param{...*}args                  变长参数,类型不限
 *
 */


//5.文件顶部必须包含文件注释,用@file标识文件说明
/**
 * @file Describe the file
 */

//[建议]文件注释中可以用@author 标识开发者信息

//6.命名空间使用@namespace 标识
/**
 * @namespace
 */
var util = {};

//7.使用@class标记类或构造函数
/**
 * 描述
 * @class
 */
function Developer() {

}

//8.[建议]使用@extends标记类的继承信息
/**
 * 描述
 *
 * @class
 * @extends Developer
 */
function Fronteer() {
    Developer.call(this);
}
util.inherits(Fronteer,Developer);

//9.函数/方法注释
//函数/方法注释必须包含函数说明,有参数和返回值时必须使用注释标识

/**
 * 函数标书
 * @param {string} p1 参数1的说明
 * @param {string} p2 参数2的说明,比较长
 *      那就换行了
 * @param {number=} p3  参数3的说明(可选)
 * @returns {object} 返回值描述
 */
function foo(p1, p2, p3) {
    var p3 = p3 || 10;
    return {
        p1: p1,
        p2: p2,
        p3: p3
    };
}


//10.对Object中各项的描述,必须使用@param标识
/**
 * 函数描述
 * @param {Object} option 参数描述
 * @param {string} option.url  option项描述
 * @param {string=} option.method  option项描述,可选参数
 */
function foo(option) {

}

//11.事件注释
//必须使用@event标识事件,事件参数的标识与方法描述的参数标识相同

/**
 * 点击处理
 *
 * @fires Select#change
 * @private
 */
Select.prototype.clickHandler = function () {

    /**
     * 值变更时触发
     *
     * @event Select#change
     * @param {Object} e e描述
     * @param {string} e.before before描述
     * @param {string} e.after after描述
     */
    this.fire(
        'change',
        {
            before: 'foo',
            after: 'bar'
        }
    );
};

//12.常量注释
/**
 * 常量说明
 * @const
 * @type {string}
 */
var REQUEST_URL = 'myurl.do';

//13.有时我们会使用一些特殊标记进行说明。特殊标记必须使用单行注释的形式。下面列举了一些常用标记
//   1.TODO:有功能待实现。此时需要对将要实现的功能进行简单说明
//   2.FIXME:该处代码运行没问题,但可能由于时间赶,需要修正,此时需要对如何修正进行简单说明
//   3.HACK:为了修正某些问题而写的不太好或者使用了某些诡异手段的代码。此时需要对思路或诡异手段进行描述
//   4.XXX:该处存在陷阱,需要对陷阱进行描述


//变量//
//1.变量、函数在使用前必须先定义(不通过var定义变量将导致变量污染全局环境)
var name = 'MyName';
//2.每个var只能声明一个变量
var hangModules = [];
var missModules = [];
var visited = [];

//3.尽可能使用简洁的表达式
//字符串为空
if (!name) {

}
//字符串非空
if (name) {

}
//数组非空
if (collection.length) {

}
//布尔不成立
if (!notTrue) {

}
//null或undefined
if (noValue == null) {

}

//4.对于相同变量或表达式的多值条件,用switch 代替If
//good
switch (typeof variable) {
    case 'object':
        //......
        break;
    case 'number':
    case 'boolean':
    case 'string':
        //....
        break;
}

//bad
var type = typeof variable;
if (type === 'object') {
    //.....
}
else if (type === 'number' || type === 'boolean' || type === 'string') {
    //.....
}

//5.如果函数或全局中的else块后没哟任何语句,可以删除else
//good
function getName() {
    if (name) {
        return name;
    }
    return 'unnamed';
}

//bad
function getName() {
    if (name) {
        return name;
    }
    else{
        return 'unnamed';
    }
}

//6.不要再循环体重包含函数表达式,事先将函数提取到循环体外(循环体中的函数表达式,运行过程中会生成循环次数个函数对象)
//good
function clicker() {
    //........
}
for (var i = 0, len = elements.length; i < len; i++) {
    var element = element[i];
    addListener(element, 'click', clicker);
}

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

//7.对循环内多次使用的不变值,在循环外用变量缓存
//good
var width = wrap.offsetWidth + 'px';
for (var i = 0, len = element.length; i < len; i++) {
    var element = element[i];
    element.style.width = width;
    //...
}

//bad
for (var i = 0, len = element.length; i < len; i++) {
    var element = element[i];
    element.style.width = wrap.offsetWidth + 'px';
    //...
}

//8.[建议]对有序集合进行遍历时,缓存length
//虽然现代浏览器都对数组长度进行了缓存,但对于一些宿主对象和老旧浏览器的数组对象,在每次length访问时会动态计算元素个数,此时浏览器缓存Length能有效提高程序性能
for (var i = 0, len = element.length; i < len; i++) {
    var element = elements[i];
    //.......
}

//9.对有序集合进行顺序无关的遍历时,使用逆序遍历(逆序遍历可以节省变量,代码比较优化)
var len = elements.length;
while (len--) {
    var element = elements[len];
}

//类型检测
//类型检测优先使用typeof,对象类型检测使用 instanceof,null或undefined的检测使用 ==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'


//类型转换
//1)[建议]转换成string时,使用 + ''
num + '';

//2)[建议]转换成number时,通常使用 +
+str;

//3)string转换成number,要转换的字符串结尾包含非数字并期望忽略时,使用parseInt
var width = '200px';
parseInt(width, 10);

//4)[建议]使用parseInt时,必须指定进制项
//good
parseInt(str, 10);
//bad
parseInt(str);

//5)数字转换成boolean时,使用!!
var num = 3.14;
!!num;

//6)[建议] number去除小数点,使用Math.floor/Math.round/Math.ceil,不使用parseInt
//good
var num = 3.14;
Math.ceil(num);
//bad
var num = 3.14;
parseInt(num, 10);

/字符串//
//1.字符串开头和结束使用单引号'(为方便HTML中包含双引号而不需要转义写法)
var str = '我是一个字符串';
var html = '<div class="cls">拼接HTML可以省去双引号转义</div>';

//2.使用数组或+拼接字符串
//使用 + 拼接字符串,如果拼接的全部是StirngLIteral,压缩工具可以对其进行自动合并的优化。所以,静态字符串建议使用 + 拼接
//在现代浏览器下,使用+拼接字符串,性能较数组的方式要高
//如需要兼顾老旧浏览器,应尽量使用数组拼接字符串

//使用数组拼接字符串
var str = [
    //推荐换行开始并缩进开始第一个字符串,对其代码,方便阅读
    '<ul>',
        '<li>第一项</li>',
        '<li>第二项</li>',
    '</ul>'
].join('');

//使用'+'拼接字符串
var str2 = ''//建议第一个为空字符串,第二个开始换行并缩进开始,对齐代码,方便阅读
    + '<ul>'
    +   '<li>第一项</li>'
    +   '<li>第二项</li>'
    + '</ul>';

//3.使用字符串拼接的方式生成HTML,需要根据语境进行合理的转义
//HTML转义
var str = '<p>' + htmlEncode(content) + '</p>';
//HTML转义
var str = '<input type="text" value="'+ htmlEncode(value) +'" />';
//URL转义
var str = '<a href="/?key='+  htmlEncode(urlEncode(value)) + '">link</a>';
//Javascript字符串转义 + HTML转义
var str = '<button onclick="checked(\''+ htmlEncode(strLiteral(name)) +'\')">提交</button>';

//使用对象字面量{}创建新Object
var obj = {};
//对象创建时,如果一个对象的所有属性均可以不添加引号,建议所有属性不添加引号
var info = {
    name: 'someone',
    age: 28
};

//对象创建时,如果任何一个属性需要添加引号,则所有属性建议加'
var info = {
    'name': 'someone',
    'age': 28,
    'more-info': '...'
};
//不允许修改和扩展任何原生对象和宿主对象的原型

//[建议]属性访问时,尽量使用'.'
//属性名符合identifier的要求,就可以通过'.'来访问,否则就只能通过[expr]方式访问
info.age;
info['more-info'];

/数组//
//1.使用数组字面量[]创新数组,除非想要创建的是指定长度的数组
var arr = [];

//2.遍历数组不使用for in
//数组对象可能存在数字以外的属性,这种情况下for in 不会得到正确结果

//3.[建议]不因为性能的原因自己实现数组排序功能,尽量使用数组的sort方法

//4.[建议]清空数组使用 .length = 0

函数
//1.一个函数的长度控制在50行以内
//2.一个函数的参数控制在6个以内

//3.有些函数的参数并不是作为算法的输入,而是对算法的某些分支条件判断之用,此类参数建议通过一个options参数传递
function removeElement(element, removeEventListeners) {
    element.parent.removeChild(element);
    if (removeEventListeners) {
        element.clearEventListeners();
    }
}

//可以转换为下面的签名
function removeElement(element, options) {
    element.parent.removeChild(element);
    if (options.removeEventListeners) {
        element.clearEventListeners();
    }
}
//这种模式的几个显著的优势
//1)boolean 型的配置项具备名称,从调用的代码上更易理解其表达的逻辑意义
//2)使用下面这种,当配置项有增长时,无需无休止增加参数个数,不贵出现removeElement(element, true, false, false, 3)这样难以理解的调用代码
//3)当部分配置参数可选时,多个参数的形式非常难处理重载逻辑,而使用一个options对象只需判断属性是否存在,实现得以简化

//空函数不使用new Function() 的形式
var emptyFunction = function () {};

//对于性能有高要求的场合,建议存一个空函数的变量,供多处使用
var EMPTY_FUNCTION = function () {};
function MyClass() {
}
MyClass.prototype.abstractMethod = EMPTY_FUNCTION;
MyClass.prototype.hooks.before = EMPTY_FUNCTION;
MyClass.prototype.hooks.after = EMPTY_FUNCTION;

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值