JavaScript中的强制类型转换总是返回标量基本类型值,如字符串、数字和布尔值,不会返回对象和函数。(强制类型转换则发生在动态类型语言的运行时(runtime)。)
“封装”,就是为标量基本类型值封装一个相应类型的对象,但这并非严格意义上的强制类型转换(类型转换发生在静态类型语言的编译阶段)。
1)ToPrimitive:
为了将对象 值转换为相应的基本类型值,抽象操作 ToPrimitive(参见 ES5 规范 9.1 节)会首先(通过内部操作 DefaultValue,参见 ES5 规范 8.12.8 节)检查该值是否有 valueOf() 方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用 toString()的返回值(如果存在)来进行强制类型转换。
如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。
从 ES5开始,使用 Object.create(null) 创建的对象 [[Prototype]] 属性为 null,并且没有 valueOf() 和 toString() 方法,因此无法进行强制类型转换。因此是真的空对象。
ToPrimitive在Number(),==比较中会运用到。
var a = {
valueOf: function(){
return "42";
},
toString: function(){
return "30";
}
};
var b = {
toString: function(){
return "42";
}
};
var c = [4,2];
c.toString = function(){
return this.join( "" ); // "42"
};
Number( a ); // 42 先调用valueOf,不存在再调用toString
Number( b ); // 42
Number( c ); // 42
String(a);//"30" String转换对象会去调用toString
parseInt(a);//30 parseInt解析对象也会先调用toString
2)toString():
// 1.07 连续乘以七个 1000
var a = 1.07 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000;
// 七个1000一共21位数字
a.toString(); // "1.07e21"
//对普通对象来说,除非自行定义,否则 toString()(Object.prototype.toString())返回内部属性 [[Class]] 的值,如 "[object Object]"。
3)JSON 字符串化: JSON.stringify(…)
(3.1)对大多数简单值(字符串、数字、布尔值和 null )来说,JSON 字符串化和 toString() 的效果基本相同,只不过序列化的结果总是字符串:
JSON.stringify( 42 ); // "42"
JSON.stringify( "42" ); // ""42"" (含有双引号的字符串)
JSON.stringify( null ); // "null"
JSON.stringify( true ); // "true"
(3.2)JSON.stringify(…)对不安全的类型的处理:
//JSON.stringify(..) 在对象中遇到 undefined、function 和 symbol 时会自动将其忽略,
//在数组中则会返回 null(以保证单元位置不变)。
JSON.stringify( undefined ); // undefined
JSON.stringify( function(){} ); // undefined
JSON.stringify(
[1,undefined,function(){},4]
); // "[1,null,null,4]" 在数组中遇到 undefined、function 和 symbol 时,会返回 null
JSON.stringify(
{ a:2, b:function(){} }
); // "{"a":2}" 在对象中遇到 undefined、function 和 symbol 时会自动将其忽略
(3.3)toJson(): 如果传递给 JSON.stringify(…) 的对象中定义了 toJSON() 方法,那么该方法会在字符串化前调用,以便将对象转换为安全的 JSON 值。(JSON.stringify(…)会对toJSON()的结果进行字符串化。) 因此,toJSON() 应该是“返回一个能够被字符串化的安全的 JSON 值”,而不是“返回一个 JSON 字符串”。
//对包含循环引用的对象执行 JSON.stringify(..) 会出错:
var o = { };
var a = {
b: 42,
c: o,
d: function(){}
};// 在a中创建一个循环引用
o.e = a;//循环引用
// 循环引用在这里会产生错误
// JSON.stringify( a );
// 自定义的JSON序列化
a.toJSON = function() {
// 序列化仅包含b
return { b: this.b };
};
JSON.stringify( a ); // "{"b":42}
/**toJSON不需要先做字符串化,可能会得到错误的结果**/
var a = {
val: [1,2,3],
// 可能是我们想要的结果!
toJSON: function(){
return this.val.slice( 1 );
}
};
var b = {
val: [1,2,3],
// 可能不是我们想要的结果!
toJSON: function(){
return "[" +
this.val.slice( 1 ).join() +
"]";
}
};
JSON.stringify( a ); // "[2,3]"
JSON.stringify( b ); // ""[2,3]""
(3.4)JSON.stringify(json, replacer,space):
<1>可选参数 replacer,它可以是数组或者函数,用来指定对象序列化过程中哪些属性应该被处理,哪些应该被排除,和 toJSON() 很像。
如果 replacer 是一个数组,那么它必须是一个字符串数组,其中包含序列化要处理的对象的属性名称,除此之外其他的属性则被忽略。
如果 replacer 是一个函数,它会对对象本身调用一次,然后对对象中的每个属性各调用一次,每次传递两个参数,键和值。如果要忽略某个键就返回 undefined,否则返回指定的值。
<2>可选参数space,用来指定输出的缩进格式。
/**replacer**/
var a = {
b: 42,
c: "42",
d: [1,2,3]
};
JSON.stringify( a, ["b","c"] ); // "{"b":42,"c":"42"}" 只返回b,c属性
JSON.stringify( a, function(k,v){
if (k !== "c") return v;
} );// "{"b":42,"d":[1,2,3]}"
/**space缩进自定义**/
var a = {
b: 42,
c: "42",
d: [1,2,3]
};
JSON.stringify( a, null, 3 );
// "{
// "b": 42,
// "c": "42",
// "d": [
// 1,
// 2,
// 3
// ]
// }"
JSON.stringify( a, null, "-----" );
// "{
// -----"b": 42,
// -----"c": "42",
// -----"d": [
// ----------1,
// ----------2,
// ----------3
// -----]
// }"
4)ToNumber():
true 转换为 1,false 转换为 0。undefined,转换失败的字符串 转换为 NaN,null 转换为 0。
对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型
值,则再遵循以上规则将其强制转换为数字。
//Number中的进制转换
console.log(Number("0O10"));//8
console.log(Number("0X10"));//16
console.log(Number("010"));//10
console.log(010);//非严格模式8 严格模式报错
console.log(0O10);//8
//Number中的特殊值转换
Number( "a" ); // NaN
Number( "" ); // 0
Number( [] ); // 0
Number( [ "abc" ] ); // NaN
5)ToBoolean
JavaScript 中的值可以分为以下两类:
(5.1) 可以被强制类型转换为 false 的值:
以下这些是假值:
undefined、 null、false、+0、-0 和 NaN、""
(5.2) 其他(被强制类型转换为 true 的值)
假值列表以外的都是真值
var a = new Boolean( false );
var b = new Number( 0 );
var c = new String( "" );
// "false" ,"0" ,"''" ,[] ,{} ,function(){} 也是真值
//a、b、c都是假值对象,但是它们皆为真值
var d = Boolean( a && b && c );//true
//为什么不用下面的方式判断三者的相与,因为js的&&与||实际是选择器运算符
//&&返回第一个假值,||返回第一个真值
var e = a && b && c;//String("") 前者都为真,返回最后一个的值
Boolean(…):
与 String(…) 和 Number(…) 一样,Boolean(…)(不带 new)是显式的 ToBoolean 强
制类型转换.
var a = "0";
var b = [];
var c = {};
var d = "";
var e = 0;
var f = null;
var g;
//Boolean转换 不加new
Boolean( a ); // true
Boolean( b ); // true
Boolean( c ); // true
Boolean( d ); // false
Boolean( e ); // false
Boolean( f ); // false
Boolean( g ); // false
new Boolean(g);//Boolean对象:__proto__: Boolean
//[[PrimitiveValue]]: false
//下面这种方式更常用
!!a; // true
!!b; // true
!!c; // true
!!d; // false
!!e; // false
!!f; // false
!!g; // false
//建议使用 Boolean(a) 和 !!a 来进行显式强制类型转换。