valueof 和toString

2018-01-18  本文已影响0人  209bd3bc6844

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()还能转换nullundefined值,也可以说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转换,具体规则如下:

  1. 如果toString方法存在并且返回“原始类型”,返回toString的结果。
  2. 如果toString方法不存在或者返回的不是“原始类型”,调用valueOf方法,如果valueOf方法存在,并且返回“原始类型”数据,返回valueOf的结果。
  3. 其他情况,抛出错误。
Number转换

当需要使用Number时,( 如Math.sin() )等,解释器会尝试将对象转换成Number对象。
通常有如下的情况会触发Number转换

  1. 方法参数需要Number的时候,如Math.sin(obj)等
  2. 对比的时候,如 obj == 'abc'
  3. 运算的时候,如 obj + 123

转换规则如下:

  1. 如果valueOf存在,且返回“原始类型”数据,返回valueOf的结果。
  2. 如果toString存在,且返回“原始类型”数据,返回toString的结果。
  3. 报错。
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上阵了。

上一篇下一篇

猜你喜欢

热点阅读