JS的强制类型转换
将值从一种类型转换为另一种类型通常称为类型转换,这是显式的情况,隐式的情况称为强制类型转换。
JavaScript中的强制类型转换总是返回标量基本类型值,如字符串、数字和布尔值,不会返回对象和函数。
类型转换发生在静态类型语言的编译阶段,而强制类型转换则发生在动态类型语言的运行时。
我们能够从代码中看出哪些地方是显式强制类型转换,而隐式强制类型转换则不那么明显,通常是某些操作产生的副作用。
1.字符串、数字和布尔值之间类型转换的基本规则
1.1 ToString
基本类型值的字符串化规则为:null转换为"null",undefined转换为"undefined",true转换为"true"。
对于普通对象来说,除非自定义,否则toString()返回内部属性[[Class]]的值,如"[object Object]"。
var a = [1,2,3];
console.log(a.toString());//"1,2,3"
toString()可以被显式调用,或者在需要字符串化时自动调用。
JSON.stringify(..)在将JSON对象序列化为字符串时也用到了ToString。
JSON.stringify(42);//"42"
JSON.stringify("42");//""42""
JSON.stringify(null);//"null"
JSON.stringify(true);//"true"
所有安全的JSON值都可以使用JSON.stringify(..)字符串化。安全的JSON值是指能够呈现为有效JSON格式的值。
不安全的JSON值包括undefined、function、symbol和包含循环引用的对象。
如果要对含有非法JSON值的对象做字符串化,或者对象中的某些值无法被序列化时,就需要定义toJSON()方法来返回一个安全的JSON值。
如果对象中定义了toJSON()方法,JSON字符串化时会首先调用该方法,然后用它的返回值来进行序列化。
toJSON()返回的应该是一个适当的值(一个能够被字符串化的安全的JSON值),可以是任何类型,然后再由JSON.stringify(..)对其进行字符串化。
var a = {
b : 42,
c : "42",
d : [1,2,3]
};
console.log(JSON.stringify(a,["b","c"]));//"{"b":42,"c","42"}"
console.log(JSON.stringify(a,function(k,v){if(k != "c"){return v;}}));//"{"b":42,"d",[1,2,3]}"
1.2 ToNumber
ES5规范定义了抽象操作ToNumber用于将非数字值转换为数字值。
其中true转换为1,false转换为0。undefined转换为NaN,null转换为0。
对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。
为了将值转换为相应的基本类型值,抽象操作ToPrimitive会首先检查该值是否有valueOf()方法,如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用toString()的返回值(如果存在)来进行强制类型转换。
var a = {
valueOf: function(){
return "42";
}
};
var b = {
toString: function(){
return "42";
}
};
var c = [4,2];
c.toString = function(){
return this.join("");//"42"
};
Number(a);//42
Number(b);//42
Number(c);//42
Number("");//0
Number([]);//0
Number(["abc"]);//NaN
1.3 ToBoolean
假值
- undefined
- null
- false
- +0、-0和NaN
- ""
假值的布尔强制类型转换结果为false。
所有的对象都是真值,假值对象除外。
假值对象不是包装了假值的封装对象。
var a = new Boolean(false);
var b = new Number(0);
var c = new String("");
var d = Boolean( a && b && c );
console.log(d);//true
//d为true,说明a、b、c都为true。
浏览器在某些特定情况下,在常规JavaScript语法基础上自己创建了一些外来(exotic)值,这些就是“假值对象”。
真值
真值就是假值列表之外的值。
var a = "false";
var b = "0";
var c = "''";
var d = Boolean( a && b && c );
console.log(d);//true
//所有字符串都是真值。
var a = [];//空数组
var b = {};//空对象
var c = function(){};//空函数
var d = Boolean( a && b && c );
console.log(d);//true
//[]、{}和function(){}都不在假值列表中,因此它们都是真值。
2.显式强制类型转换
我们在编码时应尽可能地将类型转换表达清楚,以免给别人留坑。类型转换越清晰,代码可读性越高,更容易理解。
2.1 字符串和数字之间的显式转换
var a = 42;
var b = String(a);//将数字转换为字符串
var c = "3.14";
var d = Number(c);//将字符串转换为数字
console.log(b);//"42"
console.log(d);//3.14
var e = 5+ +c;//+c显式地将c转换为数字
console.log(e);//8.14
日期显式转换为数字
var d = new Date("Mon, 18 Aug 2014 08:53:06 CDT");
console.log(+d);//1408369986000
我们不建议对日期类型使用类型转换,应该使用Date.now()来获得当前的时间戳,使用new Date(..).getTime()来获得指定时间的时间戳。
奇特的~运算符
//~x大致等同于-(x+1)。
~42;//-(42+1) ==> -43
//~和indexOf()一起可以将结果强制转换为真/假值。
//JavaScript中字符串的indexOf(..)方法在字符串中搜索指定的子字符串,如果找到就返回子字符串所在的位置(从0开始),否则返回-1。
var a = "Hello World";
~a.indexOf("lo");//-4 <-- 真值!
if(~a.indexOf("lo")){//true
//找到匹配!
}
//~-1的结果为0。
~a.indexOf("ol");//0 <-- 假值!
!~a.indexOf("ol");//true
if(!~a.indexOf("ol")){//true
//没有找到匹配!
}
字位截除
一些开发人员使用~~来截除数字值的小数部分,~~只适用于32位数字。
我们在使用~和~~进行此类转换时需要确保其他人也能够看得懂。
2.2 显式解析数字字符串
var a = "42";
var b = "42px";
Number(a);//42
parseInt(a);//42
Number(b);//NaN
parseInt(b);//42
2.3 显式转换为布尔值
var a = "0";
var b = [];
var c = {};
var d = "";
var e = 0;
var f = null;
var g;
Boolean(a);//true
Boolean(b);//true
Boolean(c);//true
Boolean(d);//false
Boolean(e);//false
Boolean(f);//false
Boolean(g);//false
!!a;//true
!!b;//true
!!c;//true
!!d;//false
!!e;//false
!!f;//false
!!g;//false
//在if(..)..这样的布尔值上下文中,如果没有使用Boolean(..)和!!,就会自动隐式地进行ToBoolean转换。
3.隐式强制类型转换
隐式强制类型转换的作用是减少冗余,让代码更简洁。
3.1 字符串和数字之间的转换
var a = "42";
var b = "0";
var c = 42;
var d = 0;
a + b;//"420"
c + d;//42
var e = [1,2];
var f = [3,4];
e + f;//"1,23,4"
var g = 42;
var h = g + "";
h;//"42"
var i = "3.14";
var j = i - 0;
j;//3.14
3.2 布尔值到数字的转换
function onlyOne(){
var sum = 0;
for(var i = 0; i<arguments.length; i++){
if(arguments[i]){
//下面等同于 sum += Number(!!arguments[i]);
sum += arguments[i];
}
}
return sum == 1;
}
var a = true;
var b = false;
console.log(onlyOne(b,a));//true
console.log(onlyOne(b,a,b,b,b));//true
console.log(onlyOne(b,b));//false
console.log(onlyOne(b,a,b,b,b,a));//false
3.3 隐式强制类型转换为布尔值
下面的情况会发生布尔值隐式强制类型转换:
if(..)语句中的条件判断表达式。for(..;..;..)语句中的条件判断表达式。while(..)和do..while(..)循环中的条件判断表达式。? :中的条件判断表达式。- 逻辑运算符
||(逻辑或)与&&(逻辑与)左边的操作数。
3.4 || 和&&
和其他语言不同,在JavaScript中||和&&的返回值是两个操作数中的一个(且仅一个)。即选择两个操作数中的一个,然后返回它的值。
var a = 42;
var b = "abc";
var c = null;
a || b;//42
a && b;//"abc"
c || b;//"abc"
c && b;//null
//a || b相当于a ? a : b
//a && b相当于a ? b : a
对于||来说,如果条件判断结果为true就返回第一个操作数的值,如果为false就返回第二个操作数的值。
对于&&来说,如果条件判断结果为true就返回第二个操作数的值,如果为false就返回第一个操作数的值。


