《JavaScript编程精解》简明读书心得-下

这是《JavaScript编程精解》简明读书心得 的下半部分。这本书的下半节有两章客户端JavaScript内容。由于这部分内容比较繁杂,而概念比较简单,而且很多工作都可以用JQuery来完成,所以我读这本书的时候,这部分就直接浏览了一遍。因此这下半部分只有两节内容,模块化和正则表达式。

模块化的JavaScript

比起C#中可以轻松地在类中声明私有字段、继承类、封装接口、生成命名空间,JavaScript简直太可怜了——它不提供任何模块化的原生支持。事实上,我们只能通过一些JavaScript的特性来“模拟”出模块的特点。模块的特点是“封装”,即模块的使用者可以对模块内的细节一无所知,其目的就是希望当其他模块发生变化时,自身可以不变,增强了代码的复用性。在JavaScript中,这是通过以下两个特性来完成的:

  • 1、函数内部的局部变量对外不可见(闭包) 
  • 2、对象的字段只能通过对象调用(这好像又是废话)

用函数封装变量,使得不需要出现在全局作用域的变量不出现在全局作用域。比如我希望获得一个计算圆柱体和圆锥体体积的函数,也许你会这样做:

var PI = 3.1415926;
var circleArea = function(theCircle) { return theCircle.radius*theCircle.radius*PI; }
var cylinderVolume = function(theCylinder) {  return circleArea(theCylinder.circle)*theCylinder.height; }
var taperedVolume = function(theTapered) {  return circleArea(theTapered.circle)*theTapered.height/3; }

浏览器解释完这4条语句之后,你获得了想要的两个函数cylinderVolume和taperedVolume,但是请注意,你也获得了PI和circleArea,这并不是你想做的,换句话说,全局作用域被PI和circleArea“污染”了。也许前面一个脚本文件里已经定义了另一个PI=1.414,或者只有你掌握了计算圆面积的方法circleArea,你不想其他人也能方便地使用(话说回来既然用了JavaScript而不是什么COM技术,不管如何扭曲代码你的秘密总会被解析出来的,因为源码就是公开的嘛),你都应该将这两个家伙封装起来。下面的实现可能会比较好:

function createFunction(){
    var PI = 3.1415926;
    var circleArea = function(theCircle) { …… }
    var cylinderVolume = function(theCylinder) {  …… }
    var taperedVolume = function(theTapered) {  …… }
    window.cylinderVolume = cylinderVolume;
    window.taperedVolume = taperedVolume;
}
createFunction();

window是浏览器窗口对象,所有的“全局变量”都是window的属性。这个函数运行之后,window对象只获得了两个计算圆柱体和圆锥体体积的函数,在后面代码里可以方便地调用这两个函数。你看,PI和circleArea并没有随着createFunction定义的结束而被释放,它们被保存到一个由浏览器维护的地方,只要调用taperedVolume函数,就会使用到它们,这就是“闭包”的特性。

如果仔细考虑,上面的实现还有问题,那就是污染了变量createFunction,那么也许使用匿名函数会更好。下面是最好的实现:

function(){
    var PI = 3.1415926;
    var circleArea = function(theCircle) { …… }
    var cylinderVolume = function(theCylinder) {  …… }
    var taperedVolume = function(theTapered) {  …… }
    window.cylinderVolume = cylinderVolume;
    window.taperedVolume = taperedVolume;
}();

这样,利用函数体内局部变量是不可达的这一特点,就完成了对模块的封装,cylinderVolume和taperedVolume就是对外交流的接口。 也许你会说,直接把PI值和计算圆面积的逻辑写到计算体积的函数里不就行了?但是,当函数的规模足够大的时候,你一定不会想那么做的。

至于利用对象的属性封装字段则很简单了,因为对象(名值对)本身就是用来模拟面向对象语言中的“对象”的,通过对象名来访问对象内部的属性,这是理所当然的。

正则表达式

正则表达式提供了非常灵活的字符串匹配方法,可想而知在表单验证之类的领域有着很强的应用。之前看犀牛书的时候一带而过,这次看书虽然不指望完全掌握,但我总想还是稍微整理一下吧。

下面是正则表达式的一个简单的应用,返回1表示能够在索引(从0开始)为1的地方找到第一个匹配el。

var text = “hello”;
text.search(/el/);//->1

正则表达式以一个斜杠开头,以一个斜杠结尾,中间的内容为匹配的内容。正则表达式可以通过通配符匹配字符串:

“1a 2 3d”.search(/\s\d\s/); //->3 匹配到a后面的“空格2空格”

还有一些常用通配符:

通配符 释意
\d  任意数字
\w  任意单词
\s  任意空字符:制表符、换行符、空格符
\b   单词边界:标点符号,空格,字符串开头和结束
 .  任意不是换行符的字符

正则表达式中,中括号"["和"]"之间的部分表示符合任意字符的匹配,星号和加号分别表示可以重复任意次数和重复至少一次:

“abccxa”.search(/[xyz]/); //->4
“abccxa”.search(/c*xa/); //->4

字符串除了search方法,还有replace方法用以替换掉被匹配的字符串,还有match方法检测是否找到匹配。

写在最后的话

花了两天看完这本小书,有一些收获都基本写到了这两篇博文里面。也许有人会问:既然JavaScript有这么多缺点,OOP是模拟出来的,事件机制也是模拟出来的,甚至调用函数的时候连参数都不检查,那为什么还要学习它呢?我有这样的答案:首先,JavaScript的本质是简单的,在这种简单的基础之上构造抽象问题的思想却是值得学习的(当突然理解“闭包”的时候,我觉得设计者的思路真是妙绝了);其次,JavaScript作为一种“立竿见影”的语言,能帮助我做想做的事情:开发游戏——WebGL官方demo里面有个赛车游戏,简直太COOL了。

posted @ 2012-11-20 15:10  一叶斋主人  阅读(1963)  评论(4编辑  收藏  举报