[译]隐式转型,你值得掌握

前几天忽然发现github上有一个大热门项目 —— “33 concepts every JavaScript developer should know”,目前已经将近25000个Stars。这个项目旨在帮助前端开发者掌握33个JavaScript基础概念。按作者话说,这些概念并不是开发所必需的,但它们是引导你通向前端大牛之路的基石。

遗憾的是,该项目中文版的文章收录不尽完整。所以本着学习与交流的目的,本人会把33个概念所涉及的文章利用业余时间竭尽所能的翻译出来,其中不免疏漏,望请指正。本文是第四篇,以下为正文:


隐式转型是指,JavaScript会把一个非预期值转换为预期值。

什么意思呢?

在一定条件下,你能够把一个字符串当作数值使用,也能够把一个对象当作字符串使用,这些类型能够发生转换,以满足你的预期。然而,我们应尽量避免JavaScript的这一语言特性。

3 * "3" //9
1 + "2" + 1 //121

true + true //2
10 - true //9


const foo = {
  valueOf: () => 2
}
3 + foo // 5
4 * foo // 8

const bar = {
  toString: () => " promise is a boy :)"
}
1 + bar // "1 promise is a boy :)"


4 * [] // 0
4 * [2] // 8
4 + [2] // "42"
4 + [1, 2] // "41,2"
4 * [1, 2] // NaN

"string" ? 4 : 1 // 4
undefined ? 4 : 1 // 1
复制代码

数字表达式中的非数值

字符串

当一个字符串参与到数学运算中来时,如涉及以下四种运算:-*/%,则相当于为该字符串调用了内置的Number()函数。这很容易理解,任何包含数字的字符串都会转换为数字,对于含有非数字字符的,则返回NaN,具体参考Number()转换规则。示例如下:

3 * "3" // 3 * 3
3 * Number("3") // 3 * 3
Number("5") // 5

Number("1.") // 1
Number("1.34") // 1.34
Number("0") // 0
Number("012") // 12

Number("1,") // NaN
Number("1+1") // NaN
Number("1a") // NaN
Number("one") // NaN
Number("text") // NaN
复制代码

+”操作符是个例外

不像其它数学运算符,“+”表现出两种特性:

  1. 加法
  2. 字符串拼接

字符串参与“+”操作时,JavaScript不再把字符串转为数字,反会将数字转为字符串。

// 字符串拼接
1 + "2" // "12"
1 + "js" // "1js"

// 加法运算
1 + 2 // 3
1 + 2 + 1 // 4

// 先加法,再拼接
1 + 2 + "1" // "31"
(1 + 2) + "1" // "31"

// 全部拼接
1 + "2" + 1 // "121"
(1 + "2") + 1 // "121"
复制代码

对象

JavaScript中大多数对象都会转换为“[object Object]”,比如:

"name" + {} // "name[object Object]
复制代码

每个JavaScript都会继承toString()方法,这就说明无论何时,对象度能够被转换为字符串。接下来,toString()方法的返回值就会参与到字符串拼接和数学运算中去。

const foo = {}
foo.toString() // [object Object]

const baz = {
  toString: () => "I'm object baz"
}

baz + "!" // "I'm object baz!"
复制代码

对象参与数学运算时,JavaScript会试图将它的返回值转换为数字;字符串拼接时,则转换为字符串。

const foo = {
  toString: () => 4
}

2 * foo // 8
2 / foo // 0.5
2 + foo // 6
"four" + foo // "four4"

const baz = {
  toString: () => "four"
}

2 * baz // NaN
2 + baz // 2four

const bar = {
  toString: () => "2"
}

2 + bar // "22"
2 * bar // 4
复制代码

数组

数组同样继承了toString()方法,然而在工作方式上则略有不同,转换的过程相当于为数组调用了一个没传参的join()方法。

[1,2,3].toString() // "1,2,3"
[1,2,3].join() // "1,2,3"
[].toString() // ""
[].join() // ""

"me" + [1,2,3] // "me1,2,3"
4 + [1,2,3] // "41,2,3"
4 * [1,2,3] // NaN
复制代码

当你把数组当作字符串使用时,JavaScript会将toString()的返回值和另一个值拼接起来;当作数字使用时,返回值则转换为数字。

4 * [] // 0
4 / [2] // 2

// 相当于
4 * Number([].toString())
4 * Number("")
4 * 0

//

4 / Number([2].toString())
4 / Number("2")
4 / 2
复制代码

True, False 和 ""

Number(true) // 1
Number(false) // 0
Number("") // 0

4 + true // 5
3 * false // 0
3 * "" // 0
3 + "" // "3"
复制代码

The valueOf() method```

在JavaScript中,你同样可以定义一个valueOf()方法,它也可以将对象转换为字符串或数值。

const foo = {
  valueOf: () => 3
}

3 + foo // 6
3 * foo // 9
复制代码

toString()valueOf()方法同时在对象中出现时,JavaScript会优先调用valueOf方法。

const bar = {
  toString: () => 2,
  valueOf: () => 5
}

"sa" + bar // "sa5"
3 * bar // 15
2 + bar // 7
复制代码

真和假

JavaScript中的每个值都可以转换为truefalse。转换为true意味着该值为真,反之则为假。

其中有为数不多的值会被转换为false,它们是:

  1. false
  2. 0
  3. null
  4. undefined
  5. NaN
  6. -0

除此以外,所有值都为真。

if (-1) // truthy
if ("0") // truthy
if ({}) // truthy
复制代码

上面的代码正如我们所预期,但是在实践中我们仍应该显式的确定一个值是否为真。总体上,我们应当避免使用隐式转型,即便你认为已将它烂熟于胸了。

下面的代码才是你应该参考使用的:

if (counter === 2)

//or

if (typeof counter === "number")
复制代码

假如,你定义了一个处理数字的函数。

const add = (number) => {
  if (!number) new Error("Only accepts arguments of type: number")
  //your code
}
复制代码

当你调用这个函数,并想传入参数 0 时,函数会给你抛出一个错误。

add(0) // Error: Only accepts arguments of type: number

// 更好的尝试

const add = (number) => {
  if (typeof number !== "number") new Error("只接受数字类型: number")
  //your code
}

add(0) // 这下没错了
复制代码

NaN

NaN 是一个特殊的数值,它与任何值都不相等,包括 NaN 本身

NaN === NaN // false

const notANumber = 3 * "a" // NaN

notANumber == notANumber // false
notANumber === notANumber // false
复制代码

NaN 是JavaScript中唯一一个自己不等于自己的值,你可以利用这个特性来检查NaN

if (notANumber !== notANumber) // true
复制代码

ES6标准引进了一种用来检查 NaN 的新方法 Number.isNaN

Number.isNaN(NaN) // true
Number.isNaN("name") // false
复制代码

使用这个函数时需要注意,它会首先将参数转型,然后才开始检查 NaN,示例如下:

const coerceThenCheckNaN = (val) => {
  const coercedVal = Number(val)
  return coercedVal !== coercedVal ? true : false
}

coerceThenCheckNaN("1a") // true
coerceThenCheckNaN("1") // false
coerceThenCheckNaN("as") // true
coerceThenCheckNaN(NaN) // true
coerceThenCheckNaN(10) // false
复制代码

(完)

下一篇讲述相等操作符和全等操作符,敬请期待

转载于:https://juejin.im/post/5c49b096e51d4504314306b7

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值