有趣的JavaScript隐式类型转换操作实例分析


Posted in Javascript onMay 02, 2020

本文实例讲述了JavaScript隐式类型转换操作。分享给大家供大家参考,具体如下:

JavaScript的数据类型是非常弱的(不然不会叫它做弱类型语言了)!在使用算术运算符时,运算符两边的数据类型可以是任意的,比如,一个字符串可以和数字相加。之所以不同的数据类型之间可以做运算,是因为JavaScript引擎在运算之前会悄悄的把他们进行了隐式类型转换的,如下是数值类型和布尔类型的相加:

3 + true; // 4

结果是一个数值型!如果是在C或者Java环境的话,上面的运算肯定会因为运算符两边的数据类型不一致而导致报错的!但是,在JavaScript中,只有少数情况下,错误类型才会导致出错,比如调用非函数,或者读取null或者undefined的属性时,如下:

"hello"(1); // error: not a function
null.x; // error: cannot read property 'x' of null

多数情况下,JavaScript都不会出错的,而是自动的进行相应的类型转换。比如-, *, /,和%等算术运算符都会把操作数转换成数字的,但是“+”号就有点不一样了,有些情况下,它是算术加号,有些情况下,是字符串连接符号,具体的要看它的操作数,如下:

2 + 3; // 5
"hello" + " world"; // "hello world"

但是,如果字符串和数字相加,会是怎样的结果呢?JavaScript会自动把数字转换成字符的,不管数字在前还是字符串在前,如下:

"2" + 3; // "23"
2 + "3"; // "23"

字符串和数字相加结果是字符串,字符串和数字相加结果是字符串,字符串和数字相加结果是字符串,重要的事情说三遍!!!!!!

此外,需要注意的是,“+”的运算方向是从左到右的,如下:

1 + 2 + "3"; // "33"

这与下面是等价的:

(1 + 2) + "3"; // "33"

相比之下,下面的结果是不一样的:

1 + "2" + 3; // "123"

但是,隐式类型转换,有时候,会隐藏一些错误的,比如,null会转换成0,undefined会转换成NaN。需要注意的是,NaN和NaN是不相等的(这是由于浮点数的精度决定的),如下:

var x = NaN;
x === NaN; // false

虽然,JavaScript提供了isNaN来检测某个值是否为NaN,但是,这也不太精确的,因为,在调用isNaN函数之前,本身就存在了一个隐式转换的过程,它会把那些原本不是NaN的值转换成NaN的,如下:

isNaN("foo"); // true
isNaN(undefined); // true
isNaN({}); // true
isNaN({ valueOf: "foo" }); // true

上面代码,我们使用isNaN来测试后,发现字符串,undefined,甚至对象,结果都返回真!!!但是,我们总不能说他们也是NaN吧?总而言之,得出的结论是:isNaN检测NaN并不可靠!!!

幸运的是,有一种可靠的并且准确的方法可以检测NaN。我们都知道,只有NaN是自己不等自己的,那么,我们就以使用不等于号(!==)来判断一个数是否等于自身,从而,可以检测到NaN了,如下:

var a = NaN;
a !== a; // true
var b = "foo";
b !== b; // false
var c = undefined;
c !== c; // false
var d = {};
d !== d; // false
var e = { valueOf: "foo" };
e !== e; // false

我们也可以把这种模式定义成一个函数,如下:

function isReallyNaN(x) {
  return x !== x;
}

OK,NaN的检测方法就是这么简单,我们下面继续讨论对象的隐式转换!

对象是可以转换成原始值的,最常见的方法就是把它转换成字符串,如下:

"the Math object: " + Math; // "the Math object: [object Math]"
"the JSON object: " + JSON; // "the JSON object: [object JSON]"

对象转换成字符串是调用了他的toSting函数的,你可以手动的调用它来检测一下:

Math.toString(); // "[object Math]"
JSON.toString(); // "[object JSON]"

类似的,对象也是可以转换成数字的,他是通过valueOf函数的,当然,你也是可以自定义这个valueOf函数的,如下:

"J" + { toString: function() { return "S"; } }; // "JS"
2 * { valueOf: function() { return 3; } }; // 6

如果,一个对象同时存在valueOf方法和toString方法,那么,valueOf方法总是会被优先调用的,如下:

var obj = {
  toString: function() {
    return "[object MyObject]";
  },
  valueOf: function() {
    return 17;
  }
};
"object: " + obj; // "object: 17"

但是,多数情况下,这都不是我们想要的,一般的,尽可能使valueOf和toString表示的值相同(尽管类型可以不同)。

最后一种强制类型转换,我们常常称之为“真值运算”,比如,if, ||, &&,他们的操作数不一定是布尔型的额。JavaScript会通过简单的转换规则,将一些非布尔类型的值转换成布尔型的。大多数的值都会转换成true,只有少数的是false,他们分别是:false, 0, -0, "", NaN, null, undefined,因为存在数字和字符串以及对象的值为false,所以,直接用真值转换来判断一个函数的参数是否传进来了,这是不不太安全的。比如,有一个可以具有默认值得可选参数的函数,如下:

function point(x, y) {
if (!x) {
  x = 320;
}
if (!y) {
  y = 240;
}
  return { x: x, y: y };
}

这个函数会忽略任何的真值为假的参数的,包括0,-0;

point(0, 0); // { x: 320, y: 240 }

检测undefined的更加准确的方法是用typeof操作:

