前端哪有什么设计模式
前言
- 常网IT源码上线啦!
- 本篇录入吊打面试官专栏,希望能祝君拿下Offer一臂之力,各位看官感兴趣可移步🚶。
- 有人说面试造火箭,进去拧螺丝;其实个人觉得问的问题是项目中涉及的点 || 热门的技术栈都是很好的面试体验,不要是旁门左道冷门的知识,实际上并不会用到的。
- 接下来想分享一些自己在项目中遇到的技术选型以及问题场景。
你生命的前半辈子或许属于别人,活在别人的认为里。那把后半辈子还给你自己,去追随你内在的声音。
一、前言
之前在讨论设计模式、算法的时候,一个后端组长冷嘲热讽的说:前端哪有什么设计模式、算法,就好像只有后端语言有一样,至今还记得那不屑的眼神。
今天想起来,就随便列几个,给这位眼里前端无设计模式的人,睁眼看世界。
二、观察者模式 (Observer Pattern)
观察者模式的核心是当数据发生变化时,自动通知并更新相关的视图。在 Vue 中,这通过其响应式系统实现。
Vue 2.x:Object.defineProperty
在 Vue 2.x 中,响应式系统是通过 Object.defineProperty
实现的。每当访问某个对象的属性时,getter
会被触发;当设置属性时,setter
会触发,从而实现数据更新时视图的重新渲染。
源码(简化版):
function defineReactive(obj, key, val) {
// 创建一个 dep 实例,用于收集依赖
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
// 当访问属性时,触发 getter,并把当前 watcher 依赖收集到 dep 中
if (Dep.target) {
dep.addDep(Dep.target);
}
return val;
},
set(newVal) {
if (newVal !== val) {
val = newVal;
dep.notify(); // 数据更新时,通知所有依赖重新渲染
}
}
});
}
Dep
类:它管理依赖,addDep
用于添加依赖,notify
用于通知所有依赖更新。
class Dep {
constructor() {
this.deps = [];
}
addDep(dep) {
this.deps.push(dep);
}
notify() {
this.deps.forEach(dep => dep.update());
}
}
- 依赖收集:当 Vue 组件渲染时,会创建一个
watcher
对象,表示一个视图的更新需求。当视图渲染过程中访问数据时,getter
会触发,并将watcher
添加到dep
的依赖列表中。
Vue 3.x:Proxy
Vue 3.x 使用了 Proxy
来替代 Object.defineProperty
,从而实现了更高效的响应式机制,支持深度代理。
源码(简化版):
function reactive(target) {
const handler = {
get(target, key) {
// 依赖收集:当访问某个属性时,触发 getter,收集依赖
track(target, key);
return target[key];
},
set(target, key, value) {
// 数据更新时,通知相关的视图更新
target[key] = value;
trigger(target, key);
return true;
}
};
return new Proxy(target, handler);
}
track
:收集依赖,确保只有相关组件更新。trigger
:当数据发生变化时,通知所有依赖重新渲染。
三、发布/订阅模式 (Publish/Subscribe Pattern)
发布/订阅模式通过中央事件总线(Event Bus)实现不同组件间的解耦,Vue 2.x 中,组件间的通信就是基于这种模式实现的。
Vue 2.x:事件总线(Event Bus)
事件总线就是一个中央的事件处理器,Vue 实例可以充当事件总线,用来处理不同组件之间的消息传递。
// 创建一个 Vue 实例作为事件总线
const EventBus = new Vue();
// 组件 A 发布事件
EventBus.$emit('message', 'Hello from A');
// 组件 B 订阅事件
EventBus.$on('message', (msg) => {
console.log(msg); // 输出 'Hello from A'
});
$emit
:用于发布事件。$on
:用于订阅事件。$off
:用于取消订阅事件。
四、工厂模式 (Factory Pattern)
工厂模式通过一个函数生成对象或实例,Vue 的组件化机制和动态组件加载就是通过工厂模式来实现的。
Vue 的 render
函数和 functional
组件支持动态生成组件实例。例如,functional
组件本质上是一个工厂函数,通过给定的 props
返回一个 VNode。
Vue.component('dynamic-component', {
functional: true,
render(h, context) {
// 工厂模式:根据传入的 props 创建不同的 VNode
return h(context.props.type);
}
});
functional
组件:它没有实例,所有的逻辑都是在render
函数中处理,返回的 VNode 就是组件的“产物”。
五、单例模式 (Singleton Pattern)
单例模式确保某个类只有一个实例,Vue 实例就是全局唯一的。
在 Vue 中,全局的 Vue
构造函数本身就是一个单例对象,通常只会创建一个 Vue 实例,用于管理应用的生命周期和全局配置。
const app = new Vue({
data: {
message: 'Hello, Vue!'
}
});
- 单例保证:整个应用只有一个 Vue 实例,所有全局的配置(如
Vue.config
)都是共享的。
六、模板方法模式 (Template Method Pattern)
模板方法模式定义了一个操作中的算法框架,而将一些步骤延迟到子类中。Vue 的生命周期钩子就是一个模板方法模式的实现。
Vue 定义了一系列生命周期钩子(如 created
、mounted
、updated
等),它们实现了组件从创建到销毁的完整过程。开发者可以在这些钩子中插入自定义逻辑。
Vue.component('my-component', {
data() {
return {
message: 'Hello, 泽!'
};
},
created() {
console.log('Component created');
},
mounted() {
console.log('Component mounted');
},
template: '<div>{{ message }}</div>'
});
Vue 组件的生命周期钩子实现了模板方法模式的核心思想,开发者可以根据需要重写生命周期钩子,而 Vue 保证生命周期的流程和框架。
七、策略模式 (Strategy Pattern)
策略模式通过定义一系列算法,将它们封装起来,使它们可以相互替换。Vue 的 计算属性(computed) 和 方法(methods) 可以看作是策略模式的应用。
计算属性允许我们定义动态的属性,其值是基于其他属性的计算结果。Vue 会根据依赖关系缓存计算结果,只有在依赖的属性发生变化时,计算属性才会重新计算。
new Vue({
data() {
return {
num1: 10,
num2: 20
};
},
computed: {
sum() {
return this.num1 + this.num2;
}
}
});
八、装饰器模式 (Decorator Pattern)
装饰器模式允许动态地给对象添加功能,而无需改变其结构。在 Vue 中,指令就是一种装饰器模式的应用,它通过指令来动态地改变元素的行为。
<div v-bind:class="className"></div>
<div v-if="isVisible">谁的疯太谍</div>
这些指令动态地修改 DOM 元素的行为,类似于装饰器在不修改对象结构的情况下,动态地增强其功能。
九、代理模式 (Proxy Pattern)
代理模式通过创建一个代理对象来控制对目标对象的访问。在 Vue 3.x 中,响应式系统就是通过 Proxy
来代理对象的访问。
vue3
const state = reactive({
count: 0
});
state.count++; // 会触发依赖更新
reactive:使用 Proxy 对对象进行代理,当对象的属性被访问或修改时,都会触发代理器的 get 和 set 操作。
function reactive(target) {
const handler = {
get(target, key) {
// 依赖收集:当访问某个属性时,触发 getter,收集依赖
track(target, key);
return target[key];
},
set(target, key, value) {
// 数据更新时,触发依赖更新
target[key] = value;
trigger(target, key);
return true;
}
};
return new Proxy(target, handler);
}
track
:当读取目标对象的属性时,收集依赖,这通常涉及到将当前的watcher
加入到依赖列表中。trigger
:当对象的属性发生改变时,通知所有相关的依赖(如组件)更新。
这个 Proxy
机制使得 Vue 可以动态地观察和更新对象的变化,比 Object.defineProperty
更具灵活性。
十、适配器模式 (Adapter Pattern)
适配器模式用于将一个类的接口转换成客户端期望的另一个接口,使得原本不兼容的接口可以一起工作。Vue 的插槽(Slots)和组件的跨平台支持某种程度上借用了适配器模式的思想。
Vue 插槽机制
Vue 的插槽机制是通过提供一个适配层,将父组件传入的内容插入到子组件的指定位置。开发者可以使用具名插槽、作用域插槽等方式,实现灵活的插槽传递。
<template>
<child-component>
<template #header>
<h1>This is the header</h1>
</template>
<p>This is the default content</p>
</child-component>
</template>
父组件通过 #header
插槽插入了一个标题内容,而 child-component
会将其插入到适当的位置。这里,插槽充当了一个适配器,允许父组件插入的内容与子组件的内容结构灵活匹配。
十全十美
至此撒花~
后记
我相信技术不分界,不深入了解,就不要轻易断言。
一个圆,有了一个缺口,不知道的东西就更多了。
但是没有缺口,不知道的东西就少了。
这也就是为什么,知道得越多,不知道的就越多。
谢谢!
最后,祝君能拿下满意的offer。
我是Dignity_呱,来交个朋友呀,有朋自远方来,不亦乐乎呀!深夜末班车
👍 如果对您有帮助,您的点赞是我前进的润滑剂。
以往推荐
原文链接
来源:juejin.cn/post/7444215159289102347