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


Posted in Javascript onAugust 13, 2007

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毫秒,效率相差十几倍。

好久没写这么长的文章了,花了我大半天的时间。

Javascript 相关文章推荐
[原创]用javascript实现检测指定目录是否存在的方法
Jan 12 Javascript
js利用Array.splice实现Array的insert/remove
Jan 13 Javascript
XMLHTTPRequest的属性和方法简介
Nov 23 Javascript
为jQuery添加Webkit的触摸的方法分享
Feb 02 Javascript
网页右下角弹出窗体实现代码
Jun 05 Javascript
jQuery实现连续动画效果实例分析
Oct 09 Javascript
JavaScript中日期的相关操作方法总结
Oct 24 Javascript
Ajax分页插件Pagination从前台jQuery到后端java总结
Jul 22 Javascript
Spring Boot+AngularJS+BootStrap实现进度条示例代码
Mar 02 Javascript
Angular实现可删除并计算总金额的购物车功能示例
Dec 26 Javascript
Es6 Generator函数详细解析
Feb 24 Javascript
js实现多个倒计时并行 js拼团倒计时
Feb 25 Javascript
IE/FireFox具备兼容性的拖动代码
Aug 13 #Javascript
JavaScript 编程引入命名空间的方法与代码
Aug 13 #Javascript
权威JavaScript 中的内存泄露模式
Aug 13 #Javascript
封装好的省市地区联动控件附下载
Aug 13 #Javascript
分享别人写的一个小型js框架
Aug 13 #Javascript
javascript下查找父节点的简单方法
Aug 13 #Javascript
根据地区不同显示时间的javascript代码
Aug 13 #Javascript
You might like
PHP中的日期处理方法集锦
2007/01/02 PHP
php 获取一个月第一天与最后一天的代码
2010/05/16 PHP
PHP cookie与session会话基本用法实例分析
2019/11/18 PHP
用js实现的抽象CSS圆角效果!!
2007/05/03 Javascript
两种WEB下的模态对话框 (asp.net或js的分别实现)
2009/12/02 Javascript
谷歌浏览器调试JavaScript小技巧
2014/12/29 Javascript
js实现从右向左缓缓浮出网页浮动层广告的方法
2015/05/09 Javascript
整理关于Bootstrap表单的慕课笔记
2017/03/29 Javascript
浅谈ES6 模板字符串的具体使用方法
2017/11/07 Javascript
Vue2.0设置全局样式(less/sass和css)
2017/11/18 Javascript
Angular2开发环境搭建教程之VS Code
2017/12/15 Javascript
jQuery+Cookie实现切换皮肤功能【附源码下载】
2018/03/25 jQuery
vuejs简单验证码功能完整示例
2019/01/08 Javascript
JS中数据结构与算法---排序算法(Sort Algorithm)实例详解
2019/06/17 Javascript
layui layer select 选择被遮挡的解决方法
2019/09/21 Javascript
vue输入节流,避免实时请求接口的实例代码
2019/10/30 Javascript
[02:23]1个至宝=115个英雄特效 最“绿”至宝拉比克“魔导师密钥”登场
2018/12/29 DOTA
Python存取XML的常见方法实例分析
2017/03/21 Python
python判断一个数是否能被另一个整数整除的实例
2018/12/12 Python
jupyter notebook oepncv 显示一张图像的实现
2020/04/24 Python
耐克美国官网:Nike.com
2016/08/01 全球购物
Aveda美国官网:天然护发产品、洗发水、护发素和沙龙
2016/12/09 全球购物
百丽国际旗下购物网站:优购
2017/02/28 全球购物
linux面试题参考答案(4)
2013/01/28 面试题
销售行政专员职责
2014/01/03 职场文书
大学毕业感言
2014/01/10 职场文书
诚信承诺书范文
2014/03/27 职场文书
倡议书格式范文
2014/04/14 职场文书
知识竞赛拉拉队口号
2014/06/16 职场文书
局机关干部群众路线个人对照检查材料思想汇报
2014/10/05 职场文书
先进工作者推荐材料
2014/12/23 职场文书
体育教师个人总结
2015/02/09 职场文书
施工安全员岗位职责
2015/04/11 职场文书
2015年三年级班主任工作总结
2015/05/21 职场文书
2015年社区重阳节活动总结
2015/07/30 职场文书
工厂无线对讲系统解决方案
2022/02/18 无线电