function point(x, y) {
if (typeof x === "undefined") {
  x = 320;
}
if (typeof y === "undefined") {
  y = 240;
}
  return { x: x, y: y };
}

这种写法,可以区分开0和undefined的:

point(); // { x: 320, y: 240 }
point(0, 0); // { x: 0, y: 0 }

另外一种方法是利用参数跟undefined作比较,如下:

if (x === undefined) { ... }

总结:

1. 类型错误有可能会被类型转换所隐藏。
2. “+”既可以表示字符串连接,又可以表示算术加,这取决于它的操作数,如果有一个为字符串的,那么,就是字符串连接了。
3. 对象通过valueOf方法,把自己转换成数字,通过toString方法,把自己转换成字符串。
4.具有valueOf方法的对象,应该定义一个相应的toString方法,用来返回相等的数字的字符串形式。
5.检测一些未定义的变量时,应该使用typeOf或者与undefined作比较,而不应该直接用真值运算。

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
列表内容的选择
Jun 30 Javascript
JavaScript伸缩的菜单简单示例
Dec 03 Javascript
浅谈javascript中的call、apply、bind
Mar 06 Javascript
ExtJS 4.2 Grid组件单元格合并的方法
Oct 12 Javascript
纯js实现动态时间显示
Sep 07 Javascript
浅谈react-native热更新react-native-pushy集成遇到的问题
Sep 30 Javascript
使用vue-router与v-if实现tab切换遇到的问题及解决方法
Sep 07 Javascript
js实现动态增加文件域表单功能
Oct 22 Javascript
layui switch 开关监听 弹出确定状态转换的例子
Sep 21 Javascript
Vue设置长时间未操作登录自动到期返回登录页
Jan 22 Javascript
vue组件讲解(is属性的用法)模板标签替换操作
Sep 04 Javascript
使用JS实现简易计算器
Jun 14 Javascript
react-router-dom 嵌套路由的实现
May 02 #Javascript
在react中使用vue的状态管理的方法示例
May 02 #Javascript
JS表单验证插件之数据与逻辑分离操作实例分析【策略模式】
May 01 #Javascript
javascript实现的图片预览和上传功能示例【兼容IE 9】
May 01 #Javascript
jQuery实现的移动端图片缩放功能组件示例
May 01 #jQuery
jQuery实现移动端图片上传预览组件的方法分析
May 01 #jQuery
jQuery实现的上拉刷新功能组件示例
May 01 #jQuery
You might like
php set_magic_quotes_runtime() 函数过时解决方法
2010/07/08 PHP
php + ajax 实现的写入数据库操作简单示例
2020/05/16 PHP
PNGHandler-借助JS让PNG图在IE下实现透明(包括背景图)
2007/08/31 Javascript
Javascript 中文字符串处理额外注意事项
2009/11/15 Javascript
Array.prototype 的泛型应用分析
2010/04/30 Javascript
JavaScript中使用构造函数实现继承的代码
2010/08/12 Javascript
日历查询的算法 如何计算某一天是星期几
2012/12/12 Javascript
如何获取select下拉框的值(option没有及有value属性)
2013/11/08 Javascript
js定时器的使用(实例讲解)
2014/01/06 Javascript
学习JavaScript设计模式(多态)
2015/11/25 Javascript
angular2使用简单介绍
2016/03/01 Javascript
简述JavaScript提交表单的方式 (Using JavaScript Submit Form)
2016/03/18 Javascript
完美解决JS文件页面加载时的阻塞问题
2016/12/18 Javascript
利用JavaScript如何查询某个值是否数组内
2017/07/30 Javascript
AngularJS实现的获取焦点及失去焦点时的表单验证功能示例
2017/10/25 Javascript
微信小程序webview组件交互,内联h5页面并网页实现微信支付实现解析
2019/08/16 Javascript
vuex页面刷新导致数据丢失的解决方案
2020/12/10 Vue.js
[01:29]2017 DOTA2国际邀请赛官方英雄手办展示
2017/03/18 DOTA
[51:44]2018DOTA2亚洲邀请赛 4.3 突围赛 Optic vs iG 第二场
2018/04/04 DOTA
Python写的服务监控程序实例
2015/01/31 Python
python基础教程项目四之新闻聚合
2018/04/02 Python
Python实现爬虫从网络上下载文档的实例代码
2018/06/13 Python
Python将一个CSV文件里的数据追加到另一个CSV文件的方法
2018/07/04 Python
python matplotlib画图库学习绘制常用的图
2019/03/19 Python
Python3实现的旋转矩阵图像算法示例
2019/04/03 Python
解决Tensorboard可视化错误:不显示数据 No scalar data was found
2020/02/15 Python
Python 实现一行输入多个数字(用空格隔开)
2020/04/29 Python
介绍一下grep命令的使用
2012/06/28 面试题
介绍一下linux的文件权限
2014/07/20 面试题
哈弗商学院毕业生求职信
2014/02/26 职场文书
励志演讲稿500字
2014/08/21 职场文书
2014年高一班主任工作总结
2014/12/05 职场文书
2014矛盾纠纷排查调处工作总结
2014/12/09 职场文书
2014年连锁店圣诞节活动方案
2014/12/09 职场文书
社区党风廉政建设调研报告
2015/01/01 职场文书
使用 Apache Dubbo 实现远程通信(微服务架构)
2022/02/12 Servers