值类型转换
定义:类型转换分为显式转换和隐式转换。区别在于,显式类型转换发生在静态类型语言的编译阶段,隐式类型转换发生在动态类型语言的运行时。
var a = 42;
var b = a + ""; //隐式
var c = String(a); //显式
抽象值操作
定义:ES5规范中定义了一些抽象操作(即仅供对内部使用的操作)和转换规则。
toString
对于普通对象来说,除非自行定义,不然toString都会返回内部属性[[Class]]的值,如"[object object]"。注意:数组默认的toStirng方法经过重新定义。
var a = [1, 2, 3];
a.toString();//"1,2,3"
JSON字符串化
常用工具类函数JSON.stringify()在序列化JSON对象时也会调用toString。
JSON.stringify(24); //"24"
JSON.stringify("24"); //""24""
JSON.stringify(null); //"null"
JSON.stringify(true); //"true"
//不安全的JSON值
JSON.stringify(undefined);//"undefined"
JSON.stringify(function(){}); //"undefined"
JSON.stringify([1,undefined,function(){},4]); //"[1,null,null,4]"
JSON.stringify({a:24,b:function(){}}); //"{a:24}"
//对于循环引用的对象会报错
//如果需要对含有非法JSON值的对象序列化,可以手动定义对象的toJSON方法,然后使用它返回安全的值进行序列化。
var o = {};
var a = {
n:8,
o:o,
f:function(){}
}
//建立循环引用
o.e = a;
JSON.stringify(a); //error
//定义toJSON方法
a.toJSON = function(val){
return this.n
}
//toJSON返回的是一个能够被序列化的安全JSON值。
JSON.stringify(a); //"{n:8}"
//JSON.stringify的可选参数(JSON_Obj,keys_Array 或者 Callback, tab_space)
//space为每一级缩进的字符数
//callback第一次调用时,k为undefined
var a = {
b:24,
c:"8",
d:[1,2,3]
};
JSON.stringify(a,["b","c"]) //"{"b":24,"c":"8"}"
JSON.stringify(a,function(k,v){
if(k !== c){
return v;
}
}) //"{"b":24,"c":"8"}"
toNumber
为了将值类型转换为相应的基本类型值,操作操作会首先检查该值是否具有valueOf方法,如果有则返回基本类型值,就使用该值进行强制类型转换。如果没有则调用toStirng方法的返回值进行强制类型转换。若valueOf和toString()均无返回值,则报错。
var a = {
valueOf:function(){
return "24";
}
}
//"24"
var b = {
toString:function(){
return "24";
}
}
//"24"
var c = [4, 2];
c.toString = function(){
return this.join("");
}
//"24"
Number(a);
Number(b);
Number(c);
toBoolean
假值:undefined、null、false、+0、-0和NaN、""
假值的布尔强制类型转换结果为false,其他为真值,转换结果为true。
注意:被包装器函数封装的假值转换结果为true。
var a = new Boolean(false); //true
var b = new Number(0); //true
var c = new String(""); //true
字符串和数字之间的显示转换
//通过String()和Number()来实现
var a = 42;
var b = String(a); //"42"
var c = "24";
var d = Number(c); //24
//其他方式
var e = a.toString(); //"42"
var f = +c; //24
//~运算符 (字位操作符“非”)
//位操作符只适用于32位整数,运算符会强制操作数使用32位格式。通过toInt32抽象操作实现。
var a = "hello world";
~a.indexOf("hello"); //-1 真值
~a.indexOf("abc"); //0 假值
//~~将值截取位32整数
var a = 39.6;
var b = -39.6;
var c = 39.4;
var d = -39.4;
~~a; //39
~~b; //-39
~~c; //39
~~d; //-39
//显示解析字符串
var a = "24";
var b = "24px";
Number(a)//24
parseInt(a)//24
Number(b) //NaN
parseInt(b) //24
//parseInt针对的是字符串,对于非字符参数会强制转化为字符串类型,parseInt的第二个参数
//来指定转换的基数,若没有传入第二个参数,则根据第一个参数的第一个字符来决定
//若第一个字符为x或X,则转换为16进制数字,0为八进制。
//parseInt解析参数,当解析到第一个不为数字的有效字符时结束,如下。
parseInt(Infinity); //NaN
parseInt(Infinity,19); //18 I以19为基数时,值为18
//显示转化为Boolean类型值
//使用!!或者Boolean
//隐式强制类型转换
//字符串和数字 :数字 => 字符串
var a = 24;
var b = "8";
a + b //"248"
//数组用"+"号运算,强制转化成字符串
var c = [1, 2];
var d = [3, 4];
c + d //"1,23,4"
//字符串的隐式转换,会先调用该对象的抽象操作valueOf获取值,然后通过toString方法返回该值的字符串形式。
var foo = {
valueOf:function(){
return 24;
},
toString:function(){
return 8
}
}
//隐式转换
a + "" // "24"
//显示转换
String(foo) //8
//字符串转数字
var a = "24";
a - 0 //24
var c = [1];
var b = [2];
c - b //-1
//布尔值和数字
var a = [true,false,true];
var sum = 0;
for(var i = 0, length = a.length; i < length; i++){
//隐式转换
if(a[i]){
//do sth
sum += a[i];
}
//显示转换
sum += Number(!!a[i]);
}
&& 和 ||
&&连接的值,若都为真,则返回最后一个操作数
||连接的值,返回第一个为真的操作数
//符号类型的强制类型转换
var s = Symbol("FZW");
String(s); //Symbol("FZW") node 6.9+
s + "" //Cannot convert a Symbol value to a string
//== 和 ===
//误区:==检查值是否相等,===检查值和类型是否相等
//== 和 === 的速度差可以忽略不计
//正解:==和===检查操作数是否相等时,都会去检查操作数的类型,区别在于操作数类型不同时,它们的处理方式不同。
//ES5抽象操作方法定义了 == 的行为
//如果两个值类型相同,就仅比较两者是否相等,反之发生隐式强制类型转换在做比较
//特殊情况:NaN !== NaN //true +0 == -0 //true
//==隐式强制类型转换规则
//字符串和数字比较
var a = 24;
var b = "24";
a == b //true
a === b //false
//如果Type(a)为数字,Type(b)为字符串,则返回a == ToNumber(b)的结果
//如果Type(a)为字符串,Type(b)为数字,则返回ToNumber(a) == b的结果
//其他类型和布尔类型之间的比较
var a = "24";
var b = true;
a == b //false
//如果Type(a)为布尔类型,则返回ToNumber(a) == b的结果
//如果Type(b)为布尔类型,则返回a == ToNumber(b)的结果
上诉比较实际转化为:"24" == 1 //false
同理 a == false //false ,实际转为 "24" == 0 //false
建议:无论什么情况都不要使用 n == true/false 的比较方式
//undefined 和 null的比较
// undefined == null //true
// undefined === null //false
//设计null和undefined的判断
if(a == null){
//do sth
}
//对象和非对象之间的比较
//如果Type(a)为数字或字符串,Type(b)为对象,则返回a == toPrimitive(b)的结果
//如果Type(b)为对象,Type(b)为数字或字符串,则返回toPrimitive(a) == b的结果
var a = [24];
var b = 24;
a == b //true
var c = "fzw";
var d = String(c);
c == d //true
//假值比较
"0" == null //false
"0" == undefined //false
"0" == false //true
"0" == NaN //false
"0" == "" //false
false == null //false
false == undefined //false
false == NaN //false
false == 0 //true
false == "" //true
false == [] //true
false == {} //false
"" == null //false
"" == undefined //false
"" == NaN //false
"" == 0 //true
"" == [] //true
"" == {} //false
0 == null //false
0 == undefined //false
0 == NaN //false
0 == [] //true
0 == {} //false
//极端情况
[] == ![] //true
![]通过隐式类型转化,[] == false ,在转化为 [] == 0,
再转化为,"" == 0 , 最后转化为 0 == 0 ,输出true
//抽象关系比较
// var a = [42];
// var b = ["43"];
// console.log(a > b); //false
// console.log(a < b); //true
var a = ["043"];
var b = [42];
console.log(a > b); //false
//a和b并没有被转化成数字,而是转化为"043"和"42"两个字符串进行比较,它们分别以"0"和"4",因为"0"在字母顺序上小于"4",所以最后结果返回为false.
var c = {a:24};
var b = {b:23};
a < b //false
a > b //false
a == b //false
a <= b //true
b >= a //true
在JS中,“<=”不是小于或者等于的意思,而是不大于。