Javascript 的隐式强制只是指 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
. 如下图,
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
复制代码
+ 运算符的情况
数学加法
字符串连接
当字符串是 + 运算符的操作数时,Javascript 不是将字符串转换为数字,而是将数字转换为字符串。
// concatenation
1 + "2" // "12"
1 + "js" // "1js"
// addition
1 + 2 // 3
1 + 2 + 1 // 4
//addition, then concatenation
1 + 2 + "1" // "31"
(1 + 2) + "1" // "31"
//concatenation all through
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
Arrays 的继承方法有点不同,它的工作方式类似于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
//similar to
4 * Number([].toString())
4 * Number("")
4 * 0
//
4 / Number([2].toString())
4 / Number("2")
4 / 2
复制代码
真、假和“”
Number(true) // 1
Number(false) // 0
Number("") // 0
4 + true // 5
3 * false // 0
3 * "" // 0
3 + "" // "3"
复制代码
参考视频讲解:进入学习
该valueOf
方法
也可以定义一个valueOf
方法,当您传递一个需要字符串或数字值的对象时,Javascript 将使用该方法。
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
复制代码
valueOf 方法适用于应该表示数值的对象。
const two = new Number(2)
two.valueOf() // 2
复制代码
虚假与真实
我真的想让它变得虚假和真实
每个 Javascript 值都可以被强制为 true 或 false。强制转换为布尔值true
意味着该值是真实的。强制转换为布尔值false
意味着该值为假。
Javascript 中有一些返回假值的值,它们是:
错误的
0
空值
不明确的
“”
NaN
-0
其他的都是真的
if (-1) // truthy
if ("0") // truthy
if ({}) // truthy
复制代码
上面的代码片段是可以的,但是在尝试确定值的真实性时,最好是明确的。基本上,不要依赖 Javascript 的隐式强制,即使您觉得自己非常了解它们。而不是下面的代码片段,
const counter = 2
if (counter)
复制代码
根据您的要求,以下任何一种都是更好的做法
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 函数,我总是会得到一个意想不到的错误
add(0) // Error: Only accepts arguments of type: number
//better check
const add = (number) => {
if (typeof number !== "number") new Error("Only accepts arguments of type: number")
//your code
}
add(0) // no error
复制代码
NaN
NaN
是一个不等于自身的特殊数值。
NaN === NaN // false
const notANumber = 3 * "a" // NaN
notANumber == notANumber // false
notANumber === notANumber // false
复制代码
NaN
是唯一不等于自身的 Javascript 值。因此,您可以NaN
通过将其与自身进行比较来检查。
if (notANumber !== notANumber) // true
复制代码
ECMAScript 6 引入了一种检查 NaN 的方法, Number.isNaN
Number.isNaN(NaN) // true
Number.isNaN("name") // false
复制代码
当心全局isNaN
函数,它会在检查它是否为NaN
. 例如,
isNaN("name") // true
isNaN("1") // false
复制代码
isNaN
应该避免使用全局函数,它的工作方式类似于下面的函数
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
复制代码
这是大部分隐性强制。如果我错过了什么,请在下面的评论中加入,感谢您一路阅读。
评论