# 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 的优势
- 写法更加优化
- 调试更加友好