就三点:
- 编码风格:忌简忌繁、统一风格
- 编码结构:模块化、函数式、易读性、复用元素的抽象
- 编码过程:扩展能力、测试
编码风格
保持良好的编码风格
- 不要刻意简写难以理解的表达式,也不要嵌套过于冗余的函数
- 缩进统一、命名统一、标符统一、文件结构统一...,一切能以标准量化的的都需要拿标准约束
- Lint等QA约束工具是必须的,用工具来实践程序正义
更详细的编码规范,可以来这: Developer code guide
编码结构
Spaghetti code (面条代码)的特征
代码没有组织,且多处出现重复的代码块
- 一般是封装粒度不够造成
多个代码块之间高度耦合,跳来跳去,使其难以调试
- 函数抽象程度不够
- OOP理解不深刻
- 典型的命令式编程
代码不会分解成条件块或标签,使其难以阅读。
- 到这个程度就不知道代码写的有多糟了
避免面条代码的方法
- 需要复用的代码一定要封装
- “模块化”不仅仅是文件意义的模块化,而是指逻辑单元的模块化,比如函数;当然现在大部分框架、库、平台...都有自己成熟的模块化系统,在模块化的基础上尽量取得平衡
- 函数的模块化和封装要尽量地“函数式”,不依赖外部变量,不改变外部变量,有输入,有输出,不过度嵌套,中间量清晰易读
- 避免全局变量和类成员传递数据,函数内部更应该优先使用局部变量和参数变量
- 优秀的代码是不需要注释的,所以命名本身很重要很重要
优秀的代码组织应该是清晰的树状结构,自上而下分解任务, 自下而上完成任务。
编码过程
防止 over-engineering (过度设计)
过度设计是指,太过于考虑今后代码的扩展性、复用性,或太过于考虑测试的便利性,导致系统被过度设计为难以理解、难以重用的复杂结构。
世界上有两种“没有bug”的代码。一种是“没有明显的bug的代码”,另一种是“明显没有bug的代码”。
第一种情况,由于代码复杂不堪,加上很多测试,各种coverage,看起来测试都通过了,所以就认为代码是正确的。
第二种情况,由于代码简单直接,就算没写很多测试,你一眼看去就知道它不可能有bug。
你钟爱哪一种?
防止过度设计的方法:
- 先把眼前的问题解决掉,解决好,再考虑将来的扩展问题
- 先写出可用的代码,反复推敲,再考虑是否需要重用的问题
- 先写出可用,简单,明显没有bug的代码,再考虑测试的问题
代码规范可以参考上面链接就可以了,可以根据自己的情况修改规范以建立自己的标准,下面分享一些平日较为不易理解的代码片段。
隐式转换
==
和!=
操作符会在需要的情况下自动转换数据类型;
===
和!==
不会,它们会同时比较值和数据类型,也称为严格比较。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
[10] === 10 // false
[10] == 10 // true
'10' == 10 // true
'10' === 10 // false
[] == 0 // true
[] === 0 // false
'' == false // true (but true == "a" is false,因为true隐式转换为字符串为'1')
'' === false // false
赋值判断
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
// 正常流程
var a
if (b) {
a = b
} else {
a = c
}
// 三目运算
var a = b ? b : c
// 利用短路运算判断赋值
var a = b || c
数据类型判断typeof
和instanceof
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
/* typeof 会返回一个变量的基本类型,针对数组和对象均返回'object' */
typeof 666 // 'number'
typeof Date() // 'string'
typeof [] // 'object'
typeof {} // 'object'
typeof false // 'boolean'
typeof new Function() // 'function'
typeof undefined // 'undefined'
typeof null // 'object'
/*
instanceof 仅检测对象的原型链是否指向构造函数的prototype对象
由于Javascript中万物皆对象,故一切用new关键字实例的对象最深原型永远指向Object
*/
666 instanceof Number // false
new Number(666) instanceof Number // true
new Number(666) instanceof Object // true
'666' instanceof String // false
new String('666') instanceof String // true
new Object() instanceof Object // true
[] instanceof Object // true
[] instanceof Array // true
new Date() instanceof Date // true
new Date() instanceof Object // true
快速求和
- 1
- 2
- 3
// eval能做的事真的太多了
var nums = [1, 2, 3, 4, 5, 6...]
console.log('和:', eval(nums.join('+')))
简写判断
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
// 标准判断(推荐)
if (a) {
b()
}
// 简写
if (a) b()
// 利用短路运算简写
a && b()
// 或者(极力不推荐)
var foo = 10
foo == 10 && doSomething()
foo == 5 || doSomething()
with作用域
- 1
- 2
- 3
- 4
var obj = { name: 'xxx' }
with(obj) {
console.log(name) // 'xxx'
}
复杂的流程控制
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
// 一种不太好的情况
if (a) {
doSomethingA()
} else if (b) {
doSomethingB()
} else if (c) {
doSomethingC()
} else if (d || e) {
doSomethingDE()
} else if (f) {
doSomethingF()
} //...
// 可以用switch/case来代替
switch (true) {
case a:
doSomethingA()
break
case b:
doSomethingB()
break
case c:
doSomethingC()
break
case (d || e):
doSomethingDE()
break
case f:
doSomethingF()
break
default:
doSomethingDefault()
break
}
完