4.宽松相等和严格相等
宽松相等==检查值是否相等,严格相等===检查值和类型是否相等。
==允许在相等比较中进行强制类型转换,而===不允许。
4.1 抽象相等
字符串和数字之间的相等比较
var a = 42;
var b = "42"
a === b;//false
a == b;//true
其他类型和布尔类型之间的相等比较
var a = "42";
//不要这样用,条件判断不成立
if(a == true){
//..
}
//也不要这样用,条件判断不成立
if(a === true){
//...
}
//这样的显式用法没问题
if(a){
//..
}
//这样的显式用法更好
if(!!a){
//..
}
//这样的显式用法也很好
if(Boolean(a)){
//..
}
null和undefined之间的相等比较
var a = null;
var b;
a == b;//true
a == null;//true
b == null;//true
a == false;//false
b == false;//false
a == "";//false
b == "";//false
a == 0;//false
b == 0;//false
对象和非对象之间的相等比较
var a = "abc";
var b = Object(a);
a === b;//false
a == b;//true
//a == b结果为true,因为b通过ToPromitive进行强制类型转换(也称为"拆封"),并返回标量基本类型值"abc",与a相等。
var a = null;
var b = Object(a);
a == b;//false
var c = undefined;
var d = Object(c);
c == d;
var e = NaN;
var f = Object(a);
e == f;
//因为没有对应的封装对象,所以null和undefined不能够被封装。
//NaN能够被封装为数字封装对象,但拆封之后NaN == NaN返回false,因为NaN不等于NaN。
4.2 比较少见的情况
假值的相等比较

