# JS 面试题

# 基础

# 如何判断是否是数组

数组对象的静态方法:Array.isArray(arg)

对象原型的toString:Object.prototype.toString.call(arg)

# 如何实现不可变对象

  • 深度拷贝 _.deepClone()
  • immutable.js https://github.com/immutable-js/immutable-js
  • immer.js https://github.com/immerjs/immer
  • Object.freeze()

# 类型转换的原理和规则

JavaScript 在需要用到布尔类型值的上下文中使用强制类型转换 (Type Conversion ) 将值转换为布尔值,例如条件语句和循环语句。

在 JavaScript 中只有 8 个 falsy 值。它们分别是

  • false
  • '', ""
  • 0
  • -0
  • 0n
  • NaN
  • null
  • undefined

# 为什么 0.1 + 0.2 不等于 0.3

  • 存储精度
  • IEEE754标准,浮点数在内存中的存储

JS 的 Number 类型遵循的是 IEEE 754 标准, 使⽤的是 64 位固定⻓度来表示。

  • 1位符号位
  • 11位指数位
  • 52位数值位
console.log(0.1 + 0.2)
// 0.30000000000000004
// 17位数之后会丢失精度
console.log(1234567890123456789)
// 1234567890123456800
console.log(0.1234567890123456789)
// 0.12345678901234568

# 说一下 esm 和 cjs 的区别

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  • CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。

# 机制

# 一段js代码是如何执行的

  • 加载js
  • 执行,变量提升,字节码,JIT
  • 单线程,任务队列,事件循环

# 解释一下变量提升

JS 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。

这造成的结果就是所有的声明语句,都会被提升到代码的头部,这就叫变量提升。

# 谈谈对作用域链的理解

JS 属于静态作用域,声明的作用域是根据程序在编译时确定的,有时也称作词法作用域。

JS 在执行过程中会创造可执行上下文,可执行上下文的词法环境中含有外部词法环境的引用,我们可以通过这个引用获取外部词法环境的变量,声明等,这些引用串联起来一直指向全局的词法环境,因此形成了作用域链。

# 谈谈对 闭包 的理解

闭包是什么,闭包就是一个函数和该函数体内可访问的变量总和。

闭包的产生,为了实现作用域链。

闭包的作用,闭包最大的作用就是隐藏内部变量。

# 谈谈对 this 的理解

普通函数和作用域 指向 执行时上下文 箭头函数 指向 声明时上下文

this ==> this绑定 ==> 执行上下文

# 谈谈对原型链的理解

原型对象,原型链

工厂模式 ==> 原型模式 ==> 享元模式

# 内存

# js 的变量存储在哪里

一般认为

  • 基本类型存储在栈中,被闭包引用时成为常驻内存,存储在内存堆中
  • 复杂类型存储在内存堆中

# js 垃圾回收机制

  • 可达性
  • 引用计数

# 异步

# async 和 await 是什么?

生成器函数的语法糖,是对 Promise 的 语法优化

异步 ==> 协程 ==> 进程 线程 协程

# async 相对 Promise 的优势

  • 写法更加优化
  • 调试更加友好