undefined
转换为 NaN
。
console.log(Number(undefined)); // NaN
null
转换为 0
。
console.log(Number(null)); // 0
true
转换为 1
,false
转换为 0
。
console.log(Number(true)); // 1
console.log(Number(false)); // 0
字符串按照 Number()
函数进行转换。
NaN
。0
。console.log(Number("42")); // 42
console.log(Number("3.14")); // 3.14
console.log(Number("")); // 0
console.log(Number("hello")); // NaN
console.log(Number("42abc")); // NaN
Symbol
值不能转换为数字,会抛出 TypeError
。
let sym = Symbol("desc");
// console.log(Number(sym)); // TypeError: Cannot convert a Symbol value to a number
对象(包括数组)会首先被转换为相应的基本类型值,然后再根据基本类型值的转换规则进行强制转换。步骤如下:
valueOf()
方法。valueOf()
存在并返回基本类型值,则使用该值进行强制类型转换。valueOf()
方法或其返回值不是基本类型,则使用 toString()
方法的返回值进行转换。valueOf()
和 toString()
均不返回基本类型值,会产生 TypeError
错误。let obj1 = {
valueOf() {
return 42;
}
};
console.log(Number(obj1)); // 42
let obj2 = {
toString() {
return "3.14";
}
};
console.log(Number(obj2)); // 3.14
let obj3 = {
valueOf() {
return {};
},
toString() {
return {};
}
};
// console.log(Number(obj3)); // TypeError: Cannot convert object to primitive value
数组在转换为数字时,会被首先转换为字符串,然后再根据字符串的转换规则进行转换。如果数组包含多个元素,结果通常为 NaN
,因为转换后的字符串包含逗号分隔的元素。
console.log(Number([1, 2, 3])); // NaN
console.log(Number([42])); // 42
console.log(Number([])); // 0
console.log(Number(["3.14"])); // 3.14
以下值在转换为布尔值时会被转换为 false
:
undefined
null
false
+0
-0
NaN
""
(空字符串)console.log(Boolean(undefined)); // false
console.log(Boolean(null)); // false
console.log(Boolean(false)); // false
console.log(Boolean(0)); // false
console.log(Boolean(-0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean("")); // false
除了上述之外的所有值,在转换为布尔值时都会被转换为 true
。这包括:
console.log(Boolean("hello")); // true
console.log(Boolean(42)); // true
console.log(Boolean(-42)); // true
console.log(Boolean({})); // true
console.log(Boolean([])); // true
console.log(Boolean(function(){}));// true
||
和 &&
操作符的返回值逻辑操作符 ||
和 &&
有特定的返回值规则,它们不仅仅返回布尔值,还可能返回操作数本身。规则如下:
||
)逻辑或操作符 ||
会在找到第一个真值时立即返回该值。如果所有操作数都为假值,则返回最后一个操作数。具体规则如下:
true
,则返回第一个操作数的值。false
,则返回第二个操作数的值。console.log(false || true); // true
console.log(0 || 42); // 42
console.log('' || 'default'); // "default"
console.log(null || 'fallback'); // "fallback"
console.log(undefined || 'ok'); // "ok"
console.log(false || 0 || 'foo'); // "foo"
console.log('' || 0 || NaN); // NaN
&&
)逻辑与操作符 &&
会在找到第一个假值时立即返回该值。如果所有操作数都为真值,则返回最后一个操作数。具体规则如下:
false
,则返回第一个操作数的值。true
,则返回第二个操作数的值。console.log(true && false); // false
console.log(42 && 0); // 0
console.log('foo' && 'bar'); // "bar"
console.log('hello' && 123); // 123
console.log(true && 'ok'); // "ok"
console.log(1 && 2 && 3); // 3
console.log('' && 'fallback'); // ""
console.log(null && 'should not reach'); // null
||
操作符:返回第一个真值,或者在所有操作数均为假值时返回最后一个操作数。&&
操作符:返回第一个假值,或者在所有操作数均为真值时返回最后一个操作数。==
(双等号)与 ===
(三等号)的区别==
(双等号)==
是宽松相等性比较操作符,会在比较两个值时进行类型转换。如果操作数的类型不同,会先将它们转换为相同类型再进行比较。规则如下:
null
和 undefined
:null
和 undefined
视为相等。示例:
console.log(2 == '2'); // true
console.log(null == undefined); // true
console.log(true == 1); // true
console.log(false == 0); // true
console.log('' == 0); // true
console.log([1, 2] == '1,2'); // true
===
(三等号)===
是严格相等性比较操作符,不会进行类型转换。如果两个值的类型不同,直接返回 false
。规则如下:
false
。示例:
console.log(2 === '2'); // false
console.log(null === undefined); // false
console.log(true === 1); // false
console.log(false === 0); // false
console.log('' === 0); // false
console.log([1, 2] === '1,2'); // false
性能:由于 ===
不需要进行类型转换,通常比 ==
的执行速度更快。但在现代 JavaScript 引擎中,这种性能差异微不足道。
可预测性:===
的行为更加可预测,不会出现一些令人困惑的结果。例如:
console.log(0 == false); // true
console.log(0 === false); // false
console.log(null == undefined); // true
console.log(null === undefined); // false
NaN
NaN
是唯一一个不等于自身的值,无论是用 ==
还是 ===
:
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false
如果需要检查一个值是否为 NaN
,应该使用 isNaN()
函数或 Number.isNaN()
方法。
建议在代码中尽量使用 ===
,这样可以避免很多潜在的错误,使代码更加健壮和可维护。同时,理解 ==
的行为也很重要,因为你可能会在一些旧代码或特定场景中遇到它。
Object.is()
与 ==
和 ===
的区别Object.is()
在大多数情况下与 ===
的行为相同,但在一些特殊情况(如 -0
和 +0
,以及 NaN
)上有所不同。规则如下:
false
。-0
和 +0
不相等。NaN
是相等的。示例:
console.log(Object.is(2, '2')); // false
console.log(Object.is(null, undefined)); // false
console.log(Object.is(true, 1)); // false
console.log(Object.is(false, 0)); // false
console.log(Object.is('', 0)); // false
console.log(Object.is([1, 2], '1,2')); // false
console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(+0, -0)); // false
console.log(Object.is(-0, -0)); // true
console.log(Object.is(+0, +0)); // true
isNaN()
与 Number.isNaN()
的区别isNaN()
isNaN()
函数会先尝试将传入的参数转换为数字,然后检查转换后的值是否为 NaN
。这意味着它不仅检测 NaN
本身,还会将那些不能转换为有效数字的值视为 NaN
。
示例:
console.log(isNaN(NaN)); // true
console.log(isNaN('hello')); // true
console.log(isNaN(undefined)); // true
console.log(isNaN({})); // true
console.log(isNaN(123)); // false
console.log(isNaN('123')); // false
Number.isNaN()
Number.isNaN()
函数不会进行类型转换,只会在参数本身是 NaN
的情况下返回 true
。它更为严格,只有传入的值是 NaN
时才会返回 true
。
示例:
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN('hello')); // false
console.log(Number.isNaN(undefined)); // false
console.log(Number.isNaN({})); // false
console.log(Number.isNaN(123)); // false
console.log(Number.isNaN('123')); // false
==
操作符的强制类型转换规则==
会在比较两个值时进行强制转换,这种类型转换遵循一套规则,使得不同类型的值可以相互比较。规则如下:
null
和 undefined
null
和 undefined
仅相等于自身和对方。示例:
console.log(null == undefined); // true
console.log(null == null); // true
console.log(undefined == undefined); // true
console.log(null == 0); // false
console.log(undefined == 0); // false
示例:
console.log(true == 1); // true
console.log(false == 0); // true
console.log(true == 2); // false
示例:
console.log('42' == 42); // true
console.log('42' == '42'); // true
console.log('42' == 43); // false
console.log('0' == false); // true
toPrimitive
方法(valueOf
或 toString
)将对象转换为原始类型,然后再进行比较。示例:
console.log([1, 2] == '1,2'); // true
console.log([1] == 1); // true
console.log({} == '[object Object]'); // true
0
进行比较。示例:
console.log('' == 0); // true
console.log('' == false); // true
toPrimitive
方法(valueOf
或 toString
),转换为原始类型后再比较。示例:
let obj = { toString: () => '42' };
console.log(obj == '42'); // true
console.log(obj == 42); // true
Symbol
类型:Symbol
类型只能与 Symbol
类型进行比较,与其他类型的比较总是返回 false
。示例:
console.log(Symbol() == Symbol()); // false
console.log(Symbol() == 'symbol'); // false
console.log(Symbol() == false); // false
==
操作符在比较两个不同类型的值时,会根据上述规则进行类型转换。这些规则可以导致一些意想不到的结果,因此在进行值比较时需要格外小心。如果希望避免这些复杂的类型转换规则,推荐使用严格相等操作符 ===
,它不进行类型转换,仅在值和类型都相等时才返回 true
。
隐式类型转换也称为类型强制转换,是指 JavaScript 在表达式求值时自动将一种数据类型转换为另一种数据类型的过程。隐式类型转换主要发生在以下三种情况下:算术运算、比较运算和逻辑运算。常见的隐式类型转换规则如下:
在算术运算中,JavaScript 会将操作数转换为数字类型。
+
,则会进行字符串拼接。-
、*
、/
、%
),则会将操作数转换为数字。示例:
console.log(5 + "5"); // "55"(字符串拼接)
console.log("5" + 5); // "55"(字符串拼接)
console.log(5 + 5); // 10(数值相加)
console.log(5 - "2"); // 3
console.log("6" * "2"); // 12
console.log("8" / 2); // 4
console.log("10" % 3); // 1
在比较运算中,JavaScript 会将操作数转换为相同的类型再进行比较。
双等号(==
):会进行类型转换。
console.log(5 == "5"); // true(字符串 "5" 被转换为数字 5)
console.log(false == 0); // true(false 被转换为数字 0)
console.log(true == 1); // true(true 被转换为数字 1)
console.log(null == undefined); // true
三等号(===
):不会进行类型转换,直接比较类型和值。
console.log(5 === "5"); // false
console.log(false === 0); // false
console.log(true === 1); // false
console.log(null === undefined); // false
>
, <
, <=
, >=
)操作数会被转换成数字或字符串。
示例:
console.log(5 > "2"); // true
console.log("6" < "12"); // false(字符串比较)
console.log("8" >= 8); // true
console.log("10" <= 20); // true
逻辑运算符(!
, ||
, &&
)会将操作数转换为布尔值。
逻辑非(!
):
console.log(!0); // true(0 被转换为 false,然后取反为 true)
console.log(!1); // false(1 被转换为 true,然后取反为 false)
console.log(!""); // true(空字符串被转换为 false,然后取反为 true)
console.log(!"hello"); // false(非空字符串被转换为 true,然后取反为 false)
逻辑或(||
):
console.log(0 || 1); // 1(0 被转换为 false,因此返回第二个操作数 1)
console.log(1 || 0); // 1(1 被转换为 true,因此返回第一个操作数 1)
逻辑与(&&
):
console.log(0 && 1); // 0(0 被转换为 false,因此返回第一个操作数 0)
console.log(1 && 2); // 2(1 被转换为 true,因此返回第二个操作数 2)
字符串与数字之间的隐式转换在很多情况下都会发生。
+
,且有一个操作数是字符串,则会进行字符串拼接。-
、*
、/
、%
),则会将字符串转换为数字。示例:
console.log("5" - 2); // 3("5" 被转换为数字 5,然后 5 - 2 = 3)
console.log("5" * "2"); // 10(两个字符串都被转换为数字)
console.log("5" / 2); // 2.5("5" 被转换为数字 5,然后 5 / 2 = 2.5)
+
操作符的特殊规则+
操作符的行为取决于操作数的类型:
字符串拼接:如果两个操作数中有一个是字符串,则 +
操作符将执行字符串的拼接。
console.log("hello" + " world"); // "hello world"
console.log(5 + "5"); // "55"
console.log("The answer is " + 42); // "The answer is 42"
数值加法:如果两个操作数都是数字,或者一方是布尔值或 null
,则 +
操作符将执行数值加法(隐式转换为数字再执行运算)。
console.log(5 + 5); // 10
console.log(true + 1); // 2 (true 被转换为 1)
console.log(null + 1); // 1 (null 被转换为 0)
对象转换为原始值:如果操作数是对象,它们会首先转换为原始值,然后再根据原始值的类型进行操作。
console.log([1, 2, 3] + [4, 5, 6]); // "1,2,34,5,6"
console.log({} + {}); // "[object Object][object Object]"
数字和字符串:优先转为字符串进行处理。
console.log(10 + "20"); // "1020"
console.log("10" + 20); // "1020"
布尔值和字符串:
console.log(true + "test"); // "truetest"
console.log(false + "test"); // "falsetest"
总结:当字符串与其他基础类型相加时,会进行字符串拼接。如果操作数是对象,会先转换为原始值,再根据原始值进行操作。
JavaScript 中的数字类型是基于双精度浮点数实现的,这种方式在大多数情况下是足够的,但在处理非常大的整数时,会出现精度问题。为了处理和表示任意精度的整数,JavaScript 引入了 BigInt
类型。
BigInt
可以处理任意大的整数且不会丢失精度,从而解决了大整数运算中的问题。
示例:
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1); // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2); // 9007199254740992 (错误)
BigInt
可以表示任意大的整数,而不会丢失精度。BigInt
专门用于整数运算,确保了精度和一致性。Number
类型区别明确:BigInt
是一种新的原始数据类型,与现有的 Number
类型区别明确,避免了混淆。使用 BigInt
非常简单,只需在整数后加上 n
后缀,或者使用 BigInt
构造函数。
示例:
const bigInt1 = 1234567890123456789012345678901234567890n;
const bigInt2 = BigInt("1234567890123456789012345678901234567890");
console.log(bigInt1); // 1234567890123456789012345678901234567890n
console.log(bigInt1 + 1n); // 1234567890123456789012345678901234567891n
BigInt
和 Number
类型不能直接混合使用,需要进行显式转换。
示例:
const num = 42;
const bigInt = 12345678901234567890n;
console.log(num + bigInt); // TypeError: Cannot mix BigInt and other types
// 需要显式转换
console.log(BigInt(num) + bigInt); // 12345678901234567932n
===
)和显式类型转换。BigInt
的引入解决了 JavaScript 在处理大整数时的精度问题,适用于需要高精度整数运算的场景。