function testDec(target) {
target.isDec = true
}
console.log(Demo.isDec)
//输出true
打印出来了true,说明@testDec这个装饰器已经成功了,函数是个装饰器,用@testDec给Demo装饰了一遍。这个target其实就是class Demo,然后给她加一个isDec。
拆解后就是下面的内容:
// 装饰器原理
@decorator
class A {}
// 等同于
class A {}
A = decorator(A) || A;
装饰器参数的形式
@testDec(false)
class Demo {
}
function testDec(isDec) {
return function (target) {
target.isDec = isDec
}
}
console.log(Demo.isDec);
验证是否是一个真正的装饰器模式需要验证以下几点:
1.将现有对戏那个和装饰器进行分离,两者独立存在
2.符合开放封闭原则
2. 适配器模式
适配器模式:旧接口格式和使用者不兼容,中间加一个适配转换接口。
比如国外的插座跟国内的插座不一样,我们需要买个转换器去兼容。
上代码:
class Adaptee {
specificRequest() {
return ‘德国标准的插头’;
}
}
class Target {
constructor() {
this.adaptee = new Adaptee();
}
request() {
let info = this.adaptee.specificRequest();
return ${info} -> 转换器 -> 中国标准的插头
}
}
// 测试
let client = new Target();
client.request();
结果:
德国标准的插头 -> 转换器 -> 中国标准的插头
场景上可封装旧接口:
// 自己封装的ajax,使用方式如下:
ajax({
url: ‘/getData’,
type: ‘Post’,
dataType: ‘json’,
data: {
id: ‘123’
}
}).done(function(){
})
// 但因为历史原因,代码中全都是:
// $.ajax({…})
这个时候需要一个适配器:
// 做一层适配器
var $ = {
ajax: function (options) {
return ajax(options)
}
}
3. 代理模式
代理模式:使用者无权访问目标对象,中间加代理,通过代理做授权和控制。
明星经纪人:比如有个演出,要请明星,要先联系经纪人。
或者理解为:为一个对象提供一个代用品或者占位符,以便控制对它的访问。例如图片懒加载、中介等。
/**
-
pre:代理模式
-
小明追求A,B是A的好朋友,小明比不知道A什么时候心情好,不好意思直接将花交给A,
-
于是小明将花交给B,再由B交给A.
*/
// 花的类
class Flower{
constructor(name){
this.name = name
}
}
// 小明拥有sendFlower的方法
let Xioaming = {
sendFlower(target){
var flower = new Flower(“玫瑰花”)
target.receive(flower)
}
}
// B对象中拥有接受花的方法,同时接收到花之后,监听A的心情,并且传入A心情好的时候函数
let B = {
receive(flower){
this.flower =flower
A.listenMood(()=>{
A.receive(this.flower)
})
}
}
// A接收到花之后输出花的名字
let A = {
receive(flower){
console.log(A收到了${flower.name}
)
// A收到了玫瑰花
},
listenMood(func){
setTimeout(func,1000)
}
}
Xioaming.sendFlower(B)
虚拟代理用于图片的预加载
图片很大,页面加载时会空白,体验不好,所以我们需要个占位符,来短暂替代这个图片,等图片加载好了放上去。
let myImage = (function(){
let img = new Image
document.body.appendChild(img)
return {
setSrc:(src)=>{
img.src = src
}
}
})()
let imgProxy =(function(){
let imgProxy = new Image
// 这个地方我使用了setTimeout来增强演示效果,否则本地加载太快,根本看不到。
imgProxy.οnlοad=function(){
setTimeout(()=>{
myImage.setSrc(this.src)
},2000)
}
return (src)=>{
myImage.setSrc(“…/…/img/bgimg.jpeg”)
imgProxy.src=src
}
})()
imgProxy(“…/…/img/background-cover.jpg”)
ES6 Proxy
其实在ES6中,已经有了Proxy,这个内置的函数。我们来用一个例子来演示一下他的用法。这是一个明星代理的问题。
let star={
name : “张XX”,
age:25,
phone : “1300001111”
}
let agent = new Proxy(star,
{
get:function(target,key){
if(key === “phone”){
return “18839552597”
}else if(key === “name”){
return “张XX”
}else if(key === “price”){
return “12W”
}else if(key === “customPrice”){
return target.customPrice
}
},
set:function(target,key,value){
if(key === “customPrice”){
if(value < “10”){
console.log(“太低了!!!”)
return false
}else{
target[key] = value
return true
}
}
}
}
)
console.log(agent.name)
console.log(agent.price)
console.log(agent.phone)
console.log(agent.age)
agent.customPrice = “12”
console.log(agent)
console.log(agent.customPrice)
设计原则验证
代理类和目标类分离,隔离开目标类和使用者
符合开放封闭原则
行为型模式
1. 策略模式
策略模式是一种简单却常用的设计模式,它的应用场景非常广泛。我们先了解下策略模式的概念,再通过代码示例来更清晰的认识它。
策略模式由两部分构成:一部分是封装不同策略的策略组,另一部分是 Context。通过组合和委托来让 Context 拥有执行策略的能力,从而实现可复用、可扩展和可维护,并且避免大量复制粘贴的工作。
策略模式的典型应用场景是表单校验中,对于校验规则的封装。接下来我们就通过一个简单的例子具体了解一下:
/**
- 登录控制器
*/
function LoginController() {
this.strategy = undefined;
this.setStrategy = function (strategy) {
this.strategy = strategy;
this.login = this.strategy.login;
}
}
/**
- 用户名、密码登录策略
*/
function LocalStragegy() {
this.login = ({ username, password }) => {
console.log(username, password);
// authenticating with username and password…
}
}
/**
- 手机号、验证码登录策略
*/
function PhoneStragety() {
this.login = ({ phone, verifyCode }) => {
console.log(phone, verifyCode);
// authenticating with hone and verifyCode…
}
}
/**
- 第三方社交登录策略
*/
function SocialStragety() {
this.login = ({ id, secret }) => {
console.log(id, secret);
// authenticating with id and secret…
}
}
const loginController = new LoginController();
// 调用用户名、密码登录接口,使用LocalStrategy
app.use(‘/login/local’, function (req, res) {
loginController.setStrategy(new LocalStragegy());
loginController.login(req.body);
});
// 调用手机、验证码登录接口,使用PhoneStrategy
app.use(‘/login/phone’, function (req, res) {
loginController.setStrategy(new PhoneStragety());
loginController.login(req.body);
});
// 调用社交登录接口,使用SocialStrategy
app.use(‘/login/social’, function (req, res) {
loginController.setStrategy(new SocialStragety());
loginController.login(req.body);
});
从以上示例可以得出使用策略模式有以下优势:
-
方便在运行时切换算法和策略
-
代码更简洁,避免使用大量的条件判断
-
关注分离,每个strategy类控制自己的算法逻辑,strategy和其使用者之间也相互独立
2. 观察者模式
观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一或一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。典型代表vue/react等。
使用观察者模式的好处:
-
支持简单的广播通信,自动通知所有已经订阅过的对象。
-
目标对象与观察者存在的是动态关联,增加了灵活性。
-
目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。
当然给元素绑定事件的addEventListener()
也是一种:
target.addEventListener(type, listener [, options]);
Target就是被观察对象Subject,listener就是观察者Observer。
观察者模式中Subject对象一般需要实现以下API:
-
subscribe()
: 接收一个观察者observer对象,使其订阅自己 -
unsubscribe()
: 接收一个观察者observer对象,使其取消订阅自己 -
fire()
: 触发事件,通知到所有观察者
用JavaScript手动实现观察者模式:
// 被观察者
function Subject() {
this.observers = [];
}
Subject.prototype = {
// 订阅
subscribe: function (observer) {
this.observers.push(observer);
},
// 取消订阅
unsubscribe: function (observerToRemove) {
this.observers = this.observers.filter(observer => {
return observer !== observerToRemove;
})
},
// 事件触发
fire: function () {
this.observers.forEach(observer => {
observer.call();
});
}
}
验证一下订阅是否成功:
const subject = new Subject();
function observer1() {
console.log(‘Observer 1 Firing!’);
}
function observer2() {
console.log(‘Observer 2 Firing!’);
}
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.fire();
输出:
Observer 1 Firing!
Observer 2 Firing!
验证一下取消订阅是否成功:
subject.unsubscribe(observer2);
subject.fire();
输出:
Observer 1 Firing!
3. 迭代器模式
ES6中的迭代器 Iterator 相信大家都不陌生,迭代器用于遍历容器(集合)并访问容器中的元素,而且无论容器的数据结构是什么(Array、Set、Map等),迭代器的接口都应该是一样的,都需要遵循 迭代器协议。
迭代器模式解决了以下问题:
-
提供一致的遍历各种数据结构的方式,而不用了解数据的内部结构
-
提供遍历容器(集合)的能力而无需改变容器的接口
一个迭代器通常需要实现以下接口:
-
hasNext()
:判断迭代是否结束,返回Boolean -
next()
:查找并返回下一个元素
为Javascript的数组实现一个迭代器可以这么写:
const item = [1, ‘red’, false, 3.14];
function Iterator(items) {
this.items = items;
this.index = 0;
}
Iterator.prototype = {
hasNext: function () {
return this.index < this.items.length;
},
next: function () {
return this.items[this.index++];
}
}
验证一下迭代器:
const iterator = new Iterator(item);
while(iterator.hasNext()){
console.log(iterator.next());
}
输出:
1, red, false, 3.14
ES6提供了更简单的迭代循环语法 for...of
,使用该语法的前提是操作对象需要实现 可迭代协议(The iterable protocol),简单说就是该对象有个Key为 Symbol.iterator
的方法,该方法返回一个iterator对象。
比如我们实现一个 Range
类用于在某个数字区间进行迭代:
function Range(start, end) {
return {
[Symbol.iterator]: function () {
return {
next() {
if (start < end) {
return { value: start++, done: false };
}
return { done: true, value: end };
}
}
}
}
}
验证:
for (num of Range(1, 5)) {
console.log(num);
}
结果:
1, 2, 3, 4
4. 状态模式
状态模式:一个对象有状态变化,每次状态变化都会触发一个逻辑,不能总是用if…else来控制。
比如红绿灯:
// 状态(红灯,绿灯 黄灯)
class State {
constructor(color) {
this.color = color;
}
// 设置状态
handle(context) {
console.log(turn to ${this.color} light
);
context.setState(this)
}
}
// 主体
class Context {
constructor() {
this.state = null;
}
// 获取状态
getState() {
return this.state;
}
setState(state) {
this.state = state;
}
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
更多面试题
**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等
// 设置状态
handle(context) {
console.log(turn to ${this.color} light
);
context.setState(this)
}
}
// 主体
class Context {
constructor() {
this.state = null;
}
// 获取状态
getState() {
return this.state;
}
setState(state) {
this.state = state;
}
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-PW1ig61o-1713669423200)]
[外链图片转存中…(img-rMaNQ39M-1713669423201)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
[外链图片转存中…(img-24BdBvnT-1713669423201)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
[外链图片转存中…(img-s3to2kdn-1713669423201)]
更多面试题
**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等
[外链图片转存中…(img-UqlE2BnJ-1713669423202)]