说说JavaScript的类型转换

栏目: JavaScript · 发布时间: 5年前

内容简介:最近在重读《JavaScript高级程序设计》,读到数据类型这一节,想到了JavaScript里令程序员抓狂的一个问题——类型转换。因为JS是一门弱类型的语言,在运行时系统会根据需要进行类型转换,而类型转换的规则又令人迷惑。于是写篇博文尝试自己总结来加深印象。首先,我们知道JavaScript里有7种数据类型:

最近在重读《JavaScript高级程序设计》,读到数据类型这一节,想到了JavaScript里令 程序员 抓狂的一个问题——类型转换。因为JS是一门弱类型的语言,在运行时系统会根据需要进行类型转换,而类型转换的规则又令人迷惑。于是写篇博文尝试自己总结来加深印象。

基本概念

首先,我们知道JavaScript里有7种数据类型:

boolean number null string symbol undefined object

object称为引用类型,其余的数据类型统称为“基本类型”。

显示强制类型转换

转换为Boolean类型

布尔值的强制类型转换使用的方法主要有: Boolean() 。其实布尔值的转换规则很好记住,因为转换后为false的值有限,只有下列几种:

null undefined false +0 -0 NaN ""

转换为Number类型

数字的强制类型转换使用的方法主要有:Number() parseInt() parseFloat() 和一元操作符。

Number() 函数的转换规则如下:

  • 如果是 Boolean 值, true 和 false 将分别被转换为 1 和 0。
  • 如果是数字值,只是简单的传入和返回。
  • 如果是 null 值,返回 0。
  • 如果是 undefined ,返回 NaN 。
  • 如果是字符串,遵循下列规则:
  • 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即 "1"会变成 1, "123" 会变成 123,而 "011" 会变成 11(注意:前导的零被忽略了);
  • 如果字符串中包含有效的浮点格式,如 "1.1" ,则将其转换为对应的浮点数值(同样,也会忽略前导零);
  • 如果字符串中包含有效的十六进制格式,例如 "0xf" ,则将其转换为相同大小的十进制整数值;
  • 如果字符串是空的(不包含任何字符),则将其转换为 0;
  • 如果字符串中包含除上述格式之外的字符,则将其转换为 NaN 。

细说parseInt

parseInt() 只处理字符串类型,如果接受的参数不是字符串类型,会先将其转换为字符串类型(稍后介绍字符串的强制转换)

parseInt() 函数在转换字符串时,更多的是看其是否符合数值模式。它会忽略字符串前面的空格,直至找到第一个非空格字符。如果第一个字符不是数字字符或者负号,parseInt() 就会返回 NaN 。如果第一个字符是数字字符,parseInt() 会继续解析第二个字符,直到解析完所有后续字符或者遇到了一个非数字字符。例:

var num1 = parseInt("123iuuan"); // 123(字母不是数字字符,被忽略)
var num2 = parseInt(""); // NaN
var num3 = parseInt("0xA"); // 10(十六进制数)
var num4 = parseInt(22.5); // 22)(小数点并不是有效的数字字符)
复制代码

parseInt() 函数可以接收两个参数,第一个参数是需转换字符串,第二个参数是转换是使用的基数(即多少进制),例如:

var num1 = parseInt("AF", 16); //175
var num2 = parseInt("AF"); //NaN
复制代码

当指定基数时,字符串可以被成功转换,而第二个转换时,按之前说的转换规则,第一个字符不是数字字符,所以直接返回了NaN。

对于同一个字符串,如果指定的基数不同,转换的结果也会受影响,例如:

var num1 = parseInt("10", 2); //2 (按二进制解析)
var num2 = parseInt("10", 8); //8 (按八进制解析)
var num3 = parseInt("10", 10); //10 (按十进制解析)
var num4 = parseInt("10", 16); //16 (按十六进制解析)
复制代码

综上所述,当不指定基数时,parseInt() 会自行决定如何解析输入的字符串,所以为了避免错误的解析,使用 parseInt() 时都应该指定基数。

转换为String类型

要把一个值转换为一个字符串有两种方式,第一种是使用 toString() 方法,除了null和undefined之外,其余的数据类型都有这个方法,它返回相应值的字符串表现。在调用数值的 toString() 方法时,可以传递一个参数:输出数值的基数。默认的输出值与指定基数10时的输出值相同。

var iuuan = true;
alert(iuuan.toString());    // 'true'
var num = 7;
alert(num.toString());      // '7'
alert(num.toString(2));     // '111'
alert(num.toString(10));    // '7'
复制代码

在不知道要转换的值是不是 null 或 undefined 的情况下,还可以使用转型函数 String() ,这个函数能够将任何类型的值转换为字符串。

  • 当值有 toString() 方法是,调用该方法并返回结果;
  • 值是null时,返回"null";
  • 值是undefined时,返回"undefined"。
