说说JavaScript的类型转换

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

内容简介:最近在重读《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的类型转换》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Head First HTML and CSS

Head First HTML and CSS

Elisabeth Robson、Eric Freeman / O'Reilly Media / 2012-9-8 / USD 39.99

Tired of reading HTML books that only make sense after you're an expert? Then it's about time you picked up Head First HTML and really learned HTML. You want to learn HTML so you can finally create th......一起来看看 《Head First HTML and CSS》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具