Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

彻底搞懂类型转换 #22

Open
Saikikoko opened this issue Mar 8, 2021 · 0 comments
Open

彻底搞懂类型转换 #22

Saikikoko opened this issue Mar 8, 2021 · 0 comments
Labels
Js knowledge of Javascript
Projects

Comments

@Saikikoko
Copy link
Owner

Saikikoko commented Mar 8, 2021

整理一波类型转换

普通类型转换

普通类型转布尔类型

类型 结果
null false
undefined false
Number NaN,+0,-0为false,其他都为true
String ""为false,其他都为true

普通类型转数字

类型
null 0
undefined NaN
Boolean false为0,true为1
String 见下
Number('123') // 123
Number('-123') // -123
Number('1.2') // 1.2
Number('000123') // 123
Number('-000123') // -123
Number('a123') // NaN 有一个不为数字就为NaN
Number('0x12') // 16进制转换为10进制整数
Number('') // 0
Number('  ') // 0
Number('123 123') // NaN

Number 转换函数传入一个字符串,它会试图将其转换成一个整数或浮点数,而且会忽略所有前导的 0,如果有一个字符不是数字,结果都会返回 NaN

普通类型转字符串

类型 结果
null 'null'
undefined 'undefined'
Number '123'
Boolean 'false', 'true'
String(0) // "0"
String(-0) // "0"

普通类型转对象

我们发现对于String、Number、Boolean类型的变量,我们可以使用.运算符对它们进行操作,例如

var a = 1
a.name = '123'

这时候操作的是它们的包装对象,没有任何影响,但是null和undefined在期望把它们当成对象操作时,则会报错TypeError

对象转换为普通类型

对象转布尔值

所有对象转换布尔值结果都为true

对象转换为数字或字符串

调用valueOf和toString方法进行转换

对象调用toString的几种不同情况:

  1. 数组:返回数组元素用','拼接的结果
  2. 函数:返回函数的字符串
  3. 对象:返回“[object object]”
  4. Regex: 返回表示正则表达式直接量的字符串
  5. Date:返回可读的日期和时间字符串
console.log(({}).toString()) // [object Object]
console.log([].toString()) // ""
console.log([0].toString()) // 0
console.log([1, 2, 3].toString()) // 1,2,3
console.log((function(){var a = 1;}).toString()) // function (){var a = 1;}
console.log((/\d+/g).toString()) // /\d+/g
console.log((new Date(2010, 0, 1)).toString()) // Fri Jan 01 2010 00:00:00 GMT+0800 (CST)

valueOf方法通常返回对象本身,但是日期对象是个例外,他返回从1970年到现在经历的毫秒数

从对象到字符串的转换过程

  1. primValue = ToPrimitive(input, String)
  2. 返回ToString(primValue).
    即先调用ToPrimitive将对象转换为基础类型,再将其转换为字符类型

从对象到数字的转换过程

  1. primValue = ToPrimitive(input, Number)
  2. 返回ToNumber(primValue)。
  3. 即先调用ToPrimitive将对象转换为基础类型,再将其转换为数字类型

ToPrimitive方法

ToPrimitive(input[, PreferredType])

第一个参数是 input,表示要处理的输入值。

第二个参数是 PreferredType,非必填,表示希望转换成的类型,有两个值可以选,Number 或者 String。

当不传入 PreferredType 时,如果 input 是日期类型,相当于传入 String,否则,都相当于传入 Number。

如果传入的 input 是 Undefined、Null、Boolean、Number、String 类型,直接返回该值。

如果是 ToPrimitive(obj, Number),处理步骤如下:

  1. 如果 obj 为 基本类型,直接返回
  2. 否则,调用 valueOf 方法,如果返回一个原始值,则 JavaScript 将其返回。
  3. 否则,调用 toString 方法,如果返回一个原始值,则 JavaScript 将其返回。
  4. 否则,JavaScript 抛出一个类型错误异常。

如果是 ToPrimitive(obj, String),处理步骤如下:

  1. 如果 obj为 基本类型,直接返回
  2. 否则,调用 toString 方法,如果返回一个原始值,则 JavaScript 将其返回。
  3. 否则,调用 valueOf 方法,如果返回一个原始值,则 JavaScript 将其返回。
  4. 否则,JavaScript 抛出一个类型错误异常。----摘自冴羽大佬的JavaScript深入系列

