valueof 和toString
var a = new String( "abc" );的值应当是什么。
a是一个对象。一个基本类型值的封装对象。
typeof a; // 是"object",不是"String"
a instanceof String; // true
Object.prototype.toString.call( a ); // "[object String]"
通过构造函数(如 new String("abc"))创建出来的是封装了基本类型值(如 "abc")的封 装对象。
我们比较准确的判断一个类型的方法为
Object.prototype.toString(..)
这是因为所有 typeof 返回值为 "object" 的对象,都有一个内部属性 [[Class]],这个属性无法直接访问,一般通过
Object.prototype.toString(..)
来查看,一般对象的内部 [[Class]] 属性和创建该对象的内建原生构造函数相对应。除了null 和 undefined,因为
Object.prototype.toString.call( null ); // "[object Null]"
Object.prototype.toString.call( undefined ); // "[object Undefined]"
虽然 Null() 和 Undefined() 这样的原生构造函数并不存在,但是内部 [[Class]] 属性值仍 然是 "Null" 和 "Undefined"。我们至少可以准确判断出类型。
为什么 "abc" 可以有.length等属性?
封装对象(object wrapper)扮演着十分重要的角色。由于基本类型值没有 .length 和 .toString() 这样的属性和方法,需要通过封装对象才能访问,此时 JavaScript 会自动为 基本类型值包装(box 或者 wrap)一个封装对象:
一般情况下,我们不需要直接使用封装对象。最好的办法是让 JavaScript 引擎自己决定什 么时候应该使用封装对象。换句话说,就是应该优先考虑使用 "abc" 和 42 这样的基本类型 值,而非new String("abc")和new Number(42)。
如果想要得到封装对象中的基本类型值,可以使用 valueOf() 函数:
var a = new String( "abc" );
var b = new Number( 42 );
var c = new Boolean( true );
a.valueOf(); // "abc"
b.valueOf(); // 42
c.valueOf(); // true
在需要用到封装对象中的基本类型值的地方会发生隐式拆封。因为没有new Null()
和new Undefined()
这样的封装器,也就是说他们是没有对应的封装对象。从而没有对应的valueOf()
。
var str1 = 'w3cplus';
var str2 = new String('w3cplus');
typeof(str1); // => string
typeof(str2); // => object
str1 == str2 // => true
str1
是一个String
类型,而str2
却是一个Object
类型,但用==
比较两个变量时,结果却为true
。这是因为,在JavaScript中会帮我们自动转换类型,然后再进行比对。
String(),new String(), toString() 区别
toString()
和String()
的主要区别就在于
String()
还能转换null
和undefined
值,也可以说String()
是toString()
增强版,在开发中直接使用String()
似乎更好,这样能避免潜在的转换风险。
toString()和valueOf()作用差不多,都是转换成原始类型的值。
valueOf():返回最适合该对象类型的原始值;
toString(): 将该对象的原始值以字符串形式返回。
这两个方法一般是交由JS去隐式调用,以满足不同的运算情况。
在数值运算里,会优先调用valueOf(),如a + b;
在字符串运算里,会优先调用toString(),如alert(c)。
在JavaScript进行对比或者各种运算的时候会把对象转换成Number、String、Boolean这些类型,从而进行后续的操作
String转换
在某个操作或者运算需要字符串的时候,往往会触发Object的String转换
var obj={name:'Mofei'}
var str = ' ' + obj
console.log(str); // [object Object]
上述的例子中,在字符串相加的过程中,系统调用了obj的String转换,具体规则如下:
- 如果toString方法存在并且返回“原始类型”,返回toString的结果。
- 如果toString方法不存在或者返回的不是“原始类型”,调用valueOf方法,如果valueOf方法存在,并且返回“原始类型”数据,返回valueOf的结果。
- 其他情况,抛出错误。
Number转换
当需要使用Number时,( 如Math.sin() )等,解释器会尝试将对象转换成Number对象。
通常有如下的情况会触发Number转换
- 方法参数需要Number的时候,如Math.sin(obj)等
- 对比的时候,如 obj == 'abc'
- 运算的时候,如 obj + 123
转换规则如下:
- 如果valueOf存在,且返回“原始类型”数据,返回valueOf的结果。
- 如果toString存在,且返回“原始类型”数据,返回toString的结果。
- 报错。
Boolean转换
在进行布尔比较的时候,比如 if(obj) , while(obj)等等,会进行布尔转换,布尔转换遵循如下规则:
值 | 布尔值 |
---|---|
true/false | true/false |
undefined,null | false |
Number | 0,NaN 对应 false, 其他的对应 true |
String | ""对应false,其他对应true('0'对应的是true) |
Object | true |
JavaScript 对象转换,toString,valueOf
valueOf()原生实现
数据类型 | 返回值 |
---|---|
Array | 与 Array.toString 和 Array.join 方法相同 |
Function | 函数本身 |
Date | 毫秒数UTC |
Boolean | 布尔值 |
Number | 数字值 |
String | 字符串值 |
Object | 对象本身 |
toString()原生实现 返回的值全部为字符串
数据类型 | 返回值 |
---|---|
Array | 与 Array.valueOf 和 Array.join 方法相同 |
Function | 获取函数源代码 |
Object | 返回[object type] |
Boolean | 布尔值 |
Date | 格式化日期 |
String | 字符串值 |
Number | 数字值,可以携带进制参数 |
隐式数据转换即为解释器自发根据需要调用Number(),Boolean()等基本类型转换函数使结果符合期待。若参数为object类型时,调用ToPrimitive()(假想函数),该函数根据需要的数据类型做出的反应也不同,若在使用操作符运算时需要number类型则优先调用valueOf(),结果为NaN再调用toString()。其他大部分情况需要string类型则优先调用toString()。
toString()和valueOf()的主要不同点在于
1、 toString()返回的是字符串,而valueOf()返回的是基本类型值
2、由于undefined和null不是对象,所以它们toString()和valueOf()两个方法都没有
3、数值Number类型的toString()方法可以接收转换基数,返回不同进制的字符串形式的数值;而valueOf()方法无法接受转换基数
4、时间Date类型的toString()方法返回的表示时间的字符串表示;而valueOf()方法返回的是现在到1970年1月1日00:00:00的数值类型的毫秒数
5、包装对象的valueOf()方法返回该包装对象对应的原始值
6、使用toString()方法可以区分内置函数和自定义函数
如果只重写了toString,对象转换时会无视valueOf的存在来进行转换。如果只重写了valueOf方法,在要转换为字符串的时候会优先考虑toString方法。在不能调用toString的情况下,只能让valueOf上阵了。