web前端

高级攻城狮从代码规范开始——web前端代码规范

命名规范

文件和文件夹命名

文件夹和文件名采用英文小写字母命名,多个英语单词用 “-” 分割,不使用驼峰命名,如:hello-world
编写组件使用 “c-” 打头,如:编写一个select组件,文件夹或者文件名定义[c-select]

样式表命名

样式表命名采用英文小写字母命名,多个英语单词用 “-” 分割,不使用驼峰命名,如:hello-world

JS命名

js变量使用驼峰命名,不使用-号分割

// 不推荐
let foo_bar = 'hello eleme';

// 推荐
let fooBar = 'hello eleme';

常量要大写

// 不推荐
let prefix = 'https://www.javanx.cn/';
let Prefix = 'http://www.javanx.cn/'

// 推荐
const PREFIX = 'www.javanx.cn';

定义dispatch或者commit的请求类型时,按照A_打头代表action,M_打头代表mutation的方式区分请求类型

注释命名

在stylus和js文件中添加注释时,在“//”后面加入空格再添加文字

/*不推荐*/
//不推荐
; // 不推荐

/* 推荐 */
// 推荐
;

在写pug模板时,在“//”后面最好加上-再空格,因为“//”会被转义成,“//-”不会被转义成任何东西

统一代码风格

Stylus代码风格

2个空格缩进,UTF-8 编码
如果你的代码中包含大括号,确保大括号与选择器之间留空,冒号后面留空,注释内外前后留空

/* 我是注释 */
div { /* 我是注释 */ }
span {
  color: red; /* 我是注释 */
}

一个选择器中有多个样式声明时每条写一行
多个选择器使用逗号隔开时写在不同的行,修改时不容易漏掉逗号后面的选择器

div,
span
  color: red
  font-size: 12px

用逗号分隔的多个样式值写成多行,便于阅读与编辑