总结一下:
对象转字符串:

  1. 调用toString方法,如果对象有自带调用自带的,否则调用原型上的,如果返回的是一个基础类型的值,则跳过2,直接进入步骤3,否则进入步骤2
  2. 调用valueOf方法,如果对象有自带调用自带的,否则调用原型上的,如果返回的是一个基础类型的值,则进入步骤3,否则抛出一个类型错误
  3. 调用内部的ToString方法,即将基础类型转换为字符串的过程

对象转数字:

  1. 调用valueOf方法,如果对象有自带调用自带的,否则调用原型上的,如果返回的是一个基础类型的值,则跳过2,直接进入步骤3,否则进入步骤2
  2. 调用toString方法,如果对象有自带调用自带的,否则调用原型上的,如果返回的是一个基础类型的值,则进入步骤3,否则抛出一个类型错误
  3. 调用内部的ToNumber方法,即将基础类型转换为数字的过程
const obj = {
  name: '123',
  valueOf() {
    return {}
  },
  toString() {
    return {}
  }
}
console.log(String(obj)) // 报错

// 上面注释掉
const obj1 = {
  name: '123',
  valueOf() {
    return '456'
  },
}
console.log(Number(obj1)) // 456

// 上面注释掉
const obj2 = {
  name: 12,
  toString() {
    return 'nb'
  }
}
console.log(String(obj2)) // nb
Number({}) // NaN

上述过程为首先调用valueOf返回{}本身,然后调用toStirng返回[object object],然后转换为数字,得到结果为NaN

运算符中的类型转换

一元运算符+

一元运算符+会把变量类型隐式转换为Number类型

console.log(+[]); // 0
console.log(+['1']); // 1
console.log(+['1', '2', '3']); // NaN
console.log(+{}); // NaN

二元操作符+

当计算 value1 + value2时:

  1. lprim = ToPrimitive(value1)
  2. rprim = ToPrimitive(value2)
  3. 如果 lprim 是字符串或者 rprim 是字符串,那么返回 ToString(lprim) 和 ToString(rprim)的拼接结果
  4. 返回 ToNumber(lprim) 和 ToNumber(rprim)的运算结果----摘自冴羽大佬的JavaScript深入系列

==值比较

==比较两个值时,也会发生类型转换
ES5规范中:
当执行x == y 时:

  1. 如果x与y是同一类型:
    1. x是Undefined,返回true
    2. x是Null,返回true
    3. x是数字:
      1. x是NaN,返回false
      2. y是NaN,返回false
      3. x与y相等,返回true
      4. x是+0,y是-0,返回true
      5. x是-0,y是+0,返回true
      6. 返回false
    4. x是字符串,完全相等返回true,否则返回false
    5. x是布尔值,x和y都是true或者false,返回true,否则返回false
    6. x和y指向同一个对象,返回true,否则返回false
  2. x是null并且y是undefined,返回true
  3. x是undefined并且y是null,返回true
  4. x是数字,y是字符串,判断x == ToNumber(y)
  5. x是字符串,y是数字,判断ToNumber(x) == y
  6. x是布尔值,判断ToNumber(x) == y
  7. y是布尔值,判断x ==ToNumber(y)
  8. x是字符串或者数字,y是对象,判断x == ToPrimitive(y)
  9. x是对象,y是字符串或者数字,判断ToPrimitive(x) == y
  10. 返回false

看了一下其实只需记住以下几种情况:
当二者类型相同时:
基础类型:当二者值完全相同时才相同,但是有几个例外

+0 == -0 // true
NaN == NaN // false

引用类型:引用的地址相同时为true

当二者(x和y)类型不同时:x == y , y == x

  1. nullundefined比较,值为true,否则进行步骤2~5
  2. 当x为数字,y为字符串时(或y为数字,x为字符串)则将y先转换为数字,再进行比较(x == ToNumber(y))
  3. 当x(或y)为布尔类型时,则先将x转换为数字,再进行比较(ToNumber(x) == y)
  4. 当x为对象,y为字符串或者数字(或y为对象,x为字符串或数字)时,则先将x转换为基础类型,再进行比较(ToPrimitive(x) == y)
  5. 其余情况都为false
[] == ![] // true

上面过程,首先进行![]转换,结果为false,符合规范中的第七条,所以将false转换为0,比较[] == 0,此时符合规范中的第9条,将[]转换为基础类型'',此时满足规范中的第5条,'' == 0,将''转换为数字为0,所以最终结果为true

@Saikikoko Saikikoko added the Js knowledge of Javascript label Mar 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Js knowledge of Javascript
Projects
JavaScript
Awaiting triage
Development

No branches or pull requests

1 participant