极端情况

安全运用隐式强制类型转换
- 如果两边的值中有
true或者false,千万不要使用==。 - 如果两边的值中有
[]、""或者0,尽量不要使用==。
这时最好用===来避免不经意的强制类型转换。这两个原则可以让我们避开几乎所有强制类型转换的坑。
5.抽象关系比较
var a = [42];
var b = ["43"];
a < b;//true
b < a;//false
var c = ["42"];
var d = ["043"];
c < d;//false
var e = [4,2];
var f = [0,4,3];
e < f;//false
//e转换为"4,2",f转换为"0,4,3",按字母顺序进行比较
var a = {b:42};
var b = {b:43};
a < b;//false
a == b;//false
a > b;//false
a <= b;//true
a >= b;//true
//根据规范a <= b被处理为b < a,然后将结果反转,因为b < a的结果是false,所以a <= b的结果是true。
参考资料:《你不知道的JavaScript》(中卷) 第四章
JS的强制类型转换的更多相关文章
- 《You dont know JS》强制类型转换
强制类型转换 将值从一种类型转换为另一种类型通常称为类型转换,这是显式的情况.隐式的情况被称为强制类型转换 在书中,作者还提出一种区分方式: 类型转换发生在静态类型语言的编译阶段,强制类型转换发生在动 ...
- JS中强制类型转换
JavaScript提供了3种强制类型转换的方法 一.Boolean()方法 该方法将指定的参数转换成布尔型.Boolean(object).参数object可以是字符串对象.数值对象.DOM对象等. ...
- JavaScript学习10 JS数据类型、强制类型转换和对象属性
JavaScript学习10 JS数据类型.强制类型转换和对象属性 JavaScript数据类型 JavaScript中有五种原始数据类型:Undefined.Null.Boolean.Number以 ...
- Js里面的强制类型转换
js 和 PHP语言一样是弱类型语言.近期我也在看C语言,并没有传说中那么难,既是书中一再强调的指针部分,也没有那么夸张.至少是理论和语法理解起来不是很难.看起来凡是什么东西,不要总是被别人的话迷惑了 ...
- JS 数据类型转换-转换函数、强制类型转换、利用js变量弱类型转换
1. 转换函数: js提供了parseInt()和parseFloat()两个转换函数.前者把值转换成整数,后者把值转换成浮点数.只有对String类型调用这些方法,这两个函数才能正确运行:对其他类型 ...
- JS在if中的强制类型转换
JS在if中的强制类型转换 众所周知,JS在很多情况下会进行强制类型转换,其中,最常见两种是: 1.使用非严格相等进行比较,对==左边的值进行类型转换 2.在if判断时,括号内的值进行类型转换,转化为 ...
- JS中的“==”与强制类型转换
JavaScript中有“==”与“===”,那么他们有何区别呢? 对于基本数据类型, === (!==)只有当两个变量的类型和值都相等时,才返回true:而 == (!=)则会对变量进行强制类型转 ...
- Js中的假值_ES5中定义的ToBoolean方法强制类型转换后值为false
你不知道的Javascript(中)--ToBoolean javascript中的值可以分为以下两类: 1.可以被强制类型转换为false的值 2.其他(被强制类型转换为true的值) 假值---以 ...
- js字符串转换为数字的三种方法。(转换函数)(强制类型转换)(利用js变量弱类型转换)
js字符串转换为数字的三种方法.(转换函数)(强制类型转换)(利用js变量弱类型转换) 一.总结 js字符串转换为数字的三种方法(parseInt("1234blue"))(Num ...
随机推荐
- Java字符串分割
java中字符串的分割函数,split("你想要分割的字符", 你想要最多分割为多少段,正整数) 注意事项: 1.分割特殊字符考虑转义字符的使用.如: . \ | 2.第二个参数: ...
- python基础学习笔记(一)
最好有点c++基础来看,,每天都更新一篇吧 这一篇是一些基础东西 1.运算符2.变量3.基本输入输出4.字符串5.列表6.元组7.字典8.集合9.简单的说下循环啥的 1.运算符 特别的 a / b:为 ...
- python-五行红旗实现
import turtle """ 绘制五星红旗 作者:zxj 版本:1.0 """ # 绘制矩形函数 def giant(leg,hig) ...
- <React Native移动开发实战>-1-React Native的JSX解决方案
JSX并不是一门新的开发语言,而是Facebook提出的语法方案:一种可以在JavaScript代码中直接书写HTML标签的语法糖,所以,JSX本质上还是JavaScript语言. 小知识:语法糖(S ...
- 备份win10的驱动程序
目录 折腾历程 怎么备份驱动 备份的驱动如何使用 关于驱动程序的OS兼容性 驱动程序的其他安装方式 1.折腾历程 从闲鱼上收了一个INSIGNIA的二合一笔记本,w7100,因原装win10性能不行自 ...
- SQL IF while 游标
-- if语句使用示例 declare @a int set @a=1 begin print @a =@a+1 end else begin print 'noooo' end -- while语句 ...
- unzip/tar命令详解
博客目录总纲首页 原文链接:https://www.cnblogs.com/zdz8207/p/3765604.html Linux下的压缩解压缩命令详解及实例 实例:压缩服务器上当前目录的内容为xx ...
- jenkins配置01--用户添加及权限配置
原文出自:https://www.cnblogs.com/kevingrace/p/6019707.html 下面重点记录下jenkins安装后的一些配置: (1)添加用户权限 jenkins初次登陆 ...
- js备忘录6
- oracle将多个结果集用逗号拼接成字符串
有两个函数wmsys.wm_concat和listagg 1,SELECT wmsys.wm_concat(CATALOG_NAME) FROM "DATASHARE"." ...