分析 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 相关文章推荐
JS中动态添加事件(绑定事件)的代码
Jan 09 Javascript
js作用域及作用域链概念理解及使用
Apr 15 Javascript
jQuery常用操作方法及常用函数总结
Jun 19 Javascript
jQuery实现根据滚动条位置加载相应内容功能
Jul 18 Javascript
AngularJS路由切换实现方法分析
Mar 17 Javascript
AngularJS中table表格基本操作示例
Oct 10 Javascript
ES6中javascript实现函数绑定及类的事件绑定功能详解
Nov 08 Javascript
ionic3实战教程之随机布局瀑布流的实现方法
Dec 28 Javascript
vue+echarts实现动态绘制图表及异步加载数据的方法
Oct 17 Javascript
JS实现数组去重及数组内对象去重功能示例
Feb 02 Javascript
React Native中ScrollView组件轮播图与ListView渲染列表组件用法实例分析
Jan 06 Javascript
微信小程序实现发微博功能的示例代码
Jun 24 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 mkdir()定义和用法
2009/01/14 PHP
PHP多个版本的分析解释
2011/07/21 PHP
国外PHP程序员的13个好习惯小结
2012/02/20 PHP
不使用php api函数实现数组的交换排序示例
2014/04/13 PHP
用Laravel轻松处理千万级数据的方法实现
2020/12/25 PHP
由JavaScript中call()方法引发的对面向对象继承机制call的思考
2011/09/12 Javascript
Extjs 3.3切换tab隐藏相应工具栏出现空白解决
2013/04/02 Javascript
jquery实现图片左右间隔滚动特效(可自动播放)
2013/05/08 Javascript
js传中文参数controller里获取参数乱码问题解决方法
2014/01/03 Javascript
微信WeixinJSBridge API使用实例
2015/05/25 Javascript
详细总结Javascript中的焦点管理
2016/09/17 Javascript
JavaScript中闭包的详解
2017/04/01 Javascript
Node.js对MongoDB数据库实现模糊查询的方法
2017/05/03 Javascript
canvas绘制爱心的几种方法总结(推荐)
2017/10/31 Javascript
Vue组件通信的四种方式汇总
2018/02/08 Javascript
JQuery扩展对象方法操作示例
2018/08/21 jQuery
JS把字符串格式的时间转换成几秒前、几分钟前、几小时前、几天前等格式
2019/07/10 Javascript
[45:59]完美世界DOTA2联赛PWL S2 FTD vs GXR 第二场 11.22
2020/11/24 DOTA
理解python多线程(python多线程简明教程)
2014/06/09 Python
Python中__new__与__init__方法的区别详解
2015/05/04 Python
python+selenium实现京东自动登录及秒杀功能
2017/11/18 Python
tensorflow 使用flags定义命令行参数的方法
2018/04/23 Python
pytorch + visdom 处理简单分类问题的示例
2018/06/04 Python
Python 经典面试题 21 道【不可错过】
2018/09/21 Python
python global关键字的用法详解
2019/09/05 Python
PyQt5+python3+pycharm开发环境配置教程
2020/03/24 Python
Xadmin+rules实现多选行权限方式(级联效果)
2020/04/07 Python
pycharm第三方库安装失败的问题及解决经验分享
2020/05/09 Python
Python实现淘宝秒杀功能的示例代码
2021/01/19 Python
一款利用css3的鼠标经过动画显示详情特效的实例教程
2014/12/29 HTML / CSS
学生自我鉴定范文
2013/10/04 职场文书
解决Pytorch修改预训练模型时遇到key不匹配的情况
2021/06/05 Python
JavaScript中document.activeELement焦点元素介绍
2021/11/27 Javascript
java项目构建Gradle的使用教程
2022/03/24 Java/Android
vue特效之翻牌动画
2022/04/20 Vue.js
Python matplotlib 利用随机函数生成变化图形
2022/04/26 Python