哈,大家好,我是千羽。分享一下来自深圳大学的朋友滴滴秋招一面的面经。
这一次滴滴面试官问了很多问题,主要是围绕着简历去展开。有问了node进程,还有express等等。手撕的代码比较多,对,然后还变到了vue2和vue3,目前Vue3的话现在是全面使用。
然后是写了大概有四五道算法题吧,总体来说还是比较强度比较大的,不过我这边硬着头皮扛下来的。
Express和Koa都是基于Node.js的服务端框架,主要用于处理HTTP请求和响应。它们都提供了中间件的概念,但是中间件的实现方式以及框架本身的特性有所不同。
new Koa()
的方式来创建一个新的Koa实例。const Koa = require('koa');
const compose = require('koa-compose');
const app = new Koa();
// 定义一些中间件函数
const middleware1 = async (ctx, next) => {
console.log('Middleware 1');
await next();
};
const middleware2 = async (ctx, next) => {
console.log('Middleware 2');
await next();
};
// 使用compose函数组合中间件
app.use(compose([middleware1, middleware2]));
app.listen(3000);
定义了两个中间件函数middleware1和middleware2,然后使用koa-compose的compose函数将它们组合在一起。在app.use中,我们使用这个组合后的中间件。当一个请求来到时,它首先会经过middleware1,然后经过middleware2。在每个中间件中,都会打印一条日志,并调用next函数来将控制权传递给下一个中间件。
以下是一个使用try-catch和抛错的Koa Compose函数的示例代码:
const Koa = require('koa');
const compose = require('koa-compose');
const app = new Koa();
// 定义一个中间件函数,用于抛出错误
const throwError = async (ctx, next) => {
console.log('Throwing error');
throw new Error('An error occurred');
};
// 定义一个中间件函数,用于捕获错误并返回错误信息
const catchError = async (ctx, next) => {
try {
await next();
} catch (err) {
console.log('Error caught');
ctx.status = 500;
ctx.body = 'An error occurred';
}
};
// 使用compose函数组合中间件,并按照从外到内的顺序执行
app.use(compose([catchError, throwError]));
app.listen(3000);
Webpack是一个用于现代JavaScript应用程序的静态模块打包工具。它能够很好地管理与打包开发中所用到的HTML、JavaScript、CSS以及各种静态文件(图片、字体等)。以下是Webpack的主要特性和理解:
Vue2和Vue3在许多方面存在显著差异,包括双向数据绑定原理、是否支持碎片、API类型、定义数据变量和方法以及性能优化等方面。
在Vue中,attrs 是一个特殊的属性,用于传递父组件中没有被子组件的props捕获的属性。这意味着,当父组件传递一个属性给子组件,但子组件没有使用props来接收这个属性时,这个属性会被放入attrs中。
attrs包含父作用域中不被prop所识别(且获取)的特性绑定(class和style除外)。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(class和style除外),并且可以通过v-bind="
在Vue 2.4版本中,为了解决该需求,引入了attrs和listeners,新增了inheritAttrs选项。
使用attrs时,需要注意的是,如果子组件需要接收父组件传递的属性,应该使用props来接收,而不是依赖attrs。因为
Vue中有三种插槽:普通插槽、具名插槽和作用域插槽。
最长公共子串问题是一个经典的动态规划问题,而 LeetCode 1143 的题目要求是找到两个字符串的中间公共子串。这个问题的本质和最长公共子串问题是一样的,只是目标变成了找到中间的子串,而不是最长的子串。
下面是一个 Java 实现的例子:
public class Solution {
public String middle(String word1, String word2) {
int m = word1.length();
int n = word2.length();
int[][] dp = new int[m+1][n+1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (word1.charAt(i-1) == word2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1] + 1;
} else {
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
}
}
}
int len = dp[m][n];
int mid = (m + n - len) / 2;
StringBuilder sb = new StringBuilder();
for (int i = m - 1, j = n - 1; len > 0; len--) {
if (word1.charAt(i) == word2.charAt(j)) {
sb.append(word1.charAt(i));
i--;
j--;
} else if (dp[i-1][j] > dp[i][j-1]) {
i--;
} else {
j--;
}
}
return sb.reverse().toString();
}
}
深拷贝在JavaScript中通常是指复制一个对象,包括其所有的属性和子对象,而不共享任何引用。这是一种非常重要的操作,因为它可以防止原始对象被修改。
这是最简单的方法,但是它不能处理循环引用的情况,也不能处理函数和其他非JSON类型的属性。
function deepCopyUsingJSON(obj) {
return JSON.parse(JSON.stringify(obj));
}
这种方法可以处理更复杂的情况,包括函数、循环引用等。但是它需要更多的代码。
function deepCopyUsingRecursion(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
let copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopyUsingRecursion(obj[key]);
}
}
return copy;
}
有一些第三方库如 lodash 的 _.cloneDeep 方法可以方便的实现深拷贝。但这是建立在引入外部库的基础上的。
在JavaScript中,可以使用typeof运算符或instanceof运算符来判断数据类型。
var num = 123;
console.log(typeof num); // 输出 "number"
var str = "hello";
console.log(typeof str); // 输出 "string"
var obj = {};
console.log(typeof obj); // 输出 "object"
typeof运算符可以判断基本数据类型,包括number、string、boolean、null、undefined、symbol等。对于对象类型,typeof运算符返回"object",但需要注意的是,对于数组和函数类型,typeof运算符也会返回"object"。
var arr = [];
console.log(arr instanceof Array); // 输出 "true"
var func = function() {};
console.log(func instanceof Function); // 输出 "true"
instanceof运算符可以判断对象是否是某个构造函数或类实例。对于数组和函数类型,可以使用Array和Function构造函数来判断。对于自定义对象类型,可以使用自定义构造函数来判断。需要注意的是,instanceof运算符对于基本数据类型和null类型不起作用。
发布-订阅模式(Pub-Sub)是一种消息传递模式,其中发送者(发布者)发送消息,而接收者(订阅者)通过注册来接收消息。应用场景:事件驱动的系统、实时应用等。
以下是一个简单的发布-订阅模式的JavaScript实现:
class EventBus {
constructor() {
this.subscribers = {};
}
subscribe(event, callback) {
if (!this.subscribers[event]) {
this.subscribers[event] = [];
}
this.subscribers[event].push(callback);
}
publish(event, data) {
if (this.subscribers[event]) {
this.subscribers[event].forEach(callback => callback(data));
}
}
}
// 使用示例:
const eventBus = new EventBus();
// 订阅事件
eventBus.subscribe('message', (data) => {
console.log(`Received message: ${data}`);
});
// 发布事件
eventBus.publish('message', 'Hello, world!'); // 输出: Received message: Hello, world!
这个简单的实现中,有一个EventBus
类,它维护了一个subscribers
对象,该对象存储了每个事件的订阅者(回调函数)。subscribe
方法允许订阅者注册他们感兴趣的事件,而publish
方法允许发布者发布一个事件,这会触发所有注册了该事件的订阅者。
负载均衡器实现:
在实现负载均衡器时,可以选择不同的算法来选择服务器。
END