约面了,放轻松,好好面
盲点
基础知识
Function 和 Object 都是函数,而函数也是对象。
Object.prototype 是几乎所有对象的原型链终点(其 proto 是 null)。
Function.prototype 是所有函数的原型(包括 Object 和 Function 自身)。
Object.proto === Function.prototype (因为 Object 是个构造函数,是函数)
Function.proto === Function.prototype (Function 自身也是函数)
Function.prototype 本身也是一个对象,它的 proto 指向 Object.prototype。
Function.prototype.proto === Object.prototype
CSS
计算机网络
框架
react版本
react 18
React 18 的并发渲染通过可中断的任务调度和优先级控制,大幅提升了复杂应用的响应流畅度。新 Hook(如 useTransition、useDeferredValue)为开发者提供了优化工具。自动批处理减少了渲染次数,流式 SSR 和 选择性 Hydration 改善了首屏性能。升级时注意使用 createRoot 并充分测试严格模式下的警告。
并发:渲染任务可中断/恢复,根据优先级调度(如用户交互 > 数据加载),避免界面卡顿。
与防抖/节流的区别:防抖和节流是通过延迟执行来减少操作频率。过渡更新是立即执行更新逻辑,但延迟其渲染的优先级和提交,并且这个过程是可中断的。过渡更新通常能提供更流畅的体验。
要使用 startTransition,必须使用 ReactDOM.createRoot 来启用并发模式,而不是旧的 ReactDOM.render
理解并善用 StrictMode
:开发
环境下,<React.StrictMode>会故意双重调用某些方法(包括 useEffect)以帮助发现副作用中的错误
。确保你的 useEffect逻辑具有幂等性(多次执行结果相同)
或清理函数能正确取消副作用。如果仅为调试,可暂时注释 StrictMode,但生产环境不应受影响
rEACTnATIVE
Git
项目
手撕
循环引用
function hasCircularReference(obj, visited = new WeakSet()) {//Set VS WeakSet:// 1.解除不必要的引用:在不需要时,手动解除对象之间的引用可以帮助垃圾回收器更快地回收内存。//// 2.使用弱引用:在ES6中,引入了WeakMap和WeakSet,它们允许创建对对象的弱引用。这些引用不会阻止垃圾回收器回收对象。//// 3.内存分析工具:使用Chrome开发者工具中的内存分析工具可以帮助你检测内存泄漏和不必要的循环引用。// 如果对象是null或undefined,或者已经访问过,则返回falseif (!obj || visited.has(obj)) {return false;}// 将当前对象标记为已访问!!visited.add(obj);// 遍历对象的所有可枚举属性for (let key in obj) {if (obj.hasOwnProperty(key)) {let value = obj[key];// 如果属性值是对象,则递归检查if (typeof value === 'object' && value !== null) {// 如果在已访问的对象中找到了当前属性值,则说明存在循环引用if (visited.has(value)) {return true;}// 递归检查属性值!!!if (hasCircularReference(value, visited)) {return true;}}}}// 如果没有找到循环引用,则返回falsereturn false;}
大数相加(含小数)
function addLargeNumbers(num1, num2) {// 分离整数与小数部分let parts1 = num1.toString().trim().split('.');let parts2 = num2.toString().trim().split('.');let int1 = parts1[0] || '0';let int2 = parts2[0] || '0';let dec1 = parts1[1] || '0';let dec2 = parts2[1] || '0';// 对齐小数部分:在较短的小数后补0let maxDecLength = Math.max(dec1.length, dec2.length);dec1 = dec1.padEnd(maxDecLength, '0');dec2 = dec2.padEnd(maxDecLength, '0');// 处理小数部分相加let decResult = addIntegerParts(dec1, dec2);let decimalCarry = 0;// 如果小数部分相加后长度超过最大长度,说明有向整数位的进位if (decResult.length > maxDecLength) {decimalCarry = parseInt(decResult[0]); // 提取进位值decResult = decResult.substring(1); // 保留剩余小数部分}// 处理整数部分相加(加上小数部分的进位)let intResult = addIntegerParts(int1, int2, decimalCarry);// 组合结果if (decResult === '0') {return intResult; // 没有小数部分时直接返回整数} else {return intResult + '.' + decResult;}
}// 辅助函数:处理整数部分相加(可处理额外进位)
function addIntegerParts(str1, str2, extraCarry = 0) {let arr1 = str1.split('').map(Number);let arr2 = str2.split('').map(Number);let i = arr1.length - 1;let j = arr2.length - 1;let result = [];let carry = extraCarry; // 初始化进位(可能来自小数部分)while (i >= 0 || j >= 0 || carry > 0) {const val1 = i >= 0 ? arr1[i] : 0;const val2 = j >= 0 ? arr2[j] : 0;const sum = val1 + val2 + carry;result.push(sum % 10); // 将当前位添加到数组末尾carry = Math.floor(sum / 10);i--;j--;}// 反转数组并转换为字符串(避免使用 unshift 提升性能)return result.reverse().join('');
}// 测试示例
console.log(addLargeNumbers("123.45", "67.8")); // 输出 "191.25"
console.log(addLargeNumbers("0.999", "0.002")); // 输出 "1.001"
console.log(addLargeNumbers("100.00", "200.00")); // 输出 "300"(自动去除多余小数位)
class EventEmitter {constructor() {this.events = new Map(); // 使用Map存储事件和对应的监听器列表}// 订阅事件on(eventName, listener) {if (!this.events.has(eventName)) {this.events.set(eventName, []);}this.events.get(eventName).push(listener);return this; // 支持链式调用}// 发布事件emit(eventName, ...args) {const listeners = this.events.get(eventName);if (listeners) {// 复制一份数组,防止在回调函数中取消监听导致迭代异常listeners.slice().forEach(listener => {listener.apply(this, args);});}return this;}// 取消订阅off(eventName, listenerToRemove) {const listeners = this.events.get(eventName);if (listeners) {// 过滤掉要移除的监听器this.events.set(eventName, listeners.filter(listener => listener !== listenerToRemove));}return this;}
}// 使用示例
const emitter = new EventEmitter();
const callback = (data) => console.log('Event received:', data);
emitter.on('myEvent', callback);
emitter.emit('myEvent', { message: 'Hello!' }); // 输出: Event received: { message: 'Hello!' }
emitter.off('myEvent', callback);
emitter.emit('myEvent', 'This will not be logged'); // 无输出
真题