前端JavaScrip面试八股常考题(二)

11.JavaScript 其他值到数字值的转换规则

1. Undefined 类型

undefined 转换为 NaN

console.log(Number(undefined)); // NaN

2. Null 类型

null 转换为 0

console.log(Number(null)); // 0

3. Boolean 类型

true 转换为 1false 转换为 0

console.log(Number(true));  // 1
console.log(Number(false)); // 0

4. String 类型

字符串按照 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

5. Symbol 类型

Symbol 值不能转换为数字,会抛出 TypeError

let sym = Symbol("desc");
// console.log(Number(sym)); // TypeError: Cannot convert a Symbol value to a number

6. 对象到数字的转换

对象(包括数组)会首先被转换为相应的基本类型值,然后再根据基本类型值的转换规则进行强制转换。步骤如下:

  1. JavaScript 尝试将对象转换为基本类型值。内部会首先检查该对象是否有 valueOf() 方法。
  2. 如果 valueOf() 存在并返回基本类型值,则使用该值进行强制类型转换。
  3. 如果没有 valueOf() 方法或其返回值不是基本类型,则使用 toString() 方法的返回值进行转换。
  4. 如果 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

7. 数组的转换

数组在转换为数字时,会被首先转换为字符串,然后再根据字符串的转换规则进行转换。如果数组包含多个元素,结果通常为 NaN,因为转换后的字符串包含逗号分隔的元素。

console.log(Number([1, 2, 3]));  // NaN
console.log(Number([42]));       // 42
console.log(Number([]));         // 0
console.log(Number(["3.14"]));   // 3.14

12.JavaScript 其他值到布尔值的转换规则

以下值在转换为布尔值时会被转换为 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

13.JavaScript 中 ||&& 操作符的返回值

逻辑操作符 ||&& 有特定的返回值规则,它们不仅仅返回布尔值,还可能返回操作数本身。规则如下:

