首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》第2章 字符串、正则表达式和数组

关灯直达底部

所有JavaScript程序都与字符串操作紧密相连。例如,许多应用程序利用Ajax从服务器获取字符串,将这些字符串转换成更易用的JavaScript对象,然后从数据中生成HTML字符串。一个典型的程序需要处理若干这样的任务:合并、分解、重新排列、搜索、遍历,以及其他方法处理字符串。

在JavaScript中,正则表达式是必不可少的,它的重要性远超过琐碎的字符串处理。提高正则表达式效率是很多开发者最易忽视的问题之一。使正则表达式更快地找到匹配,以及在非匹配位置上花费更少时间是开发者必须重视的问题之一。

密集的字符串操作和粗浅地编写正则表达式是造成JavaScript程序性能问题的主要原因,本章的建议可帮助读者避免这些常见问题。同时,由于数组是所有数据序列中运算速度最快的一种类型,且JavaScript提供了大量的数组操作方法,这些因素都值得我们去认真研究数组的内部工作机制和应用技巧。

建议34:字符串是非值操作

在字符串的复制和传递过程中,JavaScript解释器以引用方式来实现对字符串的操作。将字符串数据存储到堆区,然后把字符串的引用地址存储在字符串变量中。同时为了避免错误操作,JavaScript解释器强制约定字符串在堆区存储的数据是不可变的。这相当于设置字符串在堆区存储的数据为“只读”内容。因此,我们会发现没有一种JavaScript语法、方法或属性可以改变字符串中的原字符。

当进行字符串的复制和传递时,只是在栈区复制和传递字符串的引用地址,这种模拟使用引用的方法进行操作加快了内存的计算速度,不必把所有字符串都读取到栈区进行操作,这样节省了大量时间,提高了运行效率,如图2.1所示。

图 2.1 引用的字符串

例如,把变量a中的字符串复制给变量b,那么在b中修改字符串内容,不会影响到a中包含的内容,字符串的复制和传递操作像是为字符串建立了独立的副本。


var a="javascript";

var b=a;

b=b.toUpperCase;

alert(a);

alert(b);


在上面代码中,最终变量a和b的值是不同的,虽然它们都引用同一个字符串。JavaScript对于字符串的复制和传递仅是简单地采用引用的方法,操作对象为堆区字符串的地址,即复制和传递地址。但是,一旦编辑字符串本身的值,JavaScript就会把堆区的字符串读取到栈区进行独立操作。

操作完毕,要把结果赋值给原变量,JavaScript需要再次把字符串数据写回堆区,但没有覆盖原值所在的区域,而是新开辟一个区域进行存储,并把新空间的地址传递给栈区的变量进行存储,也就是说,在堆区新建一个副本。如果不把结果赋值给变量,就待在栈区等待JavaScript垃圾回收,而原来变量的值并没有改变。所以,在上面代码中,修改变量b的字符串后,还要把结果字符串赋值给变量b。用示意图进行演示,如图2.2所示。

图 2.2 JavaScript对于字符串的操作过程演示

因此,在操作字符串时,读者应该注意以下问题:

❑字符串的复制(即赋值)、传递(参数传递)仅是对字符串的引用进行操作,而不是对字符串本身的值进行操作。

❑修改字符串的值,需要使用值的方法进行操作,而不用修改对字符串的引用。

❑修改字符串的值,不是在堆区原值本身上进行修改,而是通过副本进行修改。

❑修改的字符串副本与原值没有任何联系,如果不把修改值复制给原值变量,则不会对原值产生影响。

❑当把修改的字符串复制给原值变量时,会重新建立一个新的引用,并把修改值存储到堆区新的位置。

❑原值引用的区域,如果还被其他变量引用,则继续保留,否则会被JavaScript回收程序回收。