美文网首页
js的类型转换

js的类型转换

作者: Super曲江龙Kimi | 来源:发表于2019-07-25 22:54 被阅读0次

js类型转换

1 用于类型转换的valueOf和toString

  • valueOf()的意义是,返回这个对象逻辑上对应的原始类型的值。比如说,String包装对象的valueOf(),应该返回这个对象所包装的字符串。
  • toString()的意义是,返回这个对象的字符串表示。用一个字符串来描述这个对象的内容。

基本类型的valueOf会返回自身的原始类型,而Array、Function、Object都返回自身,Date返回时间戳,Error和Math没有valueOf方法

2 用于检测类型的四个js内部方法

这4个方法实际上是ECMAScript定义的4个抽象的操作,它们在js内部使用,进行类型转换。我们js的使用者不能直接调用这些函数,但是了解这些函数有利于我们理解js类型转换的原理。

  • ToPrimitive ( input [ , PreferredType ] )
  • ToBoolean ( argument )
  • ToNumber ( argument )
  • ToString ( argument )

请区分这里的ToString()和上文谈到的toString(),一个是js引擎内部使用的函数,另一个是定义在对象上的函数。

ToPrimitive ( input [ , PreferredType ] )

将input转化成一个原始类型的值。PreferredType参数要么不传入,要么是Number 或 String。如果PreferredType参数是Number,ToPrimitive这样执行:

  1. 如果input本身就是原始类型,直接返回input。
  2. 调用input.valueOf(),如果结果是原始类型,则返回这个结果。
  3. 调用input.toString(),如果结果是原始类型,则返回这个结果。
  4. 抛出TypeError异常。

以下是PreferredType不为Number时的执行顺序。

  • 如果PreferredType参数是String,则交换上面这个过程的第2和第3步的顺序,其他执行过程相同。
  • 如果PreferredType参数没有传入
    • 如果input是内置的Date类型,PreferredType 视为String
    • 否则PreferredType 视为 Number -- 先调用valueOf 再调用toString

Date 转换的时候PreferredType 视为String先调用toString。所以console.log(111 + new Date()) // "111Thu Jul 25 2019 22:34:51 GMT+0800 (中国标准时间)"

可以看出,ToPrimitive依赖于valueOf和toString的实现。

toPrimitive.jpg

ToBoolean ( argument )

Argument Type Result
Undefined Return false
Null Return false
Boolean Return argument
Number 仅当argument为 +0, -0, or NaN时, return false; 否则一律 return true
String 仅当argument是空字符串(长度为0)时, return false; 否则一律 return true
Symbol Return true
Object Return true

这些规定都来自ECMA的标准,在条件判断时,除了 undefined, null, false, NaN, '', 0, -0,其他所有值都转为 true,包括所有对象。

ToNumber ( argument )

Argument Type Result
Undefined Return NaN
Null Return +0
Boolean 如果 argument 为 true, return 1. 如果 argument 为 false, return +0
Number 直接返回argument
String 将字符串中的内容转化为数字(比如"23"->23),如果转化失败则返回NaN(比如"23a"->NaN)
Symbol 抛出 TypeError 异常
Object primValue = ToPrimitive(argument, Number),再对primValue 使用 ToNumber(primValue)

由上表可见ToNumber的转化并不总是成功,有时会转化成NaN,有时则直接抛出异常。

所以Number([1,2]) -> 先由ToPrimitive(argument, Number)转换[1,2] -> valueOf返回本身,再调用toString返回'1,2' -> 再ToNumber(primValue) 转换为NaN

ToString ( argument )

Argument Type Result
Undefined Return "undefined"
Null Return "null"
Boolean 如果 argument 为 true, return "true".如果 argument 为 false, return "false"
Number 用字符串来表示这个数字
String 直接返回 argument
Symbol 抛出 TypeError 异常
Object 先primValue = ToPrimitive(argument, hint String),再对primValue使用ToString(primValue)
2.png

3 隐式类型转换(自动类型转换)

当js期望得到某种类型的值,而实际在那里的值是其他的类型,就会发生隐式类型转换。系统内部会自动调用我们前面说ToBoolean ( argument )、ToNumber ( argument )、ToString ( argument ),尝试转换成期望的数据类型。

例子1:

if ( !undefined
  && !null
  && !0
  && !NaN
  && !''
) {
  console.log('true');
} // true

例子1:因为在if的括号中,js期望得到boolean的值,所以对括号中每一个值都使用ToBoolean ( argument ),将它们转化成boolean。

例子2:

