第四章 变量,函数和运算符
JS编程的本质是编写一个个函数来完成任务。在函数内部,变量和运算符可以通过移动操作字节来使某个事件发生。通过书写格式化来减少复杂度,增强可读性显得十分重要。
4.1 变量声明
变量声明是通过 var 语句来完成的。变量声明不管是在何处声明,所有的 var 语句都会提前到代码顶部执行。
变量声明提升意味着:在函数任何地方定义变量和在函数顶部定义变量是完全一样的。所以有了一种风格就是将所有变量声明集中在函数顶部而不是散落在代码各个地方进行声明。
由而产生了一种单一的 var 风格声明。
function doSomeThing (item){
var i, len, value = 10, result = value+10 ;
for(i=10, len=item.length; i
do(item[i]);
}
}
尼古拉斯推荐 合并var声明,可以清晰看到所有变量名 以及缩小代码量。并且建议每个变量都独占一行,统一缩进。
function doSomeThing (item){
var i,
len,
value = 10,
result = value+10 ;
for(i=10, len=item.length; i
do(item[i]);
}
}
记得有位牛人博客曾经指出一些较为牛逼的建议,其中一条就是攻击单一 var 声明。 认为比如 for 循环中的() 中 i 就应该在使用的时候声明逻辑才可以更清晰,
而很多代码量是很大的,在前面声明之后有可能会忘了一些变量名的本意。
4.2 函数声明
和变量声明一样,函数声明也会被JS引擎提升。所以在函数声明之前与函数声明之后调用函数都是一样的。
推荐总是先声明函数,再使用函数。Crockford规范还推荐在函数内部的函数应当紧跟着变量声明之后声明。
function doSomeThing (item){
var i,
len,
value = 10,
result = value+10 ;
function do(item){
...
}
for(i=10, len=item.length; i
do(item[i]);
}
}
当函数在声明之前使用的话,JSLint和JSHint都会给出警告。
函数声明不应当出现在语句块之内,会有兼容方面的问题导致各个浏览器解析不一致。
if(condition){
function doThing(){
...
}
} else {
function doThing(){
...
}
}
该种场景目前属于ECMA的灰色地带,应当避免。也是google规范中禁止的。
4.3 函数调用隔离
一般情况下函数调用的写法是,在函数名和左括号之间没有空格,为了将他与块语句区分开来。
// good
doThing(item);
// not good
doThing (item);
//用来作比较的语句应当加入空格
while (condition){
// code
}
对于jQuery的风格就是 在内部参数的前后加入空格,是个代码比较透气,增强可读性和读代码的舒适度。
doThing( item );
当然不是所有的情况都应当如此,对于jQuery其他情况如下
doThing(function() {});
doThing({ item: item });
doThing([ item ]);
doThing("Hi !");
4.4 立即调用的函数
可能省略圆括号其效果是一样的,但是会带来可读性上的降低。
// 好的写法
var value = (function(){
//函数体
return {
message: "Hi !"
}
}());
// 不好的写法
var value = function(){
//函数体
return {
message: "Hi !"
}
}();
4.5 严格模式
ECMA5 中引入的严格模式,可以通过这种方式来谨慎的解析 JS 代码,以减少错误。
"use strict";
遵循ECMA5的浏览器会将其识别为指令,使用严格模式进行解析代码,而不支持的浏览器只会当做普通代码块。
不推荐将严格模式使用在全局之中,可能产生的问题就是,如果我有11个文件需要做合并处理,那么当有一个文件是使用的全局的严格模式,那么合并后的文件整体就会使用严格模式,也行我其余的10个文件不遵循严格模式呢?
function sayHi(){
"use strict";
return "Hi !";
}
在JSLint与JSHint中,也会对出现在函数体之外的严格迷模式声明发出警告。当然,推荐使用严格模式。
4.6 相等
JS具有强制类型转换的机制,所以判断相等的操作还是很微妙的
5 == "5" // true
25 == "0x19" // true
2 == true // false
对于对象,则会首先调用对象的 valueOf() 方法,得到原始类型值比较,如果没有定义则调用 toString()。
var object ={
toString: function(){
return "0x19";
}
}
object == 25; // true
由于强类型转换的情况,所以需要使用 === 和 !== 来处理比较的情况。而不推荐使用 == 和 != 。
4.6.1 eval()
eval() , Function构造函数 , setTimeout() , setInterval() 都是可以讲一段字符串作为代码来执行。
执行的代码可能产生变量名污染和安全性的问题。
当然也不完全封杀 eval 因为对于一些特殊情况还是需要使用 eval 来处理代码的,一般只是用在没有别的方法来处理的时候才使用。
4.6.2 原始包装类型
对于 字符串构造函数, 函数构造函数等,一律使用字面量形式,不适用构造函数形式。对于正则表达式,在有些情况下比如动态创建正则的时候还是需要使用的。
第二部分 编程实践
构建软件设计的方法有两种:一种是把软件做的很简单以至于明显找不到缺陷,另一种是把它做的很复杂以至于找不到明显的缺陷。
- C.A.R.Hoare 80年图灵奖获得者
上一部分编程风格只关心代码的呈现,而这部分编程实践则关心编码的结果。引导开发者以某种方式进行编码,设计模式是编程实现的组成部分,专用于解决和软件组织的相关特定问题。
第五章 UI层的松散耦合
在实际的场景中,css 与 js 应该为兄弟关系,而不是依赖关系。
需要增加分层的合理性和消除依赖。
5.1 什么是松耦合
很多的设计模式就是为了解决紧耦合的问题。如果2个组件耦合太紧密,就说明一个组件和另一个组件直接相关。
比如有一个名为 error 的className,贯穿整个站点。有一天觉得他命名不合理需要更改的时候,有可能我们需要做更改上百个使用到它的组件,也有可能只需要更改一个组件。
你能做到只修改一个组件而不是说修改 N 个组件,那么就做到了松耦合。对于一些大型系统来说这是至关重要的。
5.2 将 JS 从 CSS中抽离
IE 8 中可以使用 css 表达式(CSS expression)。允许将JS代码直接插到 css 中。
.box{
width: expression(document.body.offsetWidth + "px");
}
这是绝对不建议这么做的。 当然 IE 9 已经不再支持了。
5.3 将 CSS 从 JS 中抽离
两门语言相互协作的很不错,通过 JS 控制样式最流行的一种做法就是 直接修改 DOM 的 style 属性
element.style.color = "#FFF";
element.style.display= "block"
有些还使用 cssText 来进行对 style 的赋值。
以上是不建议 在各个方面都不如以下方式:
将需要改变的样式放入新的 css 选择器中,需要更新样式的时候只需要加入或者替换该 classname即可。
JS不应当直接操作样式,以便与 css保持松耦合。
有一种情况是可以的,就是将页面元素重新定位的时候,比如一些动画变幻等效果。
5.4 将 JS 从 HTML 中分离
在学习 JS 之初,经常将事件绑定放入页面的 HTML 中。
首先,是需要 doSomething 函数已存在,就需要将 JS 代码放置在 HTML 之前。
在次,对于可维护性方面有很大的弊端。
所以应当使用事件处理程序的绑定机制。addEventListener removeEventListener。当然一些JS库将其封装的更好。
5.5 将 HTML 从 JS 中抽离
正如将 JS 从 HTML 中抽离一样,最好也将 HTML 从 JS 中抽离。因为在我们对文本或者页面结构进行调试的时候我们更希望直接面对的是 HTML 而不是一些 JS 语句动态的修改结构。
在 JS 中使用最多的情况就是给 innerHTML 赋值。
var div = document.getElementById("myDiv");
div.innerHTML = "abc
efg
";
将HTML嵌入JS中是非常不好的实践,原因有:
1.大大增加了跟踪文本和结构性问题的复杂度。
2.加大了代码的维护成本。
3.相对于只修改 HTML,当JS和HTML混淆在一起时,修改代码更容易引发其他问题。
将HTML从JS抽离
1.从服务器加载。将模板放置于原创服务器。使用Ajax方式加载模板文件。
2.简单的客户端模板。带有一些替换标签的片段,%s 然后通过函数将模板和数据结合。
3.复杂的客户端模板。目前一些较为健全的开源模板库,可以很好地帮助实现所需要的较为大的项目需求。