每周 30 道面试题之 JavaScript 基础(一)

188 阅读7分钟

1. JavaScript 有哪些基本数据类型

解析:BigInt :表示任意大的整数

答案:UndefinedNullBooleanNumberStringSymbolBigInt

2. 向上取整和向下取整是哪两个方法

解析

  • Math.ceil() 向上取整
  • Math.floor() 向下取整
  • Math.round() 四舍五入
  • Math.abs() 绝对值

答案:Math.ceil() 向上取整、Math.floor() 向下取整

3. JavaScript 数据类型检测的方式有哪些

解析:

  1. typeof 运算符:typeof 运算符可以用于检测一个值的数据类型。它返回一个表示数据类型的字符串,如 "string""number""boolean""function" 等。但它对于 null 和数组类型检测不准确。
  2. instanceof 运算符:instanceof 运算符用于检测一个对象是否属于某个类或构造函数的实例。它返回一个布尔值,表示对象是否属于该类的实例。但其不能检测基本数据类型,不能跨 iframe
  3. constructor 属性:每个 JavaScript 对象都有一个 constructor 属性,用于指向创建该对象的构造函数。可以通过 obj.constructor 来检测对象的构造函数,从而判断对象的类型。但其能被修改。
  4. Object.prototype.toString 方法:Object.prototype.toString是一个通用的方法,可以用于检测任意对象的数据类型。
  5. Array.isArray 方法:Array.isArray是一个用于判断一个值是否为数组的静态方法。它返回一个布尔值,表示该值是否为数组类型。

答案:

  • typeof :只能检测出除 null 外的基本数据类型和 function
  • instanceof :能检测出引用类型,缺点:不能检测出基本类型,且不能跨 iframe
  • constructor :基本能检测除了 nullundefined 的所有类型,缺点:constructor 易被修改,也不能跨 iframe
  • Object.prototype.toString.call :检测出所有的类型

4. Object.prototype.toString.call 检测数据类型有什么缺点

解析: 它返回一个以"[object 类型]"形式表示对象类型的字符串。但返回的值受 Symbol.toStringTag 的影响,如果 Symbol.toStringTag 值为一个字符串,“[object 类型]”中的类型为该属性值。

答案: Symbol.toStringTag 会影响 Object.prototype.toString.call 的返回值。

5. ===== 运算符有什么区别

答案:

  • == 运算符进行类型转换,然后比较值是否相等。
  • === 运算符不进行类型转换,比较值和类型是否严格相等。

6. == 操作符的强制类型转换规则是什么

答案:

  • 数据类型转换 boolean 值得判断都会先转换为 number 在判断,数字优先级最高,然后是字符串。
  • nullundefined 除了和彼此比较以外,与其他任何类型操作数进行相等性测试都为 false

7. Object.is=== 的区别

解析: === 是一种严格相等运算符,用于判断两个值是否完全相等。Object.is 是一种“绝对相等”的比较方法,更严格一些,并且对于 NaN+0/-0 的情况有不同的处理。在 Object.is 中,NaN 被认为与自己相等,这是与 === 不同的地方。此外,Object.is 还将 +0-0 视为不相等,而 === 将它们视为相等。

答案:

  • Object.is(NaN,NaN)trueNaN===NaNfalse
  • Object.is(+0,-0)false+0===-0true

8. JavaScript 判断数组的方式

答案:

  • 通过 Object.prototype.toString.call() 做判断
  • 通过 Array.isArray() 做判断
  • 通过 instanceof 做判断

9. JavaScript 是静态作用域还是动态作用域

解析: JavaScript 是静态作用域,在静态作用域中,作用域是由程序中变量和函数在编译阶段确定的,并在运行时保持不变。作用域链是根据代码中变量和函数定义的位置来确定的,与函数的实际调用位置无关。

答案:JavaScript 是静态作用域

10. nullundefined 区别

答案:null 来表示一个有意设置为空的值,而 undefined 则表示一个未定义的值

11. 变量提升与函数提升的区别?

答案:变量提升和函数提升都是提升到作用域的顶部,函数提升的优先级大于变量提升的优先级

12. typeof null 的结果为什么是 Object

