大家好,今天的分享由 uncle13 老师提供。
本篇面经是一位参加辅导小伙伴的真实面试经历,他的基本情况是:工作2.5年,年前被裁,准备了一个多月,是一个很努力的同学,除夕的时候还在背八股。
我们整理了下他提供的面试题,并简单作答。
小红书的架构部门比较注重基础知识的考查,对框架并没有具体要求。
console.log('Start');
setTimeout(function() {
console.log('Timeout 1');
}, 0);
Promise.resolve().then(function() {
console.log('Promise 1');
});
Promise.resolve().then(function() {
console.log('Promise 2');
});
console.log('End');
输出解析:
console.log('Start')
首先被执行,输出 "Start"。setTimeout
,它会被放入宏任务队列(setTimeout队列)。Promise.resolve().then
语句都被加入微任务队列(Promise队列)。console.log('End')
被执行,输出 "End"。此时主线程任务执行完毕,开始执行微任务队列中的任务。
Promise.resolve().then
输出 "Promise 1"。Promise.resolve().then
输出 "Promise 2"。所有微任务执行完毕后,再执行宏任务。
setTimeout
的回调函数,输出 "Timeout 1"。因此,该代码的最终输出顺序是:
Start
End
Promise 1
Promise 2
Timeout 1
讲一下伪类、伪元素
盒模型、box-sizing
BFC与清除浮动
选择器优先级
min-width、max-width、width的包含(优先级关系)关系
输入URL到渲染页面的全过程
8中哪些阶段可以优化提升效率,你做过哪些性能优化工作
强缓存、协商缓存发生在8中的哪些阶段
CDN
TLS/SSL
vue router 和 route的区别
vue单向数据流的特点、vueX使用方式
es6 set和map特点和区别
箭头函数和普通函数的区别
讲一下js异步处理发展史
async await 原理
手写题:Promise.all
function customPromiseAll(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('arguments should be an array'));
}
let results = [];
let completedPromises = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then((value) => {
results[index] = value;
completedPromises++;
if (completedPromises === promises.length) {
resolve(results);
}
})
.catch(reject);
});
});
}
介绍项目、难点、解决方案
项目私有定制功能举例
手写题:节流、防抖
节流(Throttling):
作用:节流是限制函数在一定时间间隔内执行,即使触发多次也只会在固定的时间间隔后执行一次。
场景:适用于需要稀释事件发生频率的情况,比如滚动事件或者鼠标移动事件。
function throttle(func, delay) {
let canRun = true;
return function() {
if (!canRun) return;
canRun = false;
setTimeout(function() {
func.apply(this, arguments);
canRun = true;
}, delay);
};
}
防抖(Debouncing):
作用:防抖是在函数连续触发结束后,等待一段时间再执行该函数,如果在等待时间内再次触发,则重新计时。
场景:适用于减少不必要的请求发送或者减轻用户输入产生的频繁操作。
function debounce(func, delay) {
let timer;
return function() {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, arguments);
}, delay);
};
}
WebSocket建立连接需要经过握手(handshake)过程。下面是WebSocket建立连接的简要步骤:
客户端发起连接:客户端通过在HTTP头部添加Upgrade: websocket
和Connection: Upgrade
字段,然后发送一个GET请求到服务器指定的WebSocket URL。
服务器回应握手:服务器接收到客户端发送的HTTP请求后,在响应头中包含Upgrade: websocket
和Connection: Upgrade
字段,并附上Sec-WebSocket-Accept
字段作为验证。
双方握手验收:客户端收到服务器的响应后,进行握手验证。如果验证通过,双方建立连接,可以开始进行双向通信。
下面是一个基本示例展示如何手写建立WebSocket连接的过程:
// 客户端代码
const socket = new WebSocket('ws://localhost:3000');
socket.onopen = function(event) {
console.log("WebSocket连接已打开");
// 连接成功后可以发送数据
socket.send('Hello Server');
};
socket.onmessage = function(event) {
console.log('从服务器收到消息:', event.data);
};
socket.onclose = function(event) {
if (event.wasClean) {
console.log('WebSocket连接已关闭');
} else {
console.error('连接断开');
}
};
socket.onerror = function(error) {
console.error('WebSocket错误:', error);
};
服务器端实现可能因语言和框架而异,以下是一个Node.js下的简单示例(使用ws库):
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3000 });
wss.on('connection', function connection(ws) {
console.log('WebSocket连接已建立');
ws.on('message', function incoming(message) {
console.log('从客户端收到消息:', message);
// 收到消息后可以进行处理并返回数据
ws.send('收到您的消息:' + message);
});
});
以上是WebSocket建立连接的简单描述和相关代码示例。在实际应用中,还需要考虑安全性、心跳检测、断线重连、协议版本等更多细节。
CDN
typeof、instanceof区别
手写题:instanceof
function myInstanceof(obj, constructor) {
if (typeof obj !== 'object' || obj === null) return false;
let proto = Object.getPrototypeOf(obj);
while (proto !== null) {
if (proto === constructor.prototype) {
return true;
}
proto = Object.getPrototypeOf(proto);
}
return false;
}
// 测试示例
function Person() {}
const person1 = new Person();
console.log(myInstanceof(person1, Person)); // 输出 true
["1","2","3"].map(parseInt)结果,并解释原因
如何让8返回[1,2,3] 用你能想到的最简单的方案(要求使用[].map())
怎么实现接口防刷
DOS、DDOS攻击原理和防范
JWT
手写题:删除升序链表中重复出现的所有节点[1,2,3,3,4,4,5] => [1,2,5]
function deleteDuplicates(head) {
let current = head;
while (current !== null && current.next !== null) {
if (current.val === current.next.val) {
current.next = current.next.next;
} else {
current = current.next;
}
}
return head;
}
工作经历有关提问
介绍项目、项目难点
平时怎么学习前端知识
项目给你的成长
工作地点考虑哪些城市
说说你体会最有成就感的一件事
进程、线程之间如何通信
浏览器处理AJAX请求和渲染页面是同一个进程吗,为什么
输入URL到渲染页面的全过程
HTTP1/HTTP1.1、HTTP2、HTTP3各自解决的问题
HTTP请求和TCP链接的对应关系
手写题:数组随机排序,写两种方案
// 方案一
function shuffleArray(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
// 方案二
function shuffleArray2(arr) {
return arr.sort(() => Math.random() - 0.5);
}
基础知识广泛而深入:涉及了JavaScript基础、ES6特性、异步处理、网络请求、数据结构与算法等多方面知识。
软技能考察:除技术能力外,还重点关注项目经验、沟通能力和解决问题的思路。
手写题设计理念:手写题旨在考察候选人对基础概念的理解程度和实际应用能力。
项目经验重视:通过询问项目经验,面试官希望了解候选人如何应对挑战和解决问题。
重视基础:架构部门,注重基础,着重对候选人地基的考察。
技术深度:部分问题具有一定的技术深度,要求候选人有较为扎实的技术功底。
软技能考察:强调项目经验和解决问题的能力,表明该公司注重候选人的整体素养。
手写题目设计:手写题注重实际应用场景,考察候选人对基础功能的掌握程度。
扎实基础:加强对JavaScript基础、ES6、异步处理等核心概念的理解和掌握。不同部门不同应对策略,八股文还是需要背的,一些场景提只是换了一种问法而已。
项目经验准备:准备讲解清晰、有针对性的项目经验,突出自己在项目中的贡献和解决问题的能力。
软技能展示:准备好谈论自己的沟通能力、团队合作经验和解决问题的思路,以展现出自己的全面素养。
多维度准备:除了技术准备外,也要注意对面试官可能提问的软技能问题进行准备。
实践演练:适当进行模拟面试、技术分享,以提高回答问题时的清晰度和流畅度。