分析 JavaScript 中令人困惑的变量赋值

本文深入探讨JavaScript中变量存储方式的奥秘,揭示字符串与数组赋值的区别,以及这些特性如何影响程序性能。
Javascript是一门弱类型的语言,声明变量不需要声明其类型,var x 就可以等于任何类型的值。 
比如: 

var str = "string...."; 
var arr = ["this","is","array"]; 
var obj = {name:"caizhongqi",age:26,sex:"male"}; 
这些都是正确的,这似乎非常简单方便,但是这种方便也会带来一些令人难于捉摸的意外,看看下面的例子(例1): 

<script> var x = "this is string"; 
 var y = x; 
 x="ni hao"; 
 alert(y) 
</script> 

你可能一下子知道alert出来的就是“this is string”,没错,但对于用Java语言的程序员来说,var y=x 应该是把x在存储器中的地址(指针)赋给y变量才对,因此他们觉得应该alert出“ni hao”才会更符合Java语言的习惯,但JavaScript语言不是这样,字符串的赋值是直接量操作,直接把数据copy给y的存储空间。 

再看看下面的例子(例2): 

<script> 
var x = ["hello"]  // 这是一个数组,只有一个元素,并且该元素为字符串类型 
var y = x; 
x[0] = "world"; 
alert(y[0]); 
</script> 

如果你还以为alert出来的是“hello”,那就错了。当 var y = x 时,x不是已经把它的数组给了y吗?但事实上却不是这样, 当 var y = x 时,x传的是它在存储器中的地址(指针)!x[0]="world" 修改了在原存储位置上的数据,因此alert(y[0])就是拿x的新值出来alert。混乱了吧?怎么一会儿是直接量一会儿是引用量呢? 
不急,下面的例子将更加混乱(例3): 

<script> 
var x = ["hello"]  // 这是一个数组,只有一个元素,并且该元素为字符串类型 
var y = x; 
x = ["ni","hao"];  // x 将变成一个新的数组了。 
alert(y[0]); 
</script> 

你的眼睛告诉你,alert出来的是“hello”!这让人捉摸不透古灵精怪的JavaScript! 
 
其实问题出在对x的第二次赋值 x = ["ni","hao"] 上,我们看看变量在存储器上变化以及JavaScript在对待字符串类型与对象类型的不同: 

我们观察下面两种情况: 
var x = "this is string..."; 
var y = ["this","is","string"]; 

x与y不同之处在于类型,javascript的解析器把字符串直接赋值(其实就是copy)给x(直接量),却把数组的指针赋给y(引用量),这一切都是瞬间全自动的!结合下面的图,可能会更好地理解: 



图中p1、p2...就是变量的指针,上面的 var y 中的y存的就是Object类型变量的指针p1(假设),而x存放的就是字符串本身。再分析一下例3,执行 var x = ["hello"] 时,解析器就在内存上开辟一块存储空间放这个数组,而 x 就拿到了这个空间的地址(指针),再执行 x = ["ni","hao"] 时,解析器又新开辟一块存储空间放这个新数组,而x就是这个新存储空间的指针,这也就是说,JavaScript 里变量的重定义(或重新赋值)将会新开辟一块存储空间,而没有销毁原来的空间;回过头来再看例2,x[0] = "world",这句没有给x新定义值,没有新开辟存储空间,只是修改了它存储空间里面的数据,因此例2最后alert出来的就是“world”;例1是字符串赋值,全过程是直接量操作。 

从上面的分析可以看出,JavaScript 的变量可以存储直接量也可以存储指针,这是没办法被人工干扰的,因此,在日常的编码中,就需要注意这些问题,比如大字符串连接,循环里面赋值等细节就能直接影响到程序的执行效率。 

看看两个例子: 

var _tmpStr=""; 
var str = "this is big string..."; 
for (i=0; i<100; i++){ 
    _tmpStr += a; 

a = _tmpStr; 

因为是字符串操作,使用直接量,每次循环都要操作大字符串,非常笨重,效率低下。如果改用引用量操作,即通过数组: 

var str = "this is big string..."; 
var _tmpArray = []; 
for (i=0; i<100; i++){ 
    _tmpArray[i]=str; 

str = _tmpArray.join(""); 

做个测试,假如有个100k的字符串,用直接量连接操作,我的机器上需要约2600毫秒,如果用数组连接,则需要150毫秒,效率相差十几倍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值