有趣的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 相关文章推荐
jQuery中add实现同时选择两个id对象
Oct 22 Javascript
innerHTML,outerHTML,innerText,outerText的用法及区别解析
Dec 16 Javascript
js取值中form.all和不加all的区别介绍
Jan 20 Javascript
js的touch事件的实际引用
Oct 13 Javascript
Jquery实现$.fn.extend和$.extend函数
Apr 14 Javascript
jQuery判断元素是否显示 是否隐藏的简单实现代码
May 19 Javascript
React-router v4 路由配置方法小结
Aug 08 Javascript
AngularJS中的路由使用及实现代码
Oct 09 Javascript
vue-cli 首屏加载优化问题
Nov 06 Javascript
实例分析Array.from(arr)与[...arr]到底有何不同
Apr 09 Javascript
layui原生表单验证的实例
Sep 09 Javascript
ES5和ES6中类的区别总结
Dec 21 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函数,php爱好者站推荐
2007/03/19 PHP
PHP+Mysql+Ajax+JS实现省市区三级联动
2014/05/23 PHP
php+mysql实现用户注册登陆的方法
2015/01/03 PHP
利用PHP访问带有密码的Redis方法示例
2017/02/09 PHP
PHP常用的三种设计模式
2017/02/17 PHP
PHP实现的ID混淆算法类与用法示例
2018/08/10 PHP
Firebug 字幕文件JSON地址获取代码
2009/10/28 Javascript
JavaScript中将一个值转换为字符串的方法分析[译]
2012/09/21 Javascript
jQuery事件绑定.on()简要概述及应用
2013/02/07 Javascript
jQuery动态添加删除select项(实现代码)
2013/09/03 Javascript
JS.findElementById()使用介绍
2013/09/21 Javascript
封装的jquery翻页滚动(示例代码)
2013/11/18 Javascript
jquery插件jTimer(jquery定时器)使用方法
2013/12/23 Javascript
javascript生成随机数的方法
2014/05/16 Javascript
Angular 通过注入 $location 获取与修改当前页面URL的实例
2017/05/31 Javascript
JavaScript原生实现观察者模式的示例
2017/12/15 Javascript
javascript数组拍平方法总结
2018/01/20 Javascript
Angular浏览器插件Batarang介绍及使用
2018/02/07 Javascript
JS实现获取自定义属性data值的方法示例
2018/12/19 Javascript
微信小程序系列之自定义顶部导航功能
2019/05/21 Javascript
vue实现图片预览组件封装与使用
2019/07/13 Javascript
JS数组push、unshift、pop、shift方法的实现与使用方法示例
2020/04/29 Javascript
一篇文章看懂JavaScript中的回调
2021/01/05 Javascript
[14:36]2014 DOTA2国际邀请赛中国区预选赛5.21 Orenda VS NE
2014/05/22 DOTA
Python自动登录126邮箱的方法
2015/07/10 Python
使用pycharm设置控制台不换行的操作方法
2019/01/19 Python
Python提取特定时间段内数据的方法实例
2019/04/01 Python
Django框架之中间件MiddleWare的实现
2019/12/30 Python
Python3实现个位数字和十位数字对调, 其乘积不变
2020/05/03 Python
Python logging模块写入中文出现乱码
2020/05/21 Python
苹果中国官方网站:Apple中国
2016/07/22 全球购物
表彰先进集体通报
2014/01/12 职场文书
办公室主任岗位承诺书
2014/05/29 职场文书
计算机毕业生自荐信
2014/06/12 职场文书
政风行风整改方案
2014/10/25 职场文书
护士岗位竞聘书
2015/09/15 职场文书