JavaScript 规范整理
栏目: JavaScript · 发布时间: 4年前
内容简介:如果不熟悉英语,可以使用错误示例正确示例
不要使用拼音命名
如果不熟悉英语,可以使用 Codelf 或者 Google 翻译 ,避免使用拼音命名。
错误示例
// 这里是用户状态 const yongHuZhuangTai = 1
正确示例
const userStatus = 1
函数中的变量
js 中普通变量使用 小写开头驼峰命名法 ,而非不区分大小写,或使用下划线命名等等。
错误示例
// 用户操作日志备注 const useroperatinglogremark = '新增用户'
正确示例
const userOperatingLogRemark = '新增用户'
内部变量
如果需要不想让使用者使用的属性(能够看到),需要使用下划线开头。例如 _value
,代表内部的值,外部不应该直接访问(实际上可以做到)。
class DateFormat { constructor(fmt) { // 不想让外部使用 this._fmt = fmt } format(date) { // 具体格式化代码 } parse(str) { // 具体解析代码 } }
不要使用无意义的前缀命名
如果一个对象的变量名已经很好的标识了该对象,那么内部的属性就不能使用对象名作为前缀!
错误示例
// 活跃的日志信息 const activeLog = { activeUserId: 'rx', activeTime: new Date(), }
正确示例
const activeLog = { userId: 'rx', time: new Date(), }
ES6
优先使用 const/let
一般情况下,使用 const/let
声明变量,而不是使用 var
。因为使用 var
声明的变量会存在变量提升。
示例代码
;(function() { // 使用 var 声明的变量(初始值为 undefined) console.log(i) i = 1 console.log(i) // 此时使用 var 声明的变量 i 相当于在 function 顶部声明,然后在此处进行了赋值操作 var i = 0 // 使用 const 声明的变量(抛出异常 k is not defined) // console.log(k) k = 1 const k = 0 })()
关于可以参考 let 与 var 在 for 循环中的区别
使用新的函数声明方式
ES6 推出了一种更简洁的函数声明方式,不需要在写 function
,只要 名字 + ()
即可在 class
或 Object
中声明函数。
错误示例
const user = { name: 'rx', hello: function() { console.log('hello' + this.name) }, }
正确示例
const user = { name: 'rx', hello() { console.log('hello' + this.name) }, }
优先使用箭头函数而非 function
优先使用 箭头函数 而不是使用传统的函数,尤其是使用 匿名函数 时,更应如此。
错误示例
const sum = [1, 2, 3, 4] // 过滤出偶数 .filter(function(i) { return i % 2 === 0 }) // 将偶数翻倍 .map(function(i) { return i * 2 }) // 计算总和 .reduce(function(res, i) { return (res += i) }) console.log(sum)
正确示例
const sum = [1, 2, 3, 4] // 过滤出偶数 .filter(i => i % 2 === 0) // 将偶数翻倍 .map(i => i * 2) // 计算总和 .reduce((res, i) => (res += i)) console.log(sum)
不要使用 if 判断再赋予默认值
如果函数需要对参数做默认值处理,请不要使用 if
判空之后再修改参数,而是使用 ES6 的 默认参数
和 解构赋值
。
主要优点
- 减少代码,JavaScript 是动态语言,维护起来较为麻烦,代码越少,错误越少
- 清晰明了,可以让人一眼就能看出这个参数的默认值,而不需要关心函数内部的逻辑
- IDE 大多对此进行了支持,代码提示时便会告诉我们参数是可选的并且有默认值
错误示例
/** * 格式化日期 * @param {Date} [date] 日期对象。默认为当前时间 * @return {String} 格式化日期字符串 */ function formatDate(date) { if (date === undefined) { date = new Date() } return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}` }
正确示例
function formatDate(date = new Date()) { return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}` }
这里如果展开来讲实在太多,请参考 JavaScript 善用解构赋值
优先使用 Map 做键值对映射而非传统的对象
如果需要 键值映射 ,不要使用一般的对象,而是用 ES6 的 Map 。它不仅可以使用 任意类型的键 ,另外 Map 本身也是 有序 的哦
错误示例
const obj = { 2: '琉璃', 1: 'rx', '1': 'liuli', } // 结果为 true,因为属性 1 实际上会被转换为 '1' console.log(obj[1] === obj['1']) // 结果为 [ '1', '2'],因为是按照属性字符串 排序 的 console.log(Object.keys(obj))
正确示例
const map = new Map() .set(2, '琉璃') .set(1, 'rx') .set('1', 'liuli') // 结果为 false console.log(map.get(1) === map.get('1')) // 结果为 [ 2, 1, '1' ],因为是按照插入顺序排序的 console.log(Array.from(map.keys()))
优先使用模板字符串拼接多个字符串变量
如果需要拼接多个对象以及字符串时,不要使用 +
进行拼接,使用 es6 的 模板字符串
会更好一点。一般而言,如果需要拼接的变量超过 3 个,那么就应该使用模板字符串了。
错误示例
function hello(name, age, sex) { return 'name: ' + name + ', age: ' + age + ', sex: ' + sex }
正确示例
function hello(name, age, sex) { return `name: ${name}, age: ${age}, sex: ${sex}` }
当独立参数超过 3 个时使用对象参数并解构
错误示例
function hello(name, age, sex) { return `name: ${name}, age: ${age}, sex: ${sex}` }
正确示例
function hello({ name, age, sex }) { return `name: ${name}, age: ${age}, sex: ${sex}` }
不要写多余的 await
如果 await
是不必要的(在返回语句时,那么就不要用 async
标识函数),这是没有必要的 – 除非,你需要在这个函数内异步操作完成后有其他操作。
错误示例
const login = async ({ username, password }) => { if (!useranme) { console.log('用户名不能为空') return } if (!password) { console.log('密码不能为空') return } // 真正发起登录请求 return await userApi.login(user) }
正确示例
const login = ({ username, password }) => { if (!useranme) { console.log('用户名不能为空') return } if (!password) { console.log('密码不能为空') return } // 真正发起登录请求 return userApi.login(user) }
不要使用 == 进行比较
在 js 中使用 ==
比较相当危险,你永远不知道 js 到底是按照什么类型比较的,因为 js 会做各种隐式转换。而如果使用 ===
比较,则会同时比较 值
和 类型
是否都相同,避免了各种不确定的问题。
错误示例
console.log(1 == true) // true console.log(1 == '1') // true console.log('1' == true) // true console.log('0' == true) // false console.log([] == []) // false
扪心自问,你真的知道上面为什么会出现这种结果么?即便知道,对于其他人而言仍然是难以预测的,所以抛弃掉 ==
吧,学会使用更好的 ===
最好
console.log(1 == true) // false console.log(1 == '1') // false console.log('1' == true) // false console.log('0' == true) // false console.log([] == []) // false
使用计算属性名替代使用方括号表示法赋值
目前而言已经有了 计算属性名 用以在初始化时计算属性名,所以不需要再先声明对象再使用 方括号表示法 进行赋值了。
ES5 写法
const state = { 'user.username': function() {}, } state[Date.now()] = new Date() console.log(state)
ES6 写法
const state = { 'user.username'() {}, [Date.now()]: new Date(), } console.log(state)
简单的选项列表优先使用 Map 而非数组
对于复选框,想必很多人相当熟悉。下面使用 js 模拟一个复选框
const item = { id: 1, role: ['1', '2'], name: '', } const options = [ { roleid: '1', label: '黄金糕', }, { roleid: '2', label: '双皮奶', }, { roleid: '3', label: '蚵仔煎', }, ]
现在的需求是根据 role
计算显示值 name
的值
item.name = item.role .map(role => options.find(op => op.roleid === role)) .filter(s => s) .join(',')
但实际上这里应该使用 Map
替代数组,因为数组的 find
其实非常低效,也需要进行遍历,使用 Map
的实现
const item = { id: 1, role: [1, 2], name: '', } const options = new Map() .set(1, '黄金糕') .set(2, '双皮奶') .set(3, '蚵仔煎') function calcName(role) { return role .map(k => options.get(k)) .filter(s => s) .join(',') } item.name = calcName(item.role)
可以看到,获取时使用了 Map#get
,在效率上应该是极好的。
附: 该问题来自 https://segmentfault.com/q/1010000019426996
存放 id 标识列表使用 Set 而非数组
还是上面的例子,当你需要存取当前选中复选框的值 role
使用数组时,有可能遇到 id 重复的问题,实际上导致每次添加前需要使用 Array#includes
判断是否已存在。这里可以使用 Set
从数据结构层面避免掉可能重复的问题。
修改后的实现
const item = { id: 1, role: new Set([1, 2]), name: '', } const options = new Map() .set(1, '黄金糕') .set(2, '双皮奶') .set(3, '蚵仔煎') function calcName(role) { return Array.from(role) .map(k => options.get(k)) .filter(s => s) .join(',') } item.name = calcName(item.role)
先判断是否存在执行某些操作也非常方便,可以使用 Set#has
进行判断,当然时间复杂度时 O1。
逻辑代码
不要判断一个 Boolean 值并以此返回 Boolean 值
不要在得到一个 Boolean
的值后使用 if-else
进行判断,然后根据结果返回 true
或 false
,这真的显得非常非常蠢!
错误示例
// 模拟登录异步请求 const login = async ({ username, password }) => { const res = username === 'rx' && password === 'rx' if (res) { return true } else { return false } }
正确示例
// 模拟登录异步请求 const login = async ({ username, password }) => username === 'rx' && password === 'rx'
不要使用多余的变量
如果一个表达式立刻被使用并且只会被使用一次,那就不要使用变量声明,直接在需要的地方使用好了。
错误示例
// 模拟登录异步请求 const login = async ({ username, password }) => { const res = username === 'rx' && password === 'rx' return res }
正确示例
// 模拟登录异步请求 const login = async ({ username, password }) => { return username === 'rx' && password === 'rx' }
不要使用嵌套 if
不要使用多级的 if
嵌套,这会让代码变得丑陋且难以调试,应当优先使用 提前 return
的策略。
错误示例
// 模拟登录异步请求 const login = async ({ username, password }) => username === 'rx' && password === 'rx' async function submit(user) { const { username, password } = user if (username) { if (password) { const res = await login(user) if (res) { console.log('登录成功,即将跳转到首页') } else { console.log('登录失败,请检查用户名和密码') } } else { console.log('用户密码不能为空') } } else { console.log('用户名不能为空') } }
正确示例
// 模拟登录异步请求 const login = async ({ username, password }) => username === 'rx' && password === 'rx' async function submit(user) { const { username, password } = user if (!username) { console.log('用户名不能为空') return } if (!password) { console.log('用户密码不能为空') return } const res = await login(user) if (!res) { console.log('登录失败,请检查用户名和密码') return } console.log('登录成功,即将跳转到首页') }
不要先声明空对象然后一个个追加属性
有时候会碰到这种情况,先声明一个空对象,然后在下面一个个追加属性,为什么创建对象与初始化不放到一起做呢?
错误示例
// 模拟登录异步请求 const login = async ({ username, password }) => username === 'rx' && password === 'rx' async function submit(username, password) { // 数据格式校验处理。。。 const user = {} user.username = username.trim() user.password = password.trim() const res = await login(user) // 后续的错误处理。。。 }
正确示例
// 模拟登录异步请求 const login = async ({ username, password }) => username === 'rx' && password === 'rx' async function submit(username, password) { // 数据格式校验处理。。。 const user = { username: username.trim(), password: password.trim(), } const res = await login(user) // 后续的错误处理。。。 }
不要使用无意义的函数包裹
使用函数时,如果你想包裹的函数和原来函数的参数/返回值相同,那就直接应该使用函数作为参数,而非在包裹一层。给人的感觉就像是大夏天穿着棉袄吃雪糕 – 多此一举!
错误示例
// 判断是否是偶数的函数 const isEven = i => i % 2 === 0 //过滤出所有偶数 const res = [1, 2, 3, 4].filter(i => isEven(i))
正确示例
// 判断是否是偶数的函数 const isEven = i => i % 2 === 0 //过滤出所有偶数 const res = [1, 2, 3, 4].filter(isEven)
不要使用三元运算符进行复杂的计算
三元运算符适合于替代简单的 if-else
的情况,如果碰到较为复杂的情况,请使用 if + return
或者解构/默认参数的方式解决。
错误示例
function formatUser(user) { return user === undefined ? 'username: noname, password: blank' : 'username: ' + (user.username === undefined ? 'noname' : user.username) + ', password: ' + (user.password === undefined ? 'blank' : user.password) }
看到上面的代码就感觉到一股烂代码的味道扑面而来,这实在是太糟糕了!实际上只需要两行代码就好了!
正确示例
function formatUser({ username = 'noname', password = 'blank' } = {}) { return `username: ${username}, password: ${password}` }
如果变量有所关联则使用对象而非多个单独的变量
如果变量有所关联,例如一个表单,存储的时候不要使用单独的变量,将之存储到一个表单变量中更好。
错误示例
function login(){ const username = document.querySelector('#username') const password = document.querySelector('#password') const remeberMe = document.querySelector('#remeberMe') // 一些校验。。。 if (!validate(username, password, remeberMe)) { return } // 请求后台 const res = await userLogin.login(username, password, remeberMe) // 后处理。。。 }
正确示例
function login(){ const user = { username : document.querySelector('#username'), password : document.querySelector('#password'), remeberMe : document.querySelector('#remeberMe'), } // 一些校验。。。 if (!validate(user)) { return } // 请求后台 const res = await userLogin.login(user) // 后处理。。。 }
应该尽量解决编辑器警告
如果编辑器对我们的代码发出警告,那么一般都是我们代码出现了问题(一般开发人员的能力并不足以比肩编辑器 #MS 那些 dalao 的能力)。所以,如果出现了警告,应该先去解决它 – 如果你确认发生了错误,则通过注释/配置禁用它!
使用类型定义参数对象
如果一个函数需要一个对象参数,最好专门定义一个类型,并在注释上说明,便于在使用时 IDE 进行提示,而不需要去查找文档手册。
错误示例
/** * 格式化用户 * @param {Object} user 格式化的用户对象 */ function formatUser(user) { const { username, password } = user || {} return `user, username: ${username}, password: ${password}` } // 此处别人并不知道 User 里面到底有什么属性,只能去查看文档 const str = formatUser({ username: 'rx', password: '123456' }) console.log(str)
正确示例
class User { constructor(username, password) { this.username = username this.password = password } } /** * 格式化用户 * @param {User} user 格式化的用户对象 */ function formatUser(user) { const { username, password } = user || {} return `user, username: ${username}, password: ${password}` } const str = formatUser(new User('rx', '123456')) console.log(str)
尽量扁平化代码
尽量将 a
调用 b
, b
调用 c
,然后 b
调用 d
,优化为依次调用 a, b, c, d
。
注意: 这里使用的是 尽量 而非 不要 ,深层嵌套不可避免,但在局部上,应该采取扁平化的策略, 提前 return 避免嵌套 if-else 是个很好的例子。
以上所述就是小编给大家介绍的《JavaScript 规范整理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 照片整理系列二 —— 照片整理及归档的辛酸历程
- 我自己整理的码农周刊一周分享整理
- 【复习资料】ES6/ES7/ES8/ES9资料整理(个人整理)
- Hibernate 关系映射整理
- 大数据框架整理
- 树莓派资源整理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。