3 * { valueOf: function () { return 5 } };  //15

例子2:因为在乘号的两端,js期望得到number类型的值,所以对右边的那个对象使用ToNumber ( argument ),得到结果5,再与乘号左边的3相乘。

例子3:

> function returnObject() { return {} }
> 3 * { valueOf: function () { return {} }, toString: function () { return {} } }
// TypeError: Cannot convert object to primitive value

例子3:调用ToNumber ( argument )的过程中,调用了ToPrimitive ( input , Number ),因为在ToPrimitive中valueOf和toString都没有返回原始类型,所以抛出异常。

加法

符号'+'是一个比较棘手的一个符号,因为它既可以表示“算数加法”,也可以表示“字符串拼接”。
简单理解版本:只要'+'两端的任意一个操作数是字符串,那么这个'+'就表示字符串拼接,否则表示算数加法。

12+3
// 15
12+'3'
// "123"

原理理解版本:根据ECMAScript的定义,对'+'运算的求值按照以下过程:

  1. 令lval = 符号左边的值,rval = 符号右边的值
  2. 令lprim = ToPrimitive(lval),rprim = ToPrimitive(rval)
    • 如果lprim和rprim中有任意一个为string类型,将ToString(lprim)和ToString(rprim)的结果做字符串拼接
  • 否则,将ToNumber(lprim)和ToNumber(rprim)的结果做算数加法

根据这个原理可以解释

[]+[]
//  ""
// 提示:ToPrimitive([])返回空字符串

[] + {}
//  "[object Object]"
//  提示:ToPrimitive({})返回"[object Object]"

123 + { toString: function () { return "def" } }
//  "123def"
//  提示:ToPrimitive(加号右边的对象)返回"def"

{} + []
//  0
// 结果不符合我们的预期:"[object Object]"
// 提示:在Chrome中,符号左边的{}被解释成了一个语句块,而不是一个对象
// 注意在别的执行引擎上可能会将{}解释成对象
//  这一行等价于'+[]'
// '+anyValue'等价于Number(anyValue)

({}) + []
//  "[object Object]"
// 加上括号以后,{}被解释成了一个对象,结果符合我们的预期了

另外对于加法还需要注意这个表达式 'a' + + 'b'

'a' + + 'b' // -> "aNaN"

因为 + 'b' 等于 NaN,所以结果为 "aNaN",你可能也会在一些代码中看到过 + '1' 的形式来快速获取 number 类型。相当于调用ToNumber方法

比较运算符

  1. 如果是对象,就通过 toPrimitive 转换对象
  2. 如果是字符串,就通过 unicode 字符索引来比较 '23' < '3' // true
let a = {
  valueOf() {
    return 0
  },
  toString() {
    return '1'
  }
}
a > -1 // true

== 双等

xy都为Null或undefined,return true; 一方为Null或undefined,return false
x或y为NaN, return false;
如果x和y为String,Number,Boolean并且类型不一致,都转为Number再进行比较
如果存在Object,转换为原始值,再比较

"0" == null; // false
"0" == undefined; // false
"0" == false; // true !
"0" == NaN; // false
"0" == 0; // true
"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
2 == [2] // true
"" == [null] // true

4 显式类型转换(强制类型转换)

程序员显式调用Boolean(value)、Number(value)、String(value)完成的类型转换,叫做显示类型转换。
我们在文章的前面说过new Boolean(value)、new Number(value)、new String(value)传入各自对应的原始类型的值,可以实现“装箱”——将原始类型封装成一个对象。其实这三个函数不仅仅可以当作构造函数,它们可以直接当作普通的函数来使用,将任何类型的参数转化成原始类型的值:

Boolean('sdfsd');  //  true
Number("23");  //  23
String({a:24});  //  "[object Object]"

其实这三个函数用于类型转换的时候,调用的就是js内部的ToBoolean ( argument )、ToNumber ( argument )、ToString ( argument )方法!
Number()比parseInt parseFloat严格。parseInt parseFloat会只截取数字转换

这里解释一下String({a:24}); // "[object Object]"的过程:

  • 执行String({a:24})
    • 执行js内部函数ToString ( {a:24} )
      • 执行primValue = ToPrimitive({a:24}, hint String)
        1. 因为{a:24}不是原始类型,进入下一步。
        2. 在ToPrimitive内调用({a:24}).toString(),返回了原始值"[object Object]",因此直接返回这个字符串,ToPrimitive后面的步骤不用进行下去了。
      • primValue被赋值为ToPrimitive的返回值:"[object Object]"
      • 执行js内部函数ToString ( "[object Object]" ),返回"[object Object]"
      • 返回"[object Object]"
    • 返回"[object Object]"
  • 返回"[object Object]"