1. 逻辑或操作符(||

逻辑或操作符 || 会在找到第一个真值时立即返回该值。如果所有操作数都为假值,则返回最后一个操作数。具体规则如下:

  1. 对第一个操作数进行条件判断。
  2. 如果第一个操作数的条件判断结果为 true,则返回第一个操作数的值。
  3. 如果第一个操作数的条件判断结果为 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

2. 逻辑与操作符(&&

逻辑与操作符 && 会在找到第一个假值时立即返回该值。如果所有操作数都为真值,则返回最后一个操作数。具体规则如下:

  1. 对第一个操作数进行条件判断。
  2. 如果第一个操作数的条件判断结果为 false,则返回第一个操作数的值。
  3. 如果第一个操作数的条件判断结果为 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

总结

  • || 操作符:返回第一个真值,或者在所有操作数均为假值时返回最后一个操作数。
  • && 操作符:返回第一个假值,或者在所有操作数均为真值时返回最后一个操作数。

14.==(双等号)与 ===(三等号)的区别

1. ==(双等号)

== 是宽松相等性比较操作符,会在比较两个值时进行类型转换。如果操作数的类型不同,会先将它们转换为相同类型再进行比较。规则如下:

  1. 类型不同:会进行类型转换。
  2. nullundefinednullundefined 视为相等。
  3. 布尔值:布尔值会转换为数字再进行比较。
  4. 字符串和数字:字符串和数字比较时,会将字符串转换为数字。
  5. 对象与原始类型:对象与原始类型比较时,会将对象转换为原始类型。

示例:

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

2. ===(三等号)

=== 是严格相等性比较操作符,不会进行类型转换。如果两个值的类型不同,直接返回 false。规则如下:

  1. 类型不同:返回 false
  2. 类型相同:再进行值的比较。

示例:

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

3. 性能与可预测性

  • 性能:由于 === 不需要进行类型转换,通常比 == 的执行速度更快。但在现代 JavaScript 引擎中,这种性能差异微不足道。

  • 可预测性=== 的行为更加可预测,不会出现一些令人困惑的结果。例如:

    console.log(0 == false);   // true
    console.log(0 === false);  // false
    
    console.log(null == undefined);   // true
    console.log(null === undefined);  // false
    

4. 特殊值:NaN

NaN 是唯一一个不等于自身的值,无论是用 == 还是 ===

console.log(NaN == NaN);   // false
console.log(NaN === NaN);  // false

如果需要检查一个值是否为 NaN,应该使用 isNaN() 函数或 Number.isNaN() 方法。

5. 建议

建议在代码中尽量使用 ===,这样可以避免很多潜在的错误,使代码更加健壮和可维护。同时,理解 == 的行为也很重要,因为你可能会在一些旧代码或特定场景中遇到它。

15.Object.is()===== 的区别

Object.is() 在大多数情况下与 === 的行为相同,但在一些特殊情况(如 -0+0,以及 NaN)上有所不同。规则如下:

  1. 类型不同:返回 false
  2. 类型相同:再进行值的比较。
  3. 特殊情况
    • -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

16.isNaN()Number.isNaN() 的区别

1. 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

2. 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

17.== 操作符的强制类型转换规则

== 会在比较两个值时进行强制转换,这种类型转换遵循一套规则,使得不同类型的值可以相互比较。规则如下:

1. nullundefined

  • nullundefined 仅相等于自身和对方。

示例:

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

2. 布尔类型

  • 如果有一个操作数是布尔值,JavaScript 会将布尔值转换为数字,然后再进行比较。

示例:

console.log(true == 1); // true
console.log(false == 0); // true
console.log(true == 2); // false

3. 字符串和数字

  • 如果是字符串和数字比较,JavaScript 会将字符串转换为数字,然后再进行比较。

示例:

console.log('42' == 42); // true
console.log('42' == '42'); // true
console.log('42' == 43); // false
console.log('0' == false); // true

4. 对象和原始类型

  • 如果有一个操作数是对象,另一个是原始类型(字符串、数字、布尔值),JavaScript 会尝试调用对象的 toPrimitive 方法(valueOftoString)将对象转换为原始类型,然后再进行比较。

示例:

console.log([1, 2] == '1,2'); // true
console.log([1] == 1); // true
console.log({} == '[object Object]'); // true

5. 特殊情况

  • 空字符串:空字符串会被转换为数字 0 进行比较。

示例:

console.log('' == 0); // true
console.log('' == false); // true
  • 对象转换为原始类型:对象的比较会触发类型转换,通过调用 toPrimitive 方法(valueOftoString),转换为原始类型后再比较。

示例:

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

18.JavaScript 中如何进行隐式类型转换

隐式类型转换也称为类型强制转换,是指 JavaScript 在表达式求值时自动将一种数据类型转换为另一种数据类型的过程。隐式类型转换主要发生在以下三种情况下:算术运算、比较运算和逻辑运算。常见的隐式类型转换规则如下:

1. 算术运算

在算术运算中,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

2. 比较运算

在比较运算中,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
    

3. 其他比较运算符(>, <, <=, >=

操作数会被转换成数字或字符串。

  • 数字与数字之间直接比较。
  • 字符串与字符串之间按字典序比较。
  • 数字与字符串之间,字符串会被转换为数字。

示例:

console.log(5 > "2"); // true
console.log("6" < "12"); // false(字符串比较)
console.log("8" >= 8); // true
console.log("10" <= 20); // true

4. 逻辑运算符

逻辑运算符(!, ||, &&)会将操作数转换为布尔值。

  • 逻辑非(!

    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)
    

5. 字符串与数字之间的转换

字符串与数字之间的隐式转换在很多情况下都会发生。

  • 如果操作符是 +,且有一个操作数是字符串,则会进行字符串拼接。
  • 如果操作符是其他算术运算符(如 -*/%),则会将字符串转换为数字。

示例:

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)

6. + 操作符的特殊规则

+ 操作符的行为取决于操作数的类型:

  • 字符串拼接:如果两个操作数中有一个是字符串,则 + 操作符将执行字符串的拼接。

    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"
    

总结:当字符串与其他基础类型相加时,会进行字符串拼接。如果操作数是对象,会先转换为原始值,再根据原始值进行操作。

19.JavaScript 中为什么会有 BigInt 的提出?

1. 背景

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 (错误)

2. BigInt 的优势

  1. 支持任意大整数BigInt 可以表示任意大的整数,而不会丢失精度。
  2. 专门设计用于整数运算:与浮点数不同,BigInt 专门用于整数运算,确保了精度和一致性。
  3. Number 类型区别明确BigInt 是一种新的原始数据类型,与现有的 Number 类型区别明确,避免了混淆。

3. 使用方法

使用 BigInt 非常简单,只需在整数后加上 n 后缀,或者使用 BigInt 构造函数。

示例:

const bigInt1 = 1234567890123456789012345678901234567890n;
const bigInt2 = BigInt("1234567890123456789012345678901234567890");

console.log(bigInt1); // 1234567890123456789012345678901234567890n
console.log(bigInt1 + 1n); // 1234567890123456789012345678901234567891n

4. 注意事项

BigIntNumber 类型不能直接混合使用,需要进行显式转换。

示例:

const num = 42;
const bigInt = 12345678901234567890n;

console.log(num + bigInt); // TypeError: Cannot mix BigInt and other types

// 需要显式转换
console.log(BigInt(num) + bigInt); // 12345678901234567932n

总结

  1. 隐式类型转换:JavaScript 在算术运算、比较运算和逻辑运算中会自动进行类型转换,但这种转换可能会导致一些意想不到的结果。因此,建议尽量使用严格相等操作符(===)和显式类型转换。
  2. BigIntBigInt 的引入解决了 JavaScript 在处理大整数时的精度问题,适用于需要高精度整数运算的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值