var value1 = 10;
var value2 = true;
var value3 = null;
var value4;
alert(String(value1)); // "10"
alert(String(value2)); // "true"
alert(String(value3)); // "null"
alert(String(value4)); // "undefined"
复制代码

对象转换为基本类型

1、对象转换为布尔值时,根据上文所说的 Boolean() 假值可知,转换后所有的对象都为true;

2、对象转换为字符串:

  • 判断对象是否有 toString() 方法,如果有 toString() 方法且返回的结果是基本类型值,就返回这个结果并转换为字符串;
  • 如果对象没有 toString 方法或者该方法返回的不是原始值,就判断该对象是否有 valueOf 方法。如果存在 valueOf 方法且返回值是基本类型值,就返回并转换为字符串;
  • 否则就抛出错误。
var objtostring1 = {    
    //toString返回基本类型值
    toString:function(){
        return null
    }
}
var objtostring2 = {    
    //toString方法返回不是基本类型值,valueOf返回基本类型值
    toString:function(){
        return {}
    },
    valueOf:function(){
        return undefined
    }
}
var objtostring3 = {    
    //toString方法返回不是基本类型值,valueOf返回的也不是基本类型值
    toString:function(){
        return {}
    },
    valueOf:function(){
        return {}
    }
}
String(objtostring1);    //'null'
String(objtostring2);    //'undefined'
String(objtostring3);    //Uncaught TypeError: Cannot convert object to primitive value
复制代码

3、对象转换为数值:

  • 对象转换为数值的操作与转换为字符串基本相似,只是转换时先调用 valueOf ,不存在或返回值不是基本类型值时,再调用 toString 方法。
var objtonum1 = {    
    //valueOf返回基本类型值
    valueOf:function(){
   ​     return null
    }
}
var objtonum2 = {    
    //valueOf方法返回不是基本类型值,toString返回基本类型值
    valueOf:function(){
   ​     return {}
    },
    toString:function(){
   ​     return 1
    }
}
var objtonum3 = {    
    //valueOf方法返回不是基本类型值,toString返回的也不是基本类型值
    valueOf:function(){
   ​     return {}
    },
    toString:function(){
   ​     return {}
    }
}
Number(objtonum1);    //0	null转换为数值后为0
Number(objtonum2);    //1
Number(objtonum3);    //Uncaught TypeError: Cannot convert object to primitive value
复制代码

隐式强制类型转换

与显示类型转换使用函数方法不同,隐式类型转换发生在是使用操作符或者语句中间。

+ 操作符

当 + 操作符作为一元操作符时,对非数值进行 Number() 转型函数一样的转换;

var s1 = "01",s2 = "1.1",s3 = "z";,b = false,f = 1.1;
var o = {
	valueOf: function() {
		return -1;
	}
};
s1 = +s1;    // 值变成数值 1
s2 = +s2;    // 值变成数值 1.1
s3 = +s3;    // 值变成 NaN
b = +b;      // 值变成数值 0
f = +f;      // 值未变,仍然是 1.1
o = +o;      // 值变成数值-1
复制代码

当 + 操作符作为加法运算符时,会应用如下规则:

  • 如果两个操作数都是字符串,则进行简单的字符串拼接;
  • 如果只有一个操作数是字符串,则将另一个转换为字符串再进行拼接,转换为字符串的操作与显示转换时规则相同;
  • 如果有一个操作数是对象、数值或布尔值,则调用它们的 toString 方法取得相应的字符串值,然后再应用前面关于字符串的规则
var s1 = "01",s2 = "1.1",b = false,f = 1.1;
var o = {
	valueOf: function() {
		return -1;
	}
};
s1 + s2    //'011.1'
s1 + b     //'01false'
s2 + f     //'1.11.1'
s1 + o     //'01-1'
复制代码

- 操作符

当 - 操作符作为一元操作符时,对非数值进行 Number() 转型函数一样的转换之后再取负;

var s1 = "01",s2 = "1.1",s3 = "z";,b = false,f = 1.1;
var o = {
	valueOf: function() {
		return -1;
	}
};
s1 = -s1;    // 值变成了数值-1
s2 = -s2;    // 值变成了数值-1.1
s3 = -s3;    // 值变成了 NaN
b = -b;      // 值变成了数值 0
f = -f;      // 变成了-1.1
o = -o;      // 值变成了数值 1
复制代码

当 - 操作符作为加法运算符时,会应用如下规则:

  • 如果操作数存在非数值的基本类型,则先转换为数值在进行减法计算;
  • 如果操作数中存在对象,则按照对象转换为数值的规则将对象转换为数值后进行减法计算。

布尔操作符

逻辑非 !

逻辑非操作符会将它的操作数转换为一个布尔值,然后再对其求反。所以使用两个逻辑非操作符,实际上会模拟 Boolean() 转型函数的行为。

逻辑与 && 和逻辑或 ||

这两个操作符产生的值不是必须为Boolean类型,产生的值始终未两个运算表达式的结果之一。