.block 
  box-shadow: 0 0 0 rgba(#000, 0.1),
              1px 1px 0 rgba(#000, 0.2),
              2px 2px 0 rgba(#000, 0.3),
              3px 3px 0 rgba(#000, 0.4),
              4px 4px 0 rgba(#000, 0.5)

避免使用 ID 选择器,权重太高,不易维护
@require和@import支持引入css文件,避免首页产生过多HTTP请求,可以使用这两个关键字合并css文件
0 值的单位建议省略,但不强制,因为大部分 0 值的单位是没用的
类名中的字母一律小写,只使用字母、数字以及“-”,因为解析样式表时不区分大小写

JS代码风格

2个空格缩进,UTF-8 编码
打开严格模式

'use strict'; // 写在文件顶端

使用单引号,这样可以跟 HTML 的双引号更好的一起工作
在语句(Statement)的结尾加分号

// 不建议
const fn = function() {
  // Long code
} // 没有分号

// 建议
const fn = function() {
  // Long code
}; // 这里有分号

/* 踩坑 */
const f1 = function ff1() {
  return function() {
    return 1;
  };
} // 此处漏写分号
(function() { // 此处调用了上面的ff1,WHAT THE FUCK
})();
console.log(f1); // 1

const f2 = function ff2() {
  return function() {
    return 1;
  };
} // 此处漏写分号
// IIFE
;(function() { // 注意前面的分号
})();
console.log(f2); // function

在二元和三元运算符的符号与操作数之间添加空格,在非行末的 , ; } 后添加空格,在 { 前添加空格。并在每个逻辑块中间添加空白行。 特别的,在 if、while 等关键字后加空格,与函数调用做区分

// 不推荐
let foo='bar',hello=foo+2,test=true;
function hi(){
  // ...
}
if(foo&&hello){
  // ...
}else if(foo){
  // ...
}else if(! test){
  // ...
}

// 推荐
let foo = 'bar';
let hello = foo + 2;
let test = true;

function hi(arg1, arg2) {
  // ...
}

if (foo && hello) {
  // ...
} else if (foo) {
  // ...
} else if (!test) {
  // ...
}

不要为大括号另写一行

// 不推荐
if (foo)
{
  // ...
}

// 推荐
if (foo) {
  // ...
}

// 不允许
return
{
  a: 1
};

// 一定要
return {
  a: 1
};

写 else 时不要另起一行

// 不推荐
if (test) {
  things1();
  things2();
}
else {
  things3();
}

// 推荐
if (test) {
  things1();
  things2();
} else {
  things3();
}

使用变量之前必须先定义,不要定义全局变量

// 变量 undefinedVar 从未定义过
undefinedVar = 1; // 严格模式中报错
console.log(global.undefinedVar); // 1

// 不推荐
let hello = 1, world = 2;

// 推荐
let hello = 1;
let world = 2;
let foo, fee, fxx;

/* 变量和闭包遇到的坑 */
void function () {
  for (let i = 0; i < arr.length; ++i) {
    (function () {
      console.log(i); // undefined i不在闭包范围内

      for (let i = 0; i < 10; ++i) {
        // Do some other things
      }
    })();
  }
}();

const elements = [ div1, div2, div3 ];
for (let i = 0; i < elements.length; ++i) {
  elements[i].addEventListener('event', function() {
    console.log(i); // 3
  });
}

使用字面量

// 不建议
const obj = new Object();
const array = new Array();

// 推荐
const obj = {};
const array = [];

// 鉴于 Array 构造函数的特殊性,不建议
const arr1 = new Array(4, 5, 6); // [4, 5, 6]

// 以免与下面混淆
const arr2 = new Array(4); // [ undefined * 4 ]
// 等价于(不推荐)
const arr3 = [];
arr3.length = 4;
// 等价于(不推荐)
const arr4 = [,,,,];
console.log('0' in arr2, '0' in arr3, '0' in arr4); // false, false, false

// 不推荐
let str = new String('str');
console.log(str === 'str'); // false

let bool = new Boolean(false);
if (bool) {
  console.log('wat'); // wat
}

// 当真需要使用字面量包装类时,使用显式强制转换(请先三思)
let strObject = Object('str');
strObject.customProperty = someValue;

建议使用 ===/!== 而非 ==/!=,== 的规则比较复杂,大家可能记不住

// 不推荐
function foo(a) {
  if (a == 123) {
    // ...
  }
}

// 推荐
function foo(a) {
  a = Number(a);
  if (a === 123) {
    // ...
  }
}

// 隐式转换
let a = '';

// false
if (a === 0);

// true
if (a == 0);

对于可能不存在的全局引用可以先做如此判断

if (typeof localStorage !== 'undefined') {
  // 此时访问 localStorage 绝对不会出现引用错误
}

// Or
if ('localStorage' in self) {
  // 此时访问 localStorage 绝对不会出现引用错误
}

/* 区分 undefined */
let a = undefined;

// 判断一个全局变量是否有声明
'a' in self; // true

// 判断一个变量是否为 undefined 并将未声明的引用作为 undefined 处理
typeof a !== 'undefined'; // false

避免无必要的 if 语句、三元运算符

const arr = [1, 2, 3];

// 不推荐
let flag1 = arr.length > 0 ? true : false;

// 不推荐
let flag2;
if (arr.length > 0) {
  flag2 = true;
} else {
  flag2 = false;
}

// 推荐
let flag3 = arr.length > 0;

合理的格式化三元运算符

// 不推荐
let flag1 = veryLooooooooooonnnnggggggCondition ? resultWhenTruth : resultWhenFalsy;

// 推荐
let flag2 = veryLooooooooooonnnnggggggCondition
              ? resultWhenTruth
              : resultWhenFalsy;

复杂逻辑中建议使用显式转换

+num === Number(num);
!!bool === Boolean(bool);
str + '' === String(str);

// 特别的
if (bool)
// 等价于
if (Boolean(bool))
// 故
if ([]) {
  console.log('true'); // true
}
// 而
if ([] === true) {
  console.log('true'); // 无输出
}

// 另外
if (Boolean(String(false))) {
  console.log('true'); // true
}

不要使用 parseInt 做整数转换,如需使用 parseInt,请给它传入第二个参数 10,在IE上有BUG,WHAT THE FUCK

let floatValue = 123.456;

// 不要
let intValue = parseInt(floatValue);

// 可以用
let intValue2 = floatValue | 0;

// 更显然的
let intValue3 = Math.floor(floatValue);

特殊的数字处理使用 parseFloat 作转换

// 例如有:
// <div id="div" style="width: 10px"></div>

let divWidth = getComputedStyle(document.getElementById('div')).width; // '10px'

console.log(parseFloat(divWidth)); // 10
console.log(Number(divWidth)); // NaN
console.log(+divWidth); // NaN

如果想自定义的函数按照从上至下的顺序被执行,那你需要使用表达式来定义函数,而不是函数语句

// 不推荐
function fee() {
  // ...
}

// 推荐
const foo = function() {
  // ...
};

/* confused */
void function() {
  // 此处可以正常使用函数,但逻辑不清晰
  foo();

  return null;

  function foo() {};
}();

只引用一次的函数建议匿名定义,因为名称存在主观因素

// 不推荐
const foo = function() {
  // ...
};
element.onclick = foo;

// 推荐
element.onclick = function() {
  // ...
};

自执行函数

// 不推荐
(function() {
  // ...
})();

+function() {
  // ...
}();

// 推荐
!function() {
  // ...
}();

// 推荐
void function() {
  // ...
}();

/* 踩坑 */
let a = 1 // 此处无分号

+function() {
  return 2
}();

// 此处 a 的值为 3

使用Promise解决嵌套问题

// 不推荐
async1(function() {
  // TODO 1
  async2(function() {
    // TODO 2
    async3(function() {
      // TODO 3
    });
  });
});

// 推荐
Promise.resolve()
  .then(function() {
    return new Promise(function(resolve) {
      async1(resolve);
    });
  })
  .then(function() {
    // TODO 1
    return new Promise(function(resolve) {
      async2(resolve);
    });
  })
  .then(function() {
    // TODO 2
    return new Promise(function(resolve) {
      async3(resolve);
    });
  })
  .then(function() {
    // TODO 3
  });

禁止使用未定义的变量
禁止使用 eval,非用不可时可以使用 Function 构造器替代
禁止使用 with 语句
禁止在块作用域中使用函数声明语句

if (true) {
  // 禁止
  function func1() {
    // ...
  }
  // 允许
  const func2 = function() {
    // ...
  };
}

禁止使用 arguments 映射

void function(a) {
  arguments[0]++;
  // 此处 a 为 2
}(1);

禁止使用保留字做变量名如 interface 等

公告

以后每月5、15、25号更新原创文章,内容不限,喜欢小编的可以点击关注,也可在下方评论留言,你喜欢什么内容,小编根据大家喜欢的内容尝试更新

(0)

本文由 Web秀 作者:Javan 发表,转载请注明来源!

热评文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注