编写高质量JavaScript代码的重要性
从可维护性和成本而言:
从可维护性理解:举例:一个花费几个小时就写出的功能,如果代码质量低下,如果这段代码在将来出现问题,无论是针对个人还是团队,都将要花费写出这个功能数倍的时间去重新理解,这是得不偿失的,如果是高质量代码,在二次开发时,就能在短时间内理解。工程师都是趋向于开发新功能,而不是在一个难以理解的功能上花费大多数时间
从成本角度理解:花费更多时间在一个功能上意味着工程师将失去开发新功能的时间,这是对营收底线的损害
可维护性的代码意味着:
可读的
一致的
可预测的
看上去就像是同一个人写的
已记录
通过以下的方式可以达到可维护性的标准
最小全局变量(Minimizing globale)
避免创建隐式全局变量,使用const、let等控制变量的访问范围,现代js中这是轻易可实现的,框架和规范都避免了我们直接创建全局变量
一些隐式全局变量创建易踩坑点:
无声明关键字
function test(){
val = 1;// 全局变量
}
使用任务链进行部分var声明
function test(){
var a = b = 1;
}
// 等价于
function test(){
b = 1;
var a = b;// a = (b = 1);
}
访问全局对象
在浏览器中,全局对象可以通过window属性在任何地方访问,但是在其他环境下,这个方便的属性可能会被命名为其他,甚至没有,如果你需要在没有硬编码的window标识符下访问全局对象,你可以在任何层级的函数作用域中做如下操作
var golbal = (function (){
return this;
})()
这种方式可以随时获取全局对象,因为其在函数中被当作函数调用了,this总是指向全局对象
单var形式
一种在顶部使用一个var定义需要使用的变量的方式,好处在于方便变量初始化,方便查找,结构清晰,增加代码可读性
function func() {
var a = 1,
b = 2,
sum = a + b,
myobject = {},
i,
j;
// function body...
}
预解析(hoisting):var散布的问题
JavaScript中,你可以在函数的任何位置声明多个var语句,并且它们就好像是在函数顶部声明一样发挥作用,这种行为称为 hoisting(悬置/置顶解析/预解析)
hoisting带来的问题是我们会因为变量的声明位置误以为某些变量的优先级更高,但是实际上需要考虑hosting的影响,比如:
// 反例
myname = "global"; // 全局变量
function func() {
alert(myname); // "undefined"
var myname = "local";
alert(myname); // "local"
}
func();
它实际上等同于:
myname = "global"; // 全局变量
function func() {
var myname; // 等同于 -> var myname = undefined;
alert(myname); // "undefined"
myname = "local";
alert(myname); // "local"
}
func();
摘抄:为了完整,我们再提一提执行层面的稍微复杂点的东西。代码处理分两个阶段,第一阶段是变量,函数声明,以及正常格式的参数创建,这是一个解析和进入上下文 的阶段。第二个阶段是代码执行,函数表达式和不合格的标识符(为声明的变量)被创建。但是,出于实用的目的,我们就采用了”hoisting”这个概念, 这种ECMAScript标准中并未定义,通常用来描述行为。
for循环优化
对于常用的for循环,它的一般表现形式是这样的:
for(let i = 0; i < arr.length; i++){
// 做点什么
}
在循环期间,每执行一次循环,就会去获取一次长度,一般的数组而言并不会有太大的性能损耗,但是对于动态的DOM,我们在获取DOM的一些可迭代集合时,动态性+DOM操作(dom操作是昂贵的),会给性能方面带来不小负担,因此,对于for循环,可以这么优化:
for(let i = 0, max = arr.length; i < max; i++){
// 做点什么
}
for-in循环
for-in循环应该用在非数组的对象遍历中,使用for-in进行循环也被称为枚举
从技术上讲,for-in也可以枚举数组,但是这是不推荐的:
如果数组对象已被自定义的功能增强,就可能发生逻辑错误
在for-in中,属性列表的顺序(序列)是不能保证的
重要的hasOwnProperty()方法:
Object.prototype.xxx = propertyValue;这种形式可以在原型上添加属性,届时,所有的对象都可以访问这个方法,因为Object是所有对象的基类
这个方法可以根据传入属性检测对象上是否存在该属性,传入的参数为字符串。
根据这个特性,我们可以使用hasOwnProperty()方法来过滤掉原型上的属性