面试题
1. 动态执行JS有哪些方式?
注意:以下方式都受CSP策略限制,不能在严格模式下使用。
js
// 1. eval函数, 局部作用域
eval('console.log(123)');
// 2. new Function构造函数, 全局作用域
const fn = new Function('console.log(456)');
fn();
// 3. setTimeout和setInterval, 全局作用域
setTimeout('console.log(789)', 0);
// 4. 动态创建script标签, 全局作用域
const script = document.createElement('script');
script.textContent = 'console.log(101112)';
document.head.appendChild(script);2. 以下的输出是什么?
js
var a = { n: 1}; // 1
var b = a; // 2
a.x = a = { n: 2 }; // 3
console.log(a.x); // undefined
console.log(b.x); // { n: 2 }这里考查的是赋值操作的顺序,第3步中,可以看成是以下两步:
a.x = (a = {n: 2}),这里的a.x取的地址值已固定, 实际就是b.x,不受后面赋值的影响- 当给a赋值后再给a.x赋值,这里a变了,但是
a.x实际也是b.x。、
3. var, let, const 区别?
- 作用域不同:var 是函数作用域,let 和 const 是块级作用域。
- 变量提升不同:var 存在变量提升,let 和 const 不存在变量提升。
- 重复声明不同:var 可以重复声明,let 和 const 不可以重复声明。
- 赋值不同:var 可以在声明前赋值,let 和 const 必须在声明后赋值。
- const 声明的变量必须初始化,且不能被重新赋值,但如果是对象或数组,可以修改其属性或元素。
- var在全局作用域下声明的变量会成为全局对象的属性,而let和const声明的变量不会。
4. 前端有哪些场景会导致内存泄漏?
- 全局变量不会被GC,始终被window引用着
- 未清理的定时器
- 未清理的事件监听器
- 闭包滥用导致对象被意外引用
- DOM被删除了,但JS引用还在
5. 有使用过哪些设计模式?
- 单例模式:整个系统中,只存在一个实例,如Vuex和全局事件中心,某些全局缓存对象
- 工厂模式:创建对象时,不暴露具体构造过程,让创建逻辑更清晰。如封装请求模块
- 策略模式:将一组可能变化的策略封装成独立函数,通过名称动态调用,如表单验证。
- 观察者模式(Observer) / 发布订阅(Pub/Sub):一对多通知机制:一个对象变化自动通知所有订阅者。如:Vue2的依赖收集,事件订阅。
- 代理模式:DOM中事件代理
- 适配器模式:将一个接口转为另一个接口
6. Web Worker 有什么优缺点?
- 优点:
- 可以在后台线程中执行耗时操作,避免阻塞主线程
- 可以利用多核处理器的并行计算能力
- 可以与主线程通过消息传递进行通信
- 缺点:
- 每个Web Worker都是一个独立的线程,不能直接访问主线程的DOM和全局变量
- 通信成本较高,因为需要通过消息传递来进行数据交换
- 每个Web Worker都有自己的内存空间,不能直接共享数据
注意: 结构化克隆算法:在主线程和Web Worker之间传递数据时,需要进行序列化和反序列化。而结构化克隆算法可以对复杂对象进行深拷贝,避免引用传递导致的问题。但是在File/Blob时会共享底层数据以避免性能问题。
| 类型 | JS 实例共享 | 底层数据共享 | 备注 |
|---|---|---|---|
| Object / Array | ❌ | ❌ | 深拷贝 |
| Blob / File | ❌ | ✅ | 推荐大文件 |
| ImageBitmap | ❌ | ✅ | 实现相关 |
| ArrayBuffer | ❌ | ❌ | 默认拷贝 |
| ArrayBuffer (transfer) | ❌ | ❌ | 所有权转移 |
| SharedArrayBuffer | ✅ | ✅ | 真共享 |
| MessagePort | ❌ | ❌ | 转移 |
| OffscreenCanvas | ❌ | ❌ | 转移 |
7. 你对Vue3的响应式系统的理解?
通过Proxy实现响应式,对目标对象进行代理,当访问响应式数据时,收集effect依赖,修改响应式数据时,触发相应的effect更新。相比于Vue2的Object.defineProperty,Proxy可以监听对象属性的添加和删除,以及数组的变化;性能也Vue2的更好,这是因为Proxy是惰性收集依赖,而defineProperty是初始化的时候就开始全部要收集。
8. echarts大数据性能优化
- 通过抽样,聚合、large和progressive减少绘制量
- 关闭动画,必要时使用echarts-gl走WebGL渲染
- 避免频繁setOption,全量diff,使用appendData和局部更新;
- 减少tooltip/hover和事件命中范围,如只在必要区域显示