前言: 虽然最近项目周期挺紧张的,晚上还是尽量挤出时间阅读《编写可维护的JavaScript》这本书籍。书籍总共分为三部分(编程风格,编程实践,自动化),本文是第一部分编程风格中我认为比较精彩的片段(检测值 && 格式化),也应用在了当前的项目中,整理出来跟大家分享,希望对大家在重构优化代码方面能够带来一定的帮助。
情景引入
在JavaScript中,我们常常会看到这种代码:变量和null的比较(这种写法很有问题),用来判断变量是否赋被赋予了一个合理的值。比如:
var Controller = {
process: function (items) {
if (item !== null) { // 不好的写法
items.sort()
items.forEach(item => {
// 一些代码
})
}
}
}
复制代码
在这段代码中,process方法显然是希望items是一个数组,因为我们看到items拥有sort()和forEach().这段代码的意图非常明显;如果参数items不是一个数组,则停止接下来的操作。我们来分析一下,这种写法的问题在于和null比较并不能真正避免错误的发生。items的值可以是1,也可以是字符串,甚至可以是任意对象。这些值都和null不相等,进而会导致process()方法一旦执行到sort()时就会出错。
仅仅和null比较并不能提供足够的信息来判断后续的代码执行是否真的安全。好在JavaScript为我们提供了多种方法来检测变量的真实值。
检测值
一、检测原始值
在JavaScript中有5种原始类型:字符串,数字,布尔值,undefined,null
对于字符串,数字,布尔值,undefined,最佳选择是使用typeof运算符
示例代码:
// 检测字符串
if (typeof name === "string") {
// 执行代码
}
// 检测数字
if (typeof count === "number") {
// 一些代码
}
// 检测数字
if (typeof found === "boolean") {
// 一些代码
}
// 检测undefined
if (typeof MyApp === "undefined") {
// 一些代码
}
复制代码
对于null
null,一般不应用于检测语句。正如上文情景引入中提到的,简单地和null比较通常不会包含足够的信息以判断值的类型是否合法。但有一个例外,如果所期望的值真的是null,则可以直接和null进行比较。 如果使用typeof运算符比较null,运行typeof null则返回'object',这是一种低效的判断null的方法。 如果你需要验证null,请直接使用恒等运算符(===)或非等运算符(!==) 示例代码: 输入框的值的判断
if (this.skuName !== null) {
// 输入框有值才执行请求接口
this.copySkuBlock()
} else {
// 提示输入框要输入值
this.$message({
type: 'error',
message: '请输入商品规格'
})
}
复制代码
二、检测引用值
在JavaScript钟有4种引用类型:Object, Array, Date, 和Error。
示例代码:
// 检测日期
if (value instanceof Date) {
// 一些代码
}
// 检测正则表达式
if (value instanceof RegExp) {
// 一些代码
}
// 检测Error
if (value instanceof Error) {
// 一些代码
throw value
}
复制代码
三、检测函数
从技术上讲, JavaScript中的函数是引用类型,同样存在Function构造函数。由于instanceof运算符不能跨帧使用,typeof运算符则是检测函数的最佳选择。
示例代码:
function myFunc () {
// 不好的写法 不能跨帧使用,因为每个帧都有各自的Function构造函数
console.log(myFunc instanceof Function) // true
// 好的写法 能跨帧使用, 但只能在IE9+使用
console.log(typeof myFunc === "function") // true
}
复制代码
四、检测数组
ES5将**Array.isArray()**的方法正式引入JavaScript,唯一的目的就是准确地检测一个值是否为数组,IE9+支持。
示例代码:
function isArray () {
if (typeof Array.isArray === "function") {
return Array.isArray(value)
} else {
return Object.prototype.toString.call(value) === "[object Array]"
}
}
复制代码
五、检测属性
另外一种用到null(以及undefined)的场景是当检测一个属性是否在对象中存在时。比如:
// 不好的写法: 和null比较
if (object[propertyName] !== null) {
// 一些代码
}
复制代码
判断对象中的属性是否存在最好的方法是使用in运算符。 in运算符仅仅会简单地判断属性是否存在,而不会去读属性的值。
示例代码:
A. 如果实例对象的属性存在、或者继承自对象的原型,in运算符都会返回true。比如:
if ("count" in object) {
// 一些代码
}
复制代码
B. 如果你只想检测实例对象的某个属性是否存在,则使用hasOwnProperty()方法,仅支持IE9+
if (object.hasOwnproperty("count")) {
// 一些代码
}
复制代码
因此,在判断实例对象的属性是否存在时,我更倾向于使用in运算符,只有在需要判断实例属性时才会用到hasOwnproperty,这样做可以避免很多bug。
格式化
一、基本格式化
1.变量和函数, 都用小驼峰式命名,变量用名词作前缀,函数用动词作前缀。
2.禁止使用特殊值underfined,可以有效地确保只在一种情况下typeof才会返回“underfined”
二、注释
1.使用注释的原则 当代码不够清晰时添加注释,而当代码很明了时不应当添加注释当代码不够清晰时添加注释,而当代码很明了时不应当添加注释
2.文档注释 开源项目中,强烈推荐用文档生成工具来生成文档注释,比如YUIDoc或JSDoc Toolkit。 在Google内部的很多开源项目JSDoc Toolkit的应用非常广泛,这两者的区别在于,YUIDoc可以同时支持文档注释中的HTML和Markdown格式,而JSDoc Toolkit 只支持HTML
三 语句和表达式
1.for循环
尽量用条件语句代替for循环中的continue,更加容易理解且不容易出错
示例代码
// 不好的写法
var values = [0, 1, 2, 3, 4, 5, 6],
i,len
for (i = 0, len = values.length; i < len; i++) {
if (i === 2 ) {
// 跳过本次循环
continue
}
console.log('第' + i + '次循环')
}
// 好的写法
var values = [0, 1, 2, 3, 4, 5, 6],
i,len
for (i = 0, len = values.length; i < len; i++) {
if (i !== 2 ) {
console.log('第' + i + '次循环')
}
}
复制代码
2.for-in循环
for-in不仅遍历对象的实例属性,同样还会遍历从原型继承来的属性。因此,当遍历自定义对象的属性时,for-in遍历对象会遍历从原型继承来的属性,建议使用hasOwnProperty()方法来为for-in循环过滤出实例的属性
示例代码
// 好的写法
var prop
for (prop in object) {
if (object.hasOwnProperty(prop)) {
console.log('Property name is' + prop)
console.log('Property value is' + object[prop])
}
}
复制代码
我推荐总是在for-in循环中使用hasOwnProperty(), 除非你想查找原型链,这时应当补充注释,比如:
// 好的写法
var prop
for (prop in object) { // 包含对原型链的遍历
console.log('Property name is' + prop)
console.log('Property value is' + object[prop])
}
复制代码
for-in循环是用来遍历对象的,禁止用来遍历数数组成员
示例代码
// 不好的写法
var values = [1, 2, 3],
i
for (i in values) {
console.log('Property name is' + i) // 0, 1, 2
console.log('Property value is' + values[i]) // 1, 2, 3
}
复制代码
四、变量、函数、运算符
1.变量声明
将局部变量的定义作为函数内第一条语句;所有的var语句合并为一个语句,每个变量的初始化独占一行。赋值运算符应当对齐。对于那些没有初始值的变量来说,它们应当出现在var语句的尾部。
示例代码
// 好的写法
function doSomething () {
// 局部遍历的定义
var value = 10,
result = value + 10,
i,
len
for (i = 0, len = items.length; i < len; i++) {
doOtherSomething(items[i])
}
}
复制代码
- 严格模式
use strict 不仅适用于全局,也适用于局部,但是最好不要在全局作用域中使用“use strict”模式
示例代码
// 不好的写法 全局的严格模式
'use strict'
function doSomething () {
// 一些代码
}
// 好的写法
(function () {
'use strict'
function doSomething () {
// 一些代码
}
function doSomethingElse () {
// 一些代码
}
})
复制代码
3.运算符
由于JavaScript具有强制类型转换机制的缘故,我们推荐不要使用==和!=,而是应当使用===和!==.
示例代码
// 不好的写法 字符串会被转为数字,然后再进行比较
console.log(5 == '5') // true
// 好的写法
console.log(5 === '5') // false
复制代码
4.函数
eval()
通用原则:严禁使用function,并且只在别无他法时使用eval()
总结
that's all, 以上就是我目前所有的对第一部分编程风格的理解以及应用。觉得对你开发有帮助的可以点赞收藏一波,如果我哪里写错了,希望能指点出来。如果你有更好的想法或者建议,可以提出来在下方评论区与我交流。大家一起进步,共同成长。感谢[鞠躬]。
一起交流
个人的微信公众号,付出的前端路,订阅微信公众号yhzg_gz(点击复制,在微信中添加公众号粘贴即可)
ps: 提高自己,常与异性交朋友