0321美团实习面试——技能大致内容
专业技能
1.掌握盒⼦模型,Flex响应式布局和BFC等问题
盒⼦模型
Flex布局
媒体查询
结合Handleresize.ts监听设备
BFC
2.掌握原型链,异步,事件循环和闭包等问题
原型链
异步
class Promise {
static resolve(value) {
if (value instanceof Promise) {
return value;
}
return new Promise((resolve) => {
resolve(value);
});
}
static reject(reason) {
return new Promise((_, reject) => {
reject(reason);
});
}
static race(promises) {
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
Promise.resolve(promise).then(resolve, reject);
});
});
}
static all(promises) {
return new Promise((resolve, reject) => {
const results = [];
let completedCount = 0;
if (promises.length === 0) {
resolve(results);
return;
}
promises.forEach((promise, index) => {
Promise.resolve(promise).then(
(value) => {
results[index] = value;
completedCount++;
if (completedCount === promises.length) {
resolve(results);
}
},
(reason) => {
reject(reason);
}
);
});
});
}
constructor(executor) {
// 状态
this.status = "pending";
// 成功结果
this.value = undefined;
// 失败原因
this.reason = undefined;
// 成功回调函数队列
this.onResolvedCallbacks = [];
// 失败回调函数队列
this.onRejectedCallbacks = [];
let resolve = (value) => {
if (this.status === "pending") {
// 新的值需要是 Promise,则递归解析
if (value instanceof Promise) {
return value.then(resolve, reject);
}
this.status = "fulfilled";
this.value = value;
// 异步执行所有成功回调
this.onResolvedCallbacks.forEach((fn) => fn());
}
};
let reject = (reason) => {
if (this.status === "pending") {
this.status = "rejected";
this.reason = reason;
// 异步执行所有失败回调
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
// 执行器本身错误,直接 reject
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected = typeof onRejected === "function" ? onRejected : (reason) => {
throw reason;
};
let context = this;
return new Promise((resolve, reject) => {
function handleOnFulfilled() {
try {
const result = onFulfilled(context.value);
if (result instanceof Promise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
function handleOnRejected() {
try {
const result = onRejected(context.reason);
if (result instanceof Promise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
if (this.status === "fulfilled") {
setTimeout(() => {
handleOnFulfilled();
}, 0);
}
if (this.status === "rejected") {
setTimeout(() => {
handleOnRejected();
}, 0);
}
// 当状态为 pending 时
if (this.status === "pending") {
// onFulfilled 传入到成功数组
this.onResolvedCallbacks.push(handleOnFulfilled);
// onRejected 传入到失败数组
this.onRejectedCallbacks.push(handleOnRejected);
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onFinally) {
return this.then(
(value) => Promise.resolve(onFinally()).then(() => value),
(reason) => Promise.resolve(onFinally()).then(() => {
throw reason;
})
);
}
}
事件循环
class EventLoop {
constructor() {
this.callStack = [];
this.taskQueue = [];
this.microtaskQueue = [];
}
run() {
while (this.callStack.length > 0 || this.taskQueue.length > 0 || this.microtaskQueue.length > 0) {
// 执行同步代码
while (this.callStack.length > 0) {
const task = this.callStack.pop();
task();
}
// 执行微任务
while (this.microtaskQueue.length > 0) {
const microtask = this.microtaskQueue.shift();
microtask();
}
// 执行宏任务
if (this.taskQueue.length > 0) {
const task = this.taskQueue.shift();
task();
}
}
}
}
闭包
const counterModule = (function() {
let count = 0; // 私有变量
return {
increment: function() {
count++;
console.log(count);
},
reset: function() {
count = 0;
console.log('计数器已重置');
}
};
})();
counterModule.increment(); // 1
counterModule.increment(); // 2
counterModule.reset(); // 计数器已重置
3. 掌握Promise、⽣成器、类、接⼝和装饰器等问题
ES6 引入了许多新特性,包括 let 和 const 声明、箭头函数、模板字符串、解构赋值、默认参数、模块化、Promise、Class、Symbol、Set/Map 等,极大地提升了 JavaScript 的语法简洁性、功能性和开发效率。
TypeScript 是 JavaScript 的超集,通过添加静态类型检查、接口、泛型、枚举等特性,增强了代码的可读性、可维护性和开发效率,同时保持了与 JavaScript 的完全兼容
ES6 新特性的使用场景和优缺点、TypeScript 的类型系统、接口与类的区别、泛型的应用、模块化设计,以及两者如何结合提升开发体验和代码质量。
Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('操作成功');
} else {
reject('操作失败');
}
}, 1000);
});
promise
.then((result) => console.log(result)) // 操作成功
.catch((error) => console.error(error)); // 操作失败
```”
---
### 4. **Promise 的链式调用**
“Promise 支持链式调用,通过 `then` 方法处理成功的结果,通过 `catch` 方法处理失败的情况,还可以使用 `finally` 方法在 Promise 结束后执行清理操作。例如:
```javascript
fetch('https://api.example.com/data')
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error('请求失败', error))
.finally(() => console.log('请求结束'));
```”
---
### 5. **Promise 的静态方法**
“Promise 提供了多个静态方法,用于处理多个异步操作:
1. **Promise.all**:等待所有 Promise 成功,返回结果数组;如果有一个失败,立即返回失败原因。
2. **Promise.race**:返回第一个完成的 Promise 的结果(无论成功或失败)。
3. **Promise.allSettled**:等待所有 Promise 完成,返回每个 Promise 的结果和状态。
4. **Promise.any**:返回第一个成功的 Promise 的结果;如果全部失败,返回 AggregateError。
例如:
```javascript
const p1 = Promise.resolve('成功1');
const p2 = Promise.reject('失败2');
Promise.all([p1, p2])
.then((results) => console.log(results))
.catch((error) => console.error(error)); // 失败2
```”
---
### 6. **Promise 的应用场景**
“Promise 在前端开发中有广泛的应用场景,比如:
1. **网络请求**:通过 `fetch` 或 `axios` 发送异步请求。
2. **定时任务**:通过 `setTimeout` 或 `setInterval` 实现延时操作。
3. **文件操作**:在 Node.js 中,通过 Promise 封装文件读写操作。
4. **并发控制**:通过 `Promise.all` 实现多个异步任务的并发执行。”
---
### 7. **Promise 的注意事项**
“在使用 Promise 时,需要注意以下几点:
1. **错误处理**:确保每个 Promise 链都有 `catch` 方法,避免未捕获的错误。
2. **性能问题**:过多的 Promise 嵌套可能导致性能问题,可以通过 `async/await` 优化。
3. **状态不可逆**:Promise 的状态一旦改变,就不可再变,确保逻辑正确。”
---
### 8. **与 Async/Await 的关系**
“Async/Await 是 Promise 的语法糖,它让异步代码看起来像同步代码,更易读。例如:
```javascript
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('请求失败', error);
}
}
```”
---
### 9. **总结**
“Promise 是 JavaScript 中处理异步操作的核心机制,通过链式调用和静态方法,可以优雅地处理复杂的异步逻辑。结合 Async/Await,可以进一步提升代码的可读性和可维护性。”
---
### 10. **扩展与练习**
“为了加深理解,我平时会通过手写 Promise、实现并发控制等方式来练习。比如,手写一个简单的 Promise:
```javascript
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach((fn) => fn());
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.value = reason;
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
} else if (this.state === 'rejected') {
onRejected(this.value);
} else {
this.onFulfilledCallbacks.push(() => onFulfilled(this.value));
this.onRejectedCallbacks.push(() => onRejected(this.value));
}
}
}
⽣成器
function* generator() {
yield 1;
yield 2;
return 3;
}
const gen = generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: true }
- 生成器的特点
“生成器具有以下特点: - 暂停和恢复:通过
yield
暂停执行,通过next()
恢复执行。 - 惰性求值:生成器函数不会一次性执行完所有代码,而是按需执行。
- 双向通信:可以通过
next(value)
向生成器传递值,通过yield
返回值。”
- 生成器的应用场景
“生成器在前端开发中有多种应用场景,比如: - 异步操作:通过生成器实现类似
async/await
的异步控制流。 - 迭代器:生成器可以轻松实现自定义迭代器,用于遍历复杂数据结构。
- 状态机:生成器适合实现状态机,管理复杂的业务逻辑。
- 数据流处理:生成器可以用于处理数据流,比如分批次读取文件。”
- 生成器与异步操作
“生成器可以通过yield
暂停执行,结合Promise
可以实现类似async/await
的效果。例如:
function* fetchData() {
const response = yield fetch('https://api.example.com/data');
const data = yield response.json();
return data;
}
function run(generator) {
const gen = generator();
function handle(result) {
if (result.done) return result.value;
return Promise.resolve(result.value).then((res) => handle(gen.next(res)));
}
return handle(gen.next());
}
run(fetchData).then((data) => console.log(data));
```”
---
### 6. **生成器的注意事项**
“在使用生成器时,需要注意以下几点:
1. **性能问题**:生成器的暂停和恢复机制可能带来额外的性能开销。
2. **调试难度**:生成器的执行流程较复杂,可能增加调试难度。
3. **兼容性**:虽然现代浏览器支持生成器,但在旧环境中可能需要使用 Babel 转译。”
---
### 7. **生成器与迭代器的关系**
“生成器是迭代器的一种实现方式。通过 `yield` 关键字,生成器可以轻松实现 `Iterator` 接口。例如:
```javascript
const obj = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
},
};
for (const value of obj) {
console.log(value); // 1, 2, 3
}
```”
---
### 8. **总结**
“生成器是 JavaScript 中一种强大的工具,通过 `yield` 和 `next()` 实现了暂停和恢复执行的功能。它非常适合处理异步操作、自定义迭代器以及复杂的数据流。理解生成器有助于编写更灵活、更高效的代码。”
---
### 9. **扩展与练习**
“为了加深理解,我平时会通过手写生成器、实现异步控制流等方式来练习。比如,手写一个简单的生成器示例:
```javascript
function* fibonacci() {
let [prev, curr] = [0, 1];
while (true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
const gen = fibonacci();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
接口
interface User {
name: string;
age: number;
greet(): void;
}
```”
---
### 3. **接口的基本用法**
“接口可以用于定义对象的形状、函数的参数和返回值等。例如:
```typescript
interface Person {
name: string;
age: number;
}
const user: Person = {
name: 'Alice',
age: 25,
};
```”
---
### 4. **接口的扩展**
“接口可以通过 `extends` 关键字继承其他接口,形成更复杂的结构。例如:
```typescript
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
const dog: Dog = {
name: 'Buddy',
breed: 'Golden Retriever',
};
```”
---
### 5. **接口的可选属性和只读属性**
“接口支持可选属性和只读属性:
1. **可选属性**:通过 `?` 标记,表示属性可以不存在。
2. **只读属性**:通过 `readonly` 标记,表示属性不可修改。
例如:
```typescript
interface Config {
readonly id: number;
name?: string;
}
const config: Config = {
id: 1,
};
```”
---
### 6. **接口与类型的区别**
“接口和类型别名(`type`)都可以定义对象结构,但有以下区别:
1. **扩展性**:接口可以通过 `extends` 继承,类型别名需要通过 `&` 合并。
2. **重复声明**:接口可以重复声明,属性会自动合并;类型别名不可重复声明。
例如:
```typescript
interface User {
name: string;
}
interface User {
age: number;
}
const user: User = {
name: 'Alice',
age: 25,
};
```”
---
### 7. **接口的应用场景**
“接口在前端开发中有多种应用场景,比如:
1. **定义对象结构**:约束对象的属性和方法。
2. **函数参数和返回值**:明确函数的输入和输出类型。
3. **类实现接口**:通过 `implements` 关键字让类遵循接口的结构。
例如:
```typescript
interface Vehicle {
start(): void;
stop(): void;
}
class Car implements Vehicle {
start() {
console.log('Car started');
}
stop() {
console.log('Car stopped');
}
}
```”
---
### 8. **总结**
“TypeScript 的接口是一种强大的工具,用于定义对象的结构和行为。它通过类型检查提高了代码的可靠性和可维护性,同时支持扩展、可选属性和只读属性等功能。理解接口的使用场景和最佳实践,有助于编写更健壮的类型化代码。”
---
### 9. **潜在问题与答案**
#### **Q1: 接口和类型别名有什么区别?**
- **A1**: 接口和类型别名都可以定义对象结构,但接口支持继承(`extends`)和重复声明,而类型别名需要通过 `&` 合并且不可重复声明。接口更适合定义对象结构,类型别名更适合定义联合类型或复杂类型。
#### **Q2: 如何让一个类实现多个接口?**
- **A2**: 可以通过 `implements` 关键字让类实现多个接口,例如:
```typescript
interface A {
methodA(): void;
}
interface B {
methodB(): void;
}
class C implements A, B {
methodA() {}
methodB() {}
}
装饰器
function log(target: any, key: string, descriptor: PropertyDescriptor) {
console.log(`Called ${key}`);
}
class MyClass {
@log
myMethod() {
console.log('Executing myMethod');
}
}
```”
---
### 3. **装饰器的类型**
“装饰器可以分为以下几种类型:
1. **类装饰器**:用于修改或扩展类的行为。
2. **方法装饰器**:用于修改或扩展方法的行为。
3. **属性装饰器**:用于修改或扩展属性的行为。
4. **参数装饰器**:用于修改或扩展参数的行为。
5. **访问器装饰器**:用于修改或扩展 `getter` 和 `setter` 的行为。”
---
### 4. **装饰器的基本用法**
“装饰器通过 `@` 符号使用,可以应用于类、方法、属性或参数。例如:
```typescript
function classDecorator(constructor: Function) {
console.log('Class decorator');
}
function methodDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
console.log('Method decorator');
}
@classDecorator
class MyClass {
@methodDecorator
myMethod() {}
}
```”
---
### 5. **装饰器的应用场景**
“装饰器在前端开发中有多种应用场景,比如:
1. **日志记录**:通过装饰器自动记录方法的调用信息。
2. **权限校验**:通过装饰器验证用户权限。
3. **性能监控**:通过装饰器统计方法的执行时间。
4. **依赖注入**:通过装饰器实现依赖注入机制。
5. **表单验证**:通过装饰器验证表单字段。”
---
### 6. **装饰器的注意事项**
“在使用装饰器时,需要注意以下几点:
1. **实验性特性**:装饰器目前是实验性特性,未来可能会发生变化。
2. **性能开销**:装饰器可能会带来额外的性能开销,尤其是在复杂的应用中。
3. **调试难度**:装饰器的执行顺序和逻辑可能增加调试难度。”
---
### 7. **总结**
“TypeScript 装饰器是一种强大的工具,通过为类、方法、属性或参数添加元数据和额外功能,可以显著提高代码的可读性和可维护性。理解装饰器的使用场景和最佳实践,有助于编写更灵活、更高效的代码。”
---
### 8. **潜在问题与答案**
#### **Q1: 装饰器的执行顺序是怎样的?**
- **A1**: 装饰器的执行顺序遵循以下规则:
1. **参数装饰器**:从最后一个参数开始执行。
2. **方法/属性/访问器装饰器**:从下往上执行。
3. **类装饰器**:从上往下执行。
例如:
```typescript
function decoratorA() {
console.log('A');
}
function decoratorB() {
console.log('B');
}
@decoratorA
@decoratorB
class MyClass {} // 输出:B, A
泛型
4.了解React Fiber架构 以及Vue响应式和DIFF算法
React Fiber架构
React DIFF
Vue2&3响应式
响应式原理
数据劫持
Vue2 Object.defineProperty()
const data = { count: 0 };
// 劫持属性
Object.defineProperty(data, "count", {
get() {
console.log("读取 count");
return this._count; // 使用临时变量存储值
},
set(newVal) {
console.log("修改 count");
this._count = newVal;
}
});
data.count = 1; // 输出 "修改 count"
console.log(data.count); // 输出 "读取 count" → 1
// 依赖收集器(Dep类)
class Dep {
constructor() {
this.subs = []; // 存储所有Watcher(订阅者)
}
addSub(watcher) {
this.subs.push(watcher);
}
notify() {
this.subs.forEach(watcher => watcher.update());
}
}
// 观察者(Watcher类)
class Watcher {
constructor(data, key, callback) {
// Dep类的静态属性
Dep.target = this; // 当前Watcher实例
this.callback = callback;
//data[key]触发getter,且此时Dep.target不为空,将进行依赖收集
this.value = data[key]; // 触发属性的getter,完成依赖收集
Dep.target = null;
}
update() {
this.callback(this.value); // 数据变化时触发回调
}
}
// 数据劫持:将对象属性转为响应式
function defineReactive(obj, key, val) {
const dep = new Dep(); // 每个属性对应一个Dep实例
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.addSub(Dep.target); // 收集当前Watcher到Dep[[13]]
}
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify(); // 数据变化时通知所有订阅者[[18]]
}
});
}
// 示例使用
const data = { count: 0 };
defineReactive(data, 'count', data.count);
new Watcher(data, 'count', (newVal) => {
console.log('视图更新:', newVal);
});
data.count = 1; // 输出:视图更新: 1
Vue3 Proxy
const data = { count: 0 };
const proxy = new Proxy(data, {
get(target, prop) {
console.log(`读取 ${prop}`);
return Reflect.get(target, prop);
},
set(target, prop, value) {
console.log(`修改 ${prop} 为 ${value}`);
return Reflect.set(target, prop, value);
}
});
proxy.count = 1; // 输出 "修改 count 为 1"
console.log(proxy.count); // 输出 "读取 count" → 1
// 依赖收集器(Dep类同上)
class Dep {
constructor() {
this.subs = []; // 存储所有Watcher(订阅者)
}
addSub(watcher) {
this.subs.push(watcher);
}
notify() {
this.subs.forEach(watcher => watcher.update());
}
}
// 观察者(Watcher类)
class Watcher {
constructor(data, key, callback) {
// Dep类的静态属性
Dep.target = this; // 当前Watcher实例
this.callback = callback;
//data[key]触发getter,且此时Dep.target不为空,将进行依赖收集
this.value = data[key]; // 触发属性的getter,完成依赖收集
Dep.target = null;
}
update() {
this.callback(this.value); // 数据变化时触发回调
}
}
// `全局依赖映射表`(存储对象属性对应的Dep实例)
const targetMap = new WeakMap();
// 数据劫持:Proxy代理对象
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
const dep = getDep(target, key);
dep.addSub(Dep.target); // 收集依赖[[20]]
return Reflect.get(target, key);
},
set(target, key, newVal) {
const dep = getDep(target, key);
const result = Reflect.set(target, key, newVal);
dep.notify(); // 触发更新[[12]]
return result;
}
});
}
// 获取属性对应的Dep实例
function getDep(target, key) {
//1.每个对象对应一个map连接到全局依赖映射表
let depsMap = targetMap.get(target);
if (!depsMap) {
depsMap = new Map();
targetMap.set(target, depsMap);
}
//2.每个属性对应一个map连接到对象的映射表
let dep = depsMap.get(key);
if (!dep) {
dep = new Dep();
depsMap.set(key, dep);
}
return dep;
}
// 示例使用
const data = reactive({ count: 0 });
new Watcher(data, 'count', (newVal) => {
console.log('Proxy视图更新:', newVal);
});
data.count = 2; // 输出:Proxy视图更新: 2
发布订阅
// 创建一个简单的发布订阅者管理类
class EventEmitter {
constructor() {
this.events = {}; // 用于存储事件的字典,键为事件名,值为订阅者数组
}
// 订阅事件
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = []; // 如果该事件尚未被订阅,则初始化一个空数组
}
this.events[eventName].push(callback); // 将回调函数添加到订阅者数组中
return this; // 支持链式调用
}
// 取消订阅事件
off(eventName, callback) {
if (this.events[eventName]) {
// 移除指定的回调函数
this.events[eventName] = this.events[eventName].filter(cb => cb !== callback);
// 如果订阅者数组为空,则删除该事件
if (this.events[eventName].length === 0) {
delete this.events[eventName];
}
}
return this; // 支持链式调用
}
// 发布事件
emit(eventName, ...args) {
if (this.events[eventName]) {
// 遍历订阅者数组,并执行每个回调函数
this.events[eventName].forEach(callback => {
callback.apply(this, args);
});
}
return this; // 支持链式调用
}
// 可选:监听一次后自动取消订阅
once(eventName, callback) {
const onceCallback = (...args) => {
callback.apply(this, args);
this.off(eventName, onceCallback);
};
this.on(eventName, onceCallback);
return this; // 支持链式调用
}
}
// 使用示例
const eventBus = new EventEmitter();
// 订阅者1
function subscriber1(price) {
console.log('订阅者1收到消息:当前价格已降至' + price + '元');
}
// 订阅者2
function subscriber2(price) {
console.log('订阅者2也收到消息:价格更新为' + price + '元');
}
// 订阅事件
eventBus.on('priceUpdate', subscriber1);
eventBus.on('priceUpdate', subscriber2);
// 使用once方法监听一次
eventBus.once('specialOffer', (offer) => {
console.log('只接收一次的特别优惠:' + offer);
});
// 发布事件
eventBus.emit('priceUpdate', 99); // 订阅者1和订阅者2都会收到消息
eventBus.emit('specialOffer', '买一赠一'); // 只有一个订阅者会收到这个特别优惠的消息
// 取消订阅
eventBus.off('priceUpdate', subscriber1);
eventBus.emit('priceUpdate', 88); // 只有订阅者2会收到消息
模板解译
Vue2&3 Diff
5.Redux、React-Router、Ant Design和Webpack等React⼯程化⼯具库
Redux
const fetchFoodsList = () => {
return async (dispatch) => {
// 编写异步逻辑
const res = await axios.get('http://localhost:3004/takeaway')
// 调用dispatch函数提交action
dispatch(setFoodsList(res.data))
}
}
——————————————————————————————————————————————————————————————————————————————————
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchFoodsList } from './actions'; // 假设actions.js是你的action creators文件
const FoodsComponent = () => {
const dispatch = useDispatch();
const foodsList = useSelector(state => state.foodsList); // 假设你的state结构中有foodsList
useEffect(() => {
dispatch(fetchFoodsList());
}, [dispatch]);
return (
<div>
{/* 渲染foodsList */}
</div>
);
}
React-Router
React-router面试常考
Ant Design
Webpack
Webpack
devServer: {
host: '0.0.0.0',
port: port,
open: false,
proxy: {
[process.env.VUE_APP_BASE_API]: {
target: `http://localhost:8080`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
},
// Tomcat上的资源+项目部署在Tomcat上则不存在跨域
[process.env.VUE_APP_BASE_TOM]: {
target: `http://localhost:8010`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_TOM]: ''
}
},
[process.env.VUE_APP_BASE_PY]:{
target: `http://localhost:5010`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_PY]: ''
}
}
},
disableHostCheck: true
},
6.熟练使⽤Vuex、Pinia、Vue-Router、Element-UI和Vite等Vue⼯程化⼯具库
Vue2&Vue3&React
生命周期
React钩子
Vuex&Pinia
Vue-Router
Element-UI
Vue中动态样式绑定+CSS变量实现切换明暗主题功能——从入门到进阶
Vue3+Element Plus项目国际化_vue-i18n
<template>
<div>
<h1>{{ $t('message.hello') }}</h1>
<p>{{ $t('message.welcome') }}</p>
<el-button @click="toggleLanguage">切换语言</el-button> <!-- Element Plus 按钮 -->
</div>
</template>
<script>
import { useI18n } from 'vue-i18n'
export default {
setup() {
const { t, locale } = useI18n()
const toggleLanguage = () => {
const newLang = locale.value === 'zh' ? 'en' : 'zh'
locale.value = newLang // 切换语言
}
return {
t,
toggleLanguage
}
}
}
</script>
<style scoped>
/* 样式可以根据需要进行调整 */
</style>
Vite
7.掌握单例、⼯⼚、观察者、发布订阅、代理和装饰器等设计模式
以下是基于 JavaScript 实现的常见设计模式的代码示例和简要分析,包括 单例模式、工厂模式、观察者模式、发布订阅模式、代理模式 和 装饰器模式。
1. 单例模式 (Singleton Pattern)
代码实现
class Singleton {
constructor() {
if (Singleton.instance) {
return Singleton.instance; // 如果实例已存在,直接返回
}
this.name = "Singleton Instance";
Singleton.instance = this; // 保存实例
}
getName() {
return this.name;
}
}
// 测试
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // true
console.log(instance1.getName()); // Singleton Instance
分析
• 核心思想:确保一个类只有一个实例,并提供全局访问点。
• 应用场景:数据库连接池、日志记录器、配置管理器等需要全局唯一的场景。
2. 工厂模式 (Factory Pattern)
代码实现
class Car {
constructor(type) {
this.type = type;
}
drive() {
console.log(`${this.type} car is driving.`);
}
}
class CarFactory {
createCar(type) {
return new Car(type);
}
}
// 测试
const factory = new CarFactory();
const car1 = factory.createCar("Sedan");
const car2 = factory.createCar("SUV");
car1.drive(); // Sedan car is driving.
car2.drive(); // SUV car is driving.
分析
• 核心思想:通过工厂类封装对象的创建逻辑,客户端无需关心具体的创建过程。
• 应用场景:需要根据条件动态创建对象的场景,比如创建不同类型的 UI 组件。
3. 观察者模式 (Observer Pattern)
代码实现
class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} received data: ${data}`);
}
}
// 测试
const subject = new Subject();
const observer1 = new Observer("Observer1");
const observer2 = new Observer("Observer2");
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notify("Hello Observers!");
// Observer1 received data: Hello Observers!
// Observer2 received data: Hello Observers!
分析
• 核心思想:主题(Subject)维护一组观察者(Observer),当主题状态发生变化时,通知所有观察者。
• 应用场景:事件监听器、数据绑定(如 Vue 的响应式系统)。
4. 发布订阅模式 (Pub/Sub Pattern)
代码实现
class EventBus {
constructor() {
this.events = {};
}
subscribe(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
unsubscribe(event, callback) {
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
publish(event, data) {
if (this.events[event]) {
this.events[event].forEach(callback => callback(data));
}
}
}
// 测试
const eventBus = new EventBus();
const callback1 = data => console.log(`Callback1: ${data}`);
const callback2 = data => console.log(`Callback2: ${data}`);
eventBus.subscribe("message", callback1);
eventBus.subscribe("message", callback2);
eventBus.publish("message", "Hello Pub/Sub!");
// Callback1: Hello Pub/Sub!
// Callback2: Hello Pub/Sub!
eventBus.unsubscribe("message", callback1);
eventBus.publish("message", "Hello again!");
// Callback2: Hello again!
分析
• 核心思想:发布者和订阅者通过事件总线(Event Bus)解耦,发布者只负责发布消息,订阅者只负责接收消息。
• 应用场景:消息队列、事件驱动架构。
5. 代理模式 (Proxy Pattern)
代码实现
class RealSubject {
request() {
console.log("RealSubject: Handling request.");
}
}
class Proxy {
constructor(realSubject) {
this.realSubject = realSubject;
}
request() {
console.log("Proxy: Preprocessing request.");
this.realSubject.request();
console.log("Proxy: Postprocessing request.");
}
}
// 测试
const realSubject = new RealSubject();
const proxy = new Proxy(realSubject);
proxy.request();
// Proxy: Preprocessing request.
// RealSubject: Handling request.
// Proxy: Postprocessing request.
分析
• 核心思想:代理类控制对真实对象的访问,可以在访问前后添加额外的逻辑。
• 应用场景:权限控制、懒加载、日志记录。
6. 装饰器模式 (Decorator Pattern)
代码实现
class Coffee {
cost() {
return 5; // 基础咖啡价格
}
}
class MilkDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 2; // 加牛奶的价格
}
}
class SugarDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 1; // 加糖的价格
}
}
// 测试
let coffee = new Coffee();
console.log("Basic Coffee:", coffee.cost()); // 5
coffee = new MilkDecorator(coffee);
console.log("Milk Coffee:", coffee.cost()); // 7
coffee = new SugarDecorator(coffee);
console.log("Milk and Sugar Coffee:", coffee.cost()); // 8
分析
• 核心思想:通过装饰器动态扩展对象的功能,而不改变其原始结构。
• 应用场景:功能扩展、插件系统。
7.总结对比
设计模式 | 核心思想 | 应用场景 |
---|---|---|
单例模式 | 确保一个类只有一个实例,并提供全局访问点。 | 数据库连接池、日志记录器、配置管理器。 |
工厂模式 | 封装对象的创建逻辑,客户端无需关心具体的创建过程。 | 动态创建不同类型的 UI 组件。 |
观察者模式 | 主题维护一组观察者,状态变化时通知所有观察者。 | 事件监听器、数据绑定。 |
发布订阅模式 | 发布者和订阅者通过事件总线解耦,发布者只负责发布消息,订阅者只负责接收消息。 | 消息队列、事件驱动架构。 |
代理模式 | 代理类控制对真实对象的访问,可以在访问前后添加额外的逻辑。 | 权限控制、懒加载、日志记录。 |
装饰器模式 | 动态扩展对象的功能,而不改变其原始结构。 | 功能扩展、插件系统。 |
8.熟悉并掌握WebGL技术,掌握渲染管线、着⾊器编程和主流开源三维引擎
9. 熟悉使⽤Express开发RSETful API,通过分层架构解耦业务逻辑,增强系统可拓展性
10 掌握使⽤Git进⾏协作开发、Apifox进⾏测试,以及Ngnix、Tomcat进⾏部署
Git
Nginx
测试&CI/CD
一文弄懂前端CI/CD——原理、流程以及相关内容详解
11.计算机网络与浏览器