【javascript基础】toString、valueOf、转换 【译】

js中的对象可以被转换成以下3个基本数据类型:

1、Nunber

2、String

3、Boolean

对上述转换的理解,我们可以绕过缺陷,并写出更整洁的代码。

一、字符转换

      当需要一个对象的字符表示时候,将发生字符传唤。

e.g.在alert中输出obj

var obj = { name: 'John' }

alert(obj) // [object Object]

      当然,也可以显示转换,String(obj);

对象转换成字符串的逻辑 

      对象转换成字符串的逻辑如下:

               1、如果对象有toString方法,则调用该方法,并返回相应的结果;

                PS:代码通常会执行到这,因为在所有对象中都有toString方法。

               2、如果对象有valueOf方法,则调用该方法,并返回相应的结果;

               3、否则抛出异常。

      通常,所有对象toString方法,内置对象都有自己toString实现:

       e.g.

alert( {key: 'value'} ) // toString for Objects outputs: [object Object]
alert( [1,2] )          // toString for Arrays lists elements "1,2" 
alert( new Date )       // toString for Dates outputs the date as a string
自定义toString

e.g.

var user = {

  firstName: 'John',

  toString: function() {
    return 'User ' + this.firstName 
  }
}

alert( user )  // User John
二、数字转换

在JavaScript中还有另一种转换,虽然没有toString用的广泛 ,但在JS引擎内部,用得更频繁。

数字转换的两种主要情况:
1、函数需要数字,e.g.: Math.sin(obj) isNaN(obj)包括算术运算符: +obj

2、用于比较,e.g. obj == 'John'

PS:下面两种比较不会发生类型转换,

      a)在严格比较(===)中,不会发生任何的类型转换,

      b)在非严格比较中,如果参数都是对象,不会发生类型转换,通常,如果两个对象引用统一对象,则返回true.

也可以通过显式转换Number(obj)
对象转换成数字的逻辑 

     步骤 如下:

               1、如果对象有valueOf方法,则调用该方法,并返回相应的结果;

               2、否则如果对象有toString方法,则调用该方法,并返回相应的结果;

               3、否则抛出异常。

在内置对象,Date支持数字和字符串转换 :

alert( new Date() ) // The date in human-readable form
alert( +new Date() ) // Microseconds till 1 Jan 1970
但大多数的对象没有valueOf , 这意味着数字转换基本上调用toString方法
自定义valueOf

e.g.

var room = { 

  num: 777,

  valueOf: function() {
    return this.num
  }
}

alert( +room )  // 777
如果对象中没有valueOf方法,将会调用toString方法
var room = { 

  num: 777,

  toString: function() {
    return this.num
  }
}

alert( room / 3 )  // 259
 
数字转换

数字转换并不意味着必须返回一个数字,但必须是以一个基本的数据类型,但它的具体类型没有任何限制。

因此,将对象转换成数字的一个很好的办法是:通过+操作符实现

e.g.

var arr = [1,2,3]

alert( arr + '' ) 
// first tries arr.valueOf(), but arrays have no valueOf
//
 so arr.toString() is called and returns a list of elements: '1,2,3'
由于历史的原因, new Date + ''也返回一个Date字符串形式,即使new Date也有valueOf方法 。 这是一个例外。
其他的数学函数不仅进行数字转换,强制转换成一个数字。 例如一元加法+arr会给NaN
alert( +[1,2,3] ) // [1,2,3] -> '1,2,3' -> not a number


全等/比较测试中的转换

 非严格比较,将比较以数字比较。

当一个参数是基本类型的时候,对象将被强制转换,

 e.g.

if (obj == true) { ... }
如果参数都是对象,不会发生类型转换,通常,如果两个对象引用统一对象,则返回true.

下面的比较将会被转化为基本类型

var a = { 
  valueOf: function() { return  1 }
}
var b  = { 
  valueOf: function() { return  0 }
}

alert( a > b )  // 1 > 0, true

下面的为什么会返回true

alert( ['x'] == 'x' )

 解决方案:

左边是数组,右边是基本类型,因此数组将被数字转换,由于数组没有valueOf方法,于是调用toString方法,

alert( ['a','b'] + '' )   // 'a,b'

 PS:

下面的同样的逻辑

['x','y'] == 'x,y'
[] == ''

 

二、布尔值转换
还有一个标准的JavaScript的转换,在ecmascript262规范中称为[[toBoolean]]

如果发生在布尔上下文中,如if(obj) while(obj)等。

对象可能无法实现自己的这种转换,也没有其他特殊的方法。 相反,有一个硬编码的换算表:

PS:不像其他的编程语言,比如PHP,'0'在JS中返回的是true

在下面的例子中发生数字转换

alert( [0] == 0 )  // true
alert( "\n0\n" == 0 ) // true
alert( "\n0\n" == false ) // true
因此,人们可能会猜测, [0]"\n0\n"是false,因为他们等于0
但现在让我们来看看左侧部分在布尔上下文中的是如何的:
 
if ([0]) alert(1)  // 1, if treats [0] as true
if ("\n0\n") alert(2) // 2, if treats "\n0\n" as true
 
 
这是可能的, a == b ,但在布尔上下文中, atruebfalse
想想,下面为什么会相等
alert( [] == ![] ) // true


 解决:

1、对两边求值,右边是![],将会被转换成一个布尔值,true,算完之后,表达式变成:

[]==false;

2、左边是数组,右边是布尔值,按照规则,将false转换成0,数组也将进行数字转换,转换为0

0 == 0;;;;;;

 3、结果很显然了

 

 计算下下面表达式,完成时,看下下面的解决办法:

6 / "3"
"2" * "3"
4 + 5 + "px"
"$" + 4 + 5

"4" - 2

"4px" - 2

7 / 0

{}[0]

parseInt("09")

5 && 2

2 && 5

5 || 0

0 || 5
6 / "3" = 2
"2" * "3" = 6
4 + 5 + "px" = "9px"
"$" + 4 + 5
 = "$45"
"4" - 2
 = 2
"4px" - 2
 = NaN
7 / 0
 = Infinity
{}[0]
 = undefined
parseInt("09")
 = "0" or "9" // octal or decimal, depends on the browser
5 && 2
 = 2
2 && 5
 = 5
5 || 0
 = 5
0 || 5 = 5

总结

在JavaScript中有三个转换,这取决于具体情况:

  1. 字符串输出,使用toString
  2. 数字:数学函数,操作符,使用valueOf 后使用 toString
  3. 布尔值:根据下表转换。

这是不同于大多数其他编程语言,当你了解之后,其实很简单。

最准确的转换算法,参考规范:ECMA-262第五版,特别是11.8.5(关系比较),和11.9.3(相等比较)和9.1(toPrimitive)和9.3(toNumber)。

参考:

Conversion, toString and valueOf  http://javascript.info/tutorial/object-conversion

原文地址:https://www.cnblogs.com/sniper007/p/2777378.html