对于逻辑与 && 来说,如果第一个操作数条件判断为 false 就返回该操作数的值,否则就返回第二个操作数的值。

对于逻辑或 || 来说,如果第一个操作数条件判断为 true 就返回该操作数的值,否则就返回第二个操作数的值。

看个例子:

var a = 'hello',b = '';
a && b;    // '' a是真值,所以返回b
b && a;    // '' b是假值,所以直接返回b,不对a进行判断
a || b;    // 'hello' a是真值,所以直接返回a
b || a;    // 'hello' b是假值,所以返回a
复制代码

可以看得出来,两个操作符在执行时都有一个特点:当第一个操作数能决定操作结果时,则不会对第二个操作数进行判断,并且直接返回第一个操作数的值。这种操作又称为短路操作。

非严格相等 ==

等操作符比较两个值是否相等,在比较前将两个被比较的值转换为相同类型。在转换后(等式的一边或两边都可能被转换),最终的比较方式等同于全等操作符 === 的比较方式。

ECMAScript5文档中关于非严格相等的比较算法,列出了有11中情况,文中就不一一列出了,可以自行去文档查看学习:抽象相等比较算法

这里说明一下ToPrimitive操作,这个操作是ECMAScript运行时系统进行自动类型转换的一种抽象操作,用于将对象类型转换为基本类型,转换规则如下:

  • 检查该值是否有 valueOf 方法。如果有且返回基本类型值,则使用该值;
  • 如果没有就使用 toString 方法的返回值(如果存在)来进行强制类型转换;
  • 如果 valueOf 或者 toString 都不返回基本类型值,则会报错 TypeError。

如此绕的一串规则,不如来看几个例子:

7 == '7'    // true 字符串与数字比较时,字符串转数值后比较
1 == true   // true 操作数中有布尔值,布尔值转数值后比较,true为1
7 == true   // false 原理同上相当于 7 == 1
[] == 0     // true []先调用valueOf,返回值非基本类型,再调用toString,返回为'',空字符串转数值后为0
[] == []    // false 作为引用类型,内存地址不同
复制代码

总结起来就是一下几条:

  1. null和undefined互相比较时,结果为true,其余任何类型与这两个值比较都为false;
  2. 操作数中存在数值,则将另一个操作数转换为数值再比较;
  3. 操作数中没有数值但有字符串,则将另一个操作数转换为字符串再比较;
  4. 操作数中的布尔值都转换为数值。非基本类型都先进行ToPrimitive操作,按上述三条顺序进行比较。

比较关系符

同样的,文档中的规则非常长,就不列出来了,抽象关系比较算法

//两边均为字符串
'7' > '20';    // true 按字符编码进行比较
//两边不全是字符串
7 > '20';    // false 字符串转为数值后进行比较
//两边全不是基本类型
[7] > [20];    // true 数组调用valueOf返回非基本类型,再调用toString方法返回字符串。
var obj = {},obj1 = {};    
obj > obj1;    // false
复制代码

总结起来,比较关系符的类型转换比较规则就是:

  • 如果操作数中存在非基本类型,先进行ToPrimitive操作;
  • ToPrimitive操作转换后如果操作数出现数值,那么将操作数转换为数值进行比较;
  • ToPrimitive操作转换后如果操作数均为字符串,那么按照字符编码值进行比较。

最后来说说 obj >= obj1 的特殊现象

var obj = {},obj1 = {};
obj < obj1;    // false
obj == obj1;   // false
obj > obj1;    // false

obj >= obj1;   // true
obj <= obj1;   // true
复制代码

前面三个结果不难理解,非严格相等判断时,均为空对象,但引用地址不同,返回false。比较两个对象时,先进行ToPrimitive操作,均返回 ''[object Object]'' ,所以不存在大小关系,也返回false。那为什么a <= b和a >= b的结果返回的是true呢?

因为根据规范,a <= b 实际上执行的是 !(a > b),即我们理解的<=是“小于或等于”,但JavaScript执行的是“不大于”的操作,所以 a > b 为false,那么 a <= b 自然为true了。


以上所述就是小编给大家介绍的《说说JavaScript的类型转换》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数据压缩导论

数据压缩导论

萨尤得 / 2009-2 / 99.00元

《数据压缩导论(英文版·第3版)》是数据压缩方面的经典著作,介绍了各种类型的压缩模式。书中首先介绍了基本压缩方法(包括无损压缩和有损压缩)中涉及的数学知识,为常见的压缩形式打牢了信息论基础,然后从无损压缩体制开始,依次讲述了霍夫曼编码、算术编码以及字典编码技术等,对于有损压缩,还讨论了使用量化的模式,描述了标量、矢量以及微分编码和分形压缩技术,最后重点介绍了视频加密。《数据压缩导论(英文版·第3版......一起来看看 《数据压缩导论》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

html转js在线工具
html转js在线工具

html转js在线工具