钉钉前端一面

钉钉前端一面
最新回答
┌胖胖糖〃

2024-02-25 19:47:43

钉钉前端一面问题解析与答案

1. 编辑器定制开发及文字效果实现
  • 定制开发经验:若参与过编辑器开发(如基于ProseMirror、Draft.js等),可提及具体功能(如Markdown支持、协同编辑)。若无直接经验,可说明对开源编辑器的调研或简单功能实现(如工具栏按钮绑定)。
  • 文字效果实现:通常通过操作DOM或编辑器数据模型实现。例如:

    加粗:用<strong>标签包裹文本或修改数据模型中的bold属性。

    斜体:用<em>标签或italic属性。

    底层逻辑:监听工具栏按钮点击,调用编辑器API(如editor.toggleMark('bold'))或直接操作DOM样式。

2. 登录鉴权与Token存储
  • Token不存Cookie的原因

    安全性:Cookie易受CSRF攻击,而Token存于localStorage或HttpOnly Cookie(需配合其他措施)更安全。

    灵活性:Token可跨域使用(如JWT),而Cookie受同源策略限制。

    控制权:前端可主动清除Token,避免依赖服务器过期时间。

3. 跨域问题
  • 常见解决方案

    CORS:后端配置Access-Control-Allow-Origin。

    JSONP:仅限GET请求,利用<script>标签。

    代理:开发环境配置Webpack代理,生产环境用Nginx反向代理。

4. 断点续传(未答)
  • 关键点:文件分片、记录已上传分片、断点续传时校验文件MD5或分片哈希。
5. 验证码安全
  • 保证验证码有效性

    后端维护:存储验证码与会话ID的映射,设置短有效期(如5分钟)。

    一次性验证:验证后立即失效,防止重复使用。

6. 手写Ajaxfunction ajax(url, method = 'GET', data = null) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open(method, url); xhr.onload = () => resolve(xhr.responseText); xhr.onerror = () => reject(xhr.statusText); xhr.send(data); });}7. 事件循环与代码执行顺序console.log(2); // 同步代码console.log(3); // 同步代码console.log(5); // 同步代码Promise.resolve().then(() => console.log(4)); // 微任务setTimeout(() => console.log(1), 0); // 宏任务

输出顺序:2 → 3 → 5 → 4 → 1解析:同步代码优先,微任务(Promise)次之,最后宏任务(setTimeout)。

8. 手写节流(立即执行版)function throttle(fn, delay) { let lastTime = 0; return function(...args) { const now = Date.now(); if (now - lastTime >= delay) { fn.apply(this, args); lastTime = now; } };}9. 性能优化
  • 代码层面:减少重绘回流、防抖节流、懒加载。
  • 构建层面:代码分割、Tree Shaking、CDN加速。
  • 网络层面:HTTP缓存、资源预加载、压缩。
10. call、apply、bind区别
  • 共同点:改变函数this指向。
  • 差异

    call:参数逐个传递(fn.call(obj, 1, 2))。

    apply:参数以数组传递(fn.apply(obj, [1, 2]))。

    bind:返回新函数,需手动调用(const newFn = fn.bind(obj); newFn())。

11. 代码题解析child.showName(); // 'c' → 实例属性优先于原型child.showName.call(obj1); // 'a' → this指向obj1child.showName.apply(obj2); // 'b' → this指向obj2let bind = child.showName.bind(obj1); bind(); // 'a' → 绑定obj112. 手写深拷贝function deepClone(obj, hash = new WeakMap()) { if (obj === null || typeof obj !== 'object') return obj; if (hash.has(obj)) return hash.get(obj); const clone = Array.isArray(obj) ? [] : {}; hash.set(obj, clone); for (const key in obj) { if (obj.hasOwnProperty(key)) { clone[key] = deepClone(obj[key], hash); } } return clone;}13. 三栏布局实现
  • Flexbox方案
.container { display: flex;}.left, .right { width: 200px; }.middle { flex: 1; }14. Vue双向绑定原理
  • 核心:数据劫持(Object.defineProperty或Proxy) + 发布-订阅模式。
  • 流程

    初始化时递归劫持数据属性。

    渲染时收集依赖(Watcher)。

    数据变化时通知依赖更新视图。

15. Diff算法
  • 优化策略

    同层比较:避免跨层级移动DOM。

    Key值匹配:识别相同节点复用或移动。

    最小操作:通过编辑距离算法计算最优移动步骤。

16. 反问环节
  • 部门业务:钉钉智能协作(如文档编辑、协同会议)。
  • 技术栈:React + Node.js + Java,可能涉及微前端、Serverless。
  • 面试流程:两轮技术面 + HR面,侧重项目深度与系统设计。

以上答案覆盖了面试中的技术点,结合实际经验与理论知识,确保准确性与实用性。