javascript加号"+"的二义性说明


Posted in Javascript onMarch 04, 2013

单个的加号作为运算符在 JavaScript 中有三种作用。它可以表示字符串连接,例如:

var str = 'hello ' + 'world!';

或表示数字取正值的一元运算符,例如:

var n = 10;  
var n2 = +n;

或表示数值表达式的求和运算,例如:

var n = 100;  
var nn2 = n + 1; 
 

三种表示法里,字符串连接与数字求和是容易出现二义性的。因为 JavaScript 中对这两种运算的处理将依赖于数据类型,而无法从运算符上进行判读。我们单独地看一个表达式:

aa = a + b;

是根本无法知道它真实的含义是在求和,亦或是在做字符串连接。这在 JavaScript 引擎做语法分析时,也是无法确知的。

加号"+"带来的主要问题与另一条规则有关。这条规则是"如果表达式中存在字符串,则优先按字符串连接进行运算"。例如:

var v1 = '123';  
var v2 = 456;  //显示结果值为字符串'123456'  
alert( v1 + v2 );

这会在一些宿主中出现问题。例如浏览器中,由于 DOM 模型的许多值看起来是数字,但实际上却是字符串。因此试图做"和"运算,却变成了"字符串连接"运算。下面的例子说明了这个问题:

<img id="testPic" style="border: 1 solid red"> 
 

我们看到这个 id 为 testPic 的 IMG 元素(element)有一个宽度为 1 的边框--省略了默认的单位 px(pixel,像素点)。但是如果你试图用下面的代码来加宽它的边框,就会导致错误(一些浏览器忽略该值,另一些则弹出异常,还有一些浏览器则可能崩溃):

var el = document.getElementById('testPic');  
el.style.borderWidth += 10; 
 

因为事实上在 DOM 模型里,borderWidth 是有单位的字符串值,因此这里的值会是"1px"。JavaScript 本身并不会出错,它会完成类似下面的运算,并将值赋给 borderWidth:

el.style.borderWidth = '1px' + 10;  
//值为 '1px10'

这时,浏览器的 DOM 模型无法解释"1px10"的含义,因此出错了。当你再次读borderWidth 值时,它将仍是值 1px。那么,怎么证明上述的运算过程呢?下面的代码将表明 JavaScript 运算的结果是 1px10,但赋值到 borderWidth 时,是由于 DOM 忽略掉这个错误的值,因此 borderWidth 没有发生实际的修改:

alert( el.style.borderWidth = '1px' + 10 );//值为 '1px10'

这个问题追其根源,一方面在于我们允许了省略单位的样式表写法,另一方面也在于脚本引擎不能根据运算符来确定这里的操作是数值运算还是字符串连接。

后来 W3C 推动 XHTML 规范,试图从第一个方面来避免这个问题,但对开发界的影响仍旧有限。因此,在浏览器的开发商提供的手册中,都会尽可能地写明每一个属性的数据类型,以避免开发人员写出上面这样的代码。在这种情况下,最正确的写法是:

var el = document.getElementById('testPic');  
// 1.取原有的单位  
var value = parseInt(el.style.borderWidth);  
var unit = el.style.borderWidth.substr(value.toString().length);  
// 2.运算结果并附加单位  
el.style.borderWidth = value + 10 + unit;  //如果你确知属性采用了默认单位 px,并试图仍然省略单位值,  
//那么你可以用下面这种方法(我并不推荐这样):  
// el.style.borderWidth = parseInt(el.style.borderWidth) + 10;
Javascript 相关文章推荐
firefox 和 ie 事件处理的细节,研究,再研究 书写同时兼容ie和ff的事件处理代码
Apr 12 Javascript
在一个js文件里远程调用jquery.js会在ie8下的一个奇怪问题
Nov 28 Javascript
js代码实现的加入收藏效果并兼容主流浏览器
Jun 23 Javascript
json实现前后台的相互传值详解
Jan 05 Javascript
javascript实现全角半角检测的方法
Jul 23 Javascript
不同js异步函数同步的实现方法
May 28 Javascript
Angular和百度地图的结合实例代码
Oct 19 Javascript
BootStrap table使用方法分析
Nov 08 Javascript
angular-ui-sortable实现可拖拽排序列表
Dec 28 Javascript
Canvas实现微信红包照片效果
Aug 21 Javascript
javascript Canvas动态粒子连线
Jan 01 Javascript
最新最全的手机号验证正则表达式
Feb 24 Javascript
js给dropdownlist添加选项的小例子
Mar 04 #Javascript
jQuery侧边栏随窗口滚动实现方法
Mar 04 #Javascript
利用js实现选项卡的特别效果的实例
Mar 03 #Javascript
DWZ刷新dialog解决方法
Mar 03 #Javascript
js 控制下拉菜单刷新的方法
Mar 03 #Javascript
可在线编辑网页文字效果代码(单击)
Mar 02 #Javascript
javascript重复绑定事件造成的后果说明
Mar 02 #Javascript
You might like
ThinkPHP模板之变量输出、自定义函数与判断语句用法
2014/11/01 PHP
PHP环形链表实现方法示例
2017/09/15 PHP
Javascript中eval函数的使用方法与示例
2007/04/09 Javascript
分析 JavaScript 中令人困惑的变量赋值
2007/08/13 Javascript
学习JS面向对象成果 借国庆发布个最新作品与大家交流
2009/10/03 Javascript
JQuery 选项卡效果(JS与HTML的分离)
2010/04/01 Javascript
可以将word转成html的js代码
2010/04/11 Javascript
《JavaScript高级程序设计》阅读笔记(三) ECMAScript中的引用类型
2012/02/27 Javascript
Package.js  现代化的JavaScript项目make工具
2012/05/23 Javascript
javascript在网页中实现读取剪贴板粘贴截图功能
2014/06/07 Javascript
超级简单实现JavaScript MVC 样式框架
2015/03/24 Javascript
jquery实现定时自动轮播特效
2015/12/10 Javascript
js实现页面刷新滚动条位置不变
2016/11/27 Javascript
详谈js遍历集合(Array,Map,Set)
2017/04/06 Javascript
react native带索引的城市列表组件的实例代码
2017/08/08 Javascript
node.js实现微信JS-API封装接口的示例代码
2017/09/06 Javascript
VUE+Element UI实现简单的表格行内编辑效果的示例的代码
2018/10/31 Javascript
解决Angularjs异步操作后台请求用$q.all排列先后顺序问题
2019/11/29 Javascript
vue-cli3.0实现一个多页面应用的历奇经历记录总结
2020/03/16 Javascript
Python模块搜索概念介绍及模块安装方法介绍
2015/06/03 Python
python画柱状图--不同颜色并显示数值的方法
2018/12/13 Python
Python读取指定日期邮件的实例
2019/02/01 Python
python ctypes库2_指定参数类型和返回类型详解
2019/11/19 Python
vscode写python时的代码错误提醒和自动格式化的方法
2020/05/07 Python
微软加拿大官方网站:Microsoft Canada
2019/04/28 全球购物
十佳大学生事迹材料
2014/01/29 职场文书
大学运动会入场词
2014/02/22 职场文书
作文批改评语
2014/12/25 职场文书
邀请函样本
2015/02/02 职场文书
简历自我评价优缺点
2015/03/11 职场文书
催款函范文
2015/06/24 职场文书
2016年过年放假安排通知
2015/08/18 职场文书
五年级作文之想象作文
2019/10/30 职场文书
Redis可视化客户端小结
2021/06/10 Redis
sql注入教程之类型以及提交注入
2021/08/02 MySQL
解决 redis 无法远程连接
2022/05/15 Redis