答案:Javascript 早期留下来的 bug,null 的二进制表示是 000 和 Object 类型一样,因此返回 Object

13. 什么是临时死区?

解析: 使用letconst关字声明变量时,在声明之前会将变量放入“临时死区”中,访问该变量会抛出ReferenceError错误,从而阻止变量提升。

答案:使用 letconst 关字声明的变量不会被提升,在声明之前会将变量放入“临时死区”。

14. 会转换为假值的有哪些

答案:undefined 、 null 、 false 、 0 和 NaN 、 ""

15. 如何获取安全的 undefined 值?

解析:undefined 可以作为变量声明,可以通过 void 0 来获取安全的 undefined

答案:void 0

16. 什么是高阶函数

答案:一个函数作为参数或返回值的函数

17. typeof NaN 的结果是什么?

答案:number

18. isNaNNumber.isNaN 函数的区别

答案:isNaN() 将参数转换为数值,Number.isNaN() 不会。

19. 什么是闭包

解析: 函数内部声明的嵌套函数能够访问外部函数的变量。脚本执行时会将要执行函数放入执行栈中,同时产生执行上下文放入栈中,函数执行完了执行上下文出栈回收。但其他函数用到执行上下文时,就不会出栈释放,也就形成了闭包。

答案:闭包是指函数内部声明的嵌套函数能够访问外包函数变量。

20. 闭包的作用

答案:

  • 创建私有变量
  • 让变量保留在内存中
  • 柯里化

21. 闭包的使用场景

答案:

  • 高阶函数(回调函数,return 一个函数)
  • 自执行函数
  • 节流防抖
  • 函数柯里化
  • 函数回调

22. 闭包的缺点

答案:内存泄漏,使用完闭包函数后手动释放。

23. 执行上下文

解析: 执行上下文 可以理解为当前代码的执行环境,同一个函数在不同的环境中执行,会因为访问数据的不同产生不一样的结果。

答案:

  • 全局执行上下文:只有一个,程序首次运行时创建,它会在浏览器中创建一个全局对象( window 对象),使 this 指向这个全局对象
  • 函数执行上下文:函数被调用时创建,每次调用都会为该函数创建一个新的执行上下文
  • Eval 函数执行上下文:运行 eval 函数中的代码时创建的执行上下文,少用且不建议使用

答案:执行上下文是函数代码的执行环境,分为全局执行上下文、函数执行上下文、eval 函数执行上下文三种。

24. 执行栈

答案:脚本执行时会将要执行函数放入执行栈中,同时产生执行上下文放入栈中,函数执行完了执行上下文出栈回收

25. this 的理解

答案:

  • 函数执行时,this 指向全局对象
  • 方法调用时,this 指向调用这个方法的对象
  • 构造函数调用时,this 指向新创建的对象
  • applycallbind 调用,this 指向第一个参数的对象,如果第一个参数是 null 那指向全局对象。
  • 箭头函数时,this 执行函数声明时所在上下文的 this 值。

26. forEach 如何跳出循环?

解析:forEach 参数是回调函数因此 breakreturn 都无法跳槽循环,可以使用 try catch 捕获异常来跳出循环

答案:try catch

27. 什么是尾调用,使用尾调用有什么好处?

答案:

尾调用是指一个函数的最后一条语句是调用另一个函数,好处:

  • 尾调用可以重用当前函数的调用帧,而不会增加额外的堆栈空间。
  • 尾调用因为是最后一步执行函数,因此不必再保存当前的执行上下文。

尾调用只在严格模式下才会被优化,而在正常模式下无效。

28. forEachmap 方法的区别?

答案:

  • forEach 遍历数组,没有返回值,如果遍历的元素是引用类型,可以改变元素的属性值
  • map 遍历数组,返回一个新数组,新数组中的值为回调函数的返回值,遍历的元素是引用类型,也可以改变元素的属性值。

29. includesindexOf 好在哪?

解析:includes 内部使用了 Number.isNaNNaN 进行了匹配

答案:includes 可以检测 NaNindexOf 不能检测 NaN

30. intanceof 操作符的作用是什么?

答案:instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置