为了防止出现意料之外的结果,最好在不确定的地方使用显式类型转换

let obj2 = {
    valueOf() {
        return 2
    },
    toString(){
        return []
    }
}
String(obj2)  // '2'
2 + obj2   // 4

当然你也可以重写 Symbol.toPrimitive ,该方法在转原始类型时调用优先级最高。

let a = {
  valueOf() {
    return 0
  },
  toString() {
    return '1'
  },
  [Symbol.toPrimitive]() {
    return 2
  }
}
1 + a // => 3

parseInt()
parseInt只会转换字符串。如果传入的不是字符串会先转换成字符串再进行parse。

let obj = {
    valueOf:function() {return '2px'},
    toString: function() {return []}
}
parseInt(obj)  // 2  如果不是字符串会先根据ToString规则转换成字符串。再去转换

parseInt(1/0, 19) // 18  => 1/0转换成字符串为Infinity 。而有效数字范围是0-9 a-i 所以第一位为I 代表18。n超出19的范围了所以只有18返回
parseInt(0.0000008) // 8 => 8e+7  6个0转换成字符串会转换成指数
parseInt(0.000008) // 0 => 0.000008 
parseInt(false, 16) // 250 => 'false' => 'fa'在16进制下有效
parseInt(function(){...}, 16) // 15 => 'f'在16进制下有效

如果不填写第二个参数,则会根据传入的值来判断是什么进制,填写了代表转换成多少进制

parseInt('0x10')  // 16
parseInt('103', 2)  // 2

JSON.stringify()

JSON.stringify() 遇到undefined、function、symbol会自动将其忽略。如果在数组中会返回null占位

JSON.stringify(undefined); // undefined
JSON.stringify(function() {}); // undefined
JSON.stringify([undefined, function(){}, 2 ]);  // [null, null, 2]
JSON.stringify({ a:undefined, b:function(){} });  // {}

如果对象中自定义了toJson方法,那么在使用JSON.stringify()时会先调用toJson方法,然后再去stringify

tip:

  1. ~运算符可以表示 -(x+1) : ~2 => -3 ~-1 => 0 根据这个特性。可以对-1进行特殊判断。比如indexof时 。if( ~a. indexof('bbb') ) 表示如果是-1就会返回false。
  2. 3.2 | 0 => 3; -6.7 | 0 => -6
    Object.create(null)没有valueOf和toString方法,因此无法进行强制类型转换

相关文章

  • javaScript中数据类型转换方法

    JS 数据类型转换 方法主要有三种 转换函数、强制类型转换、利用js变量弱类型转换。 1. 转换函数: js提供了...

  • 数据类型转换

    JS 数据类型转换 方法主要有三种 转换函数、强制类型转换、利用js变量弱类型转换。 1. 转换函数: js提供了...

  • JavaScript类型转换

    在js中数据类型转换一般分为两种,即强制类型转换和隐式类型转换(利用js弱变量类型转换)。 强制类型转换 即通过使...

  • 前端开发入门到实战:JavaScript字符串转换数字

    js 字符串转换数字方法主要有三种: 转换函数、强制类型转换、利用js变量弱类型转换。 1. 转换函数: js提供...

  • 前端开发入门到实战:JavaScript字符串转换数字

    js 字符串转换数字方法主要有三种: 转换函数、强制类型转换、利用js变量弱类型转换。 1. 转换函数: js提供...

  • js中的类型转换

    在js中数据转换分为3种:隐式类型转换,强制类型转换,函数转换 1.隐式类型转换 (1):运算符转换 js中的值在...

  • JavaScript字符串转换数字

    这里记录js 字符串转换数字的三种主要方法: 转换函数、强制类型转换、利用js变量弱类型转换。 1. 转换函数: ...

  • js中parseInt()与parseFloat(),Numb

    js将字符串转数值的方法主要有三种 转换函数、强制类型转换、利用js变量弱类型转换。 1. 转换函数: js提供了...

  • JS类型转换

    方法主要有三种 转换函数、强制类型转换、利用js变量弱类型转换。 1. 转换函数: js提供了parseInt()...

  • js关于字符串和数字的转换

    js字符串转换成数字 js 字符串转换数字方法主要有三种:转换函数、强制类型转换、利用JS变量弱类型特点进行转换 ...

网友评论

      本文标题:js的类型转换

      本文链接:https://www.haomeiwen.com/subject/smvhrctx.html