JavaScript开发者应懂的33个概念26-设计模式

本文介绍了JavaScript开发中常见的26个设计模式,如工厂模式、单例模式、策略模式等,通过实例阐述了它们的用途和应用场景,帮助开发者提升代码组织和复用性。
摘要由CSDN通过智能技术生成

JavaScript开发者应懂的33个概念26-设计模式

目录

  1. 调用堆栈
  2. 原始类型
  3. 值类型和引用类型
  4. 隐式, 显式, 名义和鸭子类型
  5. == 与 ===, typeof 与 instanceof
  6. this, call, apply 和 bind
  7. 函数作用域, 块级作用域和词法作用域
  8. 闭包
  9. map, reduce, filter 等高阶函数
  10. 表达式和语句
  11. 变量提升
  12. Promise async 与 wait
  13. 立即执行函数, 模块化, 命名空间
  14. 递归
  15. 算法
  16. 数据结构
  17. 消息队列和事件循环
  18. setTimeout, setInterval 和 requestAnimationFrame
  19. 继承, 多态和代码复用
  20. 按位操作符, 类数组对象和类型化数组
  21. DOM 树和渲染过程
  22. new 与构造函数, instanceof 与实例
  23. 原型继承与原型链
  24. Object.create 和 Object.assign
  25. 工厂函数和类
  26. 设计模式
  27. Memoization
  28. 纯函数, 函数副作用和状态变化
  29. 耗性能操作和时间复杂度
  30. JavaScript 引擎
  31. 二进制, 十进制, 十六进制, 科学记数法
  32. 偏函数, 柯里化, Compose 和 Pipe
  33. 代码整洁之道

简介

记录一个重新学习javascript的过程 ,文章并不是按顺序写的,写完就会更新目录链接 本篇文章目录是参照 @leonardomso 创立,英文版项目地址在这里

1.工厂模式

工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。

大白话说的意思就是:更方便地去创建实例 比如vue中 axios.create就是工厂模式的运用 axios.create()每次返回的都是一个全新的实例

例子

function createPerson(name, age, gender) {
    var person = new Object();
    person.name = name;
    person.age = age;
    person.gender = gender;
    person.sayName = function () {
        console.log(this.name);
    }
    return person;
}
//利用工厂函数来创建对象
var person1 = createPerson("zhangsan", 18, 'male');
var person2 = createPerson("lisi", 20, 'female');

createPerson就像一个工厂 我们只需传入不通的参数便可以创建出来不通的新的对象

2.单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点,这样的模式就叫做单例模式。

使用场景 Vuex: Vuex实现了一个全局的 Store 用于存储应用的所有状态。这个 Store 的实现,正是单例模式的典型应用,用Vue.use()方法,我们安装了 Vuex 插件。Vuex 插件是一个对象,它在内部实现了一个 install 方法,这个方法会在插件安装时被调用,从而把 Store 注入到Vue实例里去。也就是说每 install 一次,都会尝试给 Vue 实例注入一个 Store

使用场景 还有弹出全局模态框

例子

// 单例模式
var Singleton = function(name){
    this.name = name;
};
Singleton.prototype.getName = function(){
    return this.name;
}
// 获取实例对象
var getInstance = (function() {
    var instance = null;//闭包中改变的变量相当于一个全局变量
    return function(name) {
        console.log("111",instance);
        console.log("222",name)
        if(!instance) {
            instance = new Singleton(name);
        }
        return instance;
    }
})();
// 测试单体模式的实例
var a = getInstance("aa");
var b = getInstance("bb");
var c = getInstance("cc");
console.log(a === b); // true

console.log(a.getName());// aa

console.log(b.getName());// aa
console.log(c.getName());//aa

单例模式大白话的意思就是: 一个类只能构造出唯一实例 然后在全局使用

3.策略模式

根据不同参数可以命中不同的策略

优点

  1. 能减少大量的 if 语句
  2. 复用性好

年终奖的 demo, 根据不同的参数(level)获得不同策略方法(规则), 这是策略模式在 JS 比较经典的运用之一

const S = function(salary) {
    return salary * 4
}

const A = function(salary) {
    return salary * 3
}

const B = function(salary) {
    return salary * 2
}

const calculateBonus = function(func, salary) {
    return func(salary)
}

calculateBonus(A, 10000) // 30000
calculateBonus(S, 20000) // 80000
calculateBonus(B, 30000) // 60000

4.适配器模式

适配器模式通俗点说就是:将一种格式适配成你所需要的格式

适配器模式可用来在现有接口和不兼容的类之间进行适配。它被添加到现有代码中来协调两个不同的接口。就类似于苹果电脑的 type-c 接口和U盘之间的接口转换器。

我们现在客户系统有一个对象 clientObj,而我们有一个现有的方法 interfaceMethod:

var clientObj = {
    name: 'Jack',
    phone: '13333333333',
    address: 'China'
}
function interfaceMethod(str1, str2, str3){
    ...
}
 

这时要把 clientObj 作为参数传给这个方法,需要一个适配器:

function clientToInterfaceAdapter(o) {
    interfaceMethod(o.name, o.phone, o.address)
}
// 利用适配器传递对象
clientToInterfaceAdapter(clientObj)

适配器模式在 vue 中的应用

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'hello'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

message 这个属性的值是 ‘Hello’,但我想要的是一个倒转的 ‘Hello’, 通过computed 中的 reversedMessage 方法, 我们得到了目标 ‘olleh’,且没有改变原有的数值。这里的 reversedMessage 就相当于一个适配器。

适配器模式在 ts 中的应用

type Person = {
  name?: string,
  age?: number
}

5.装饰器模式

原有方法维持不变,在原有方法上再挂载其他方法来满足现有需求,装饰器模式通俗点说就是:定义一个类,在不改这个类的前提下,给这个类拓展功能

例子

class Circle{
    draw() {
        console.log('画一个圆形')
    }
}

class Decorator {
    constructor(circle) {
        this.circle = circle
    }
    draw() {
        this.circle.draw()
        this.setRedBorder(circle)
    }
    setRedBorder(circle) {
        console.log('设置红色边框')
    }
}

// 测试
let circle = new Circle()
circle.draw()

let dec = new Decorator(circle)
dec.draw()

6.代理模式

在JavaScript中,代理模式是一种常见的设计模式,它允许我们在不改变对象本身的情况下,通过代理对象来控制对象的访问

代理模式通俗易懂点说就是:为对象提供一种代理,便以控制对这个对象的访问,不能直接访问目标对象

最好的实践场景就是ES6 Proxy

let target = {
    name: 'Tom',
    age: 18
};

let proxy = new Proxy(target, {
    get(target, key) {
        console.log(`get ${key}`);
        return target[key];
    },
    set(target, key, value) {
        console.log(`set ${key}=${value}`);
        target[key] = value;
    }
});

proxy.name; // 输出:get name
proxy.age = 20; // 输出:set age=20

7.观察者模式

当观察对象发生变化时自动调用相关函数,观察者模式通俗点讲就是:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知

生活中场景的例子就是

某人对某个事情敢兴趣,不是自己一直盯着那个事情,而是发生的事件对象 去通知对这个事情敢兴趣的人

例子

//观察者设计模式
//发布者 -->商家
var shopObj = {};
//商品列表 [key:[]], key为商品名
shopObj.list = [];
//订阅方法
shopObj.listen = function ( key, fn) {// key是商品型号, fn这个函数就是订阅的行为
    if (!this.list[key]) {
        this.list[key] = [];
    }
    this.list[key].push(fn);//往商品名为key的商品列表中添加订阅
}
//发布消息方法
shopObj.publish = function (key) {
    //var key = arguments[0];//如果不传参数key,这样也可以
    var fns = this.list[key];
    // for (var i = 0; i < fns.length; i++) {
    for(var i = 0 ,fn; fn = fns[i++];){
        //执行订阅的函数fn  arguemnts储存的所有实参
        // var fn = fns[i++];
        fn.apply(this, arguments)
    }
}
//A用户添加订阅
shopObj.listen("华为", function (brand, model) {
    console.log( "A用户收到:" + brand + model + "手机降价了");
})
//B用户添加订阅
shopObj.listen("华为", function (brand, model) {
    console.log("B用户收到:" + brand + model + "手机降价了");
})
//c用户添加订阅
shopObj.listen("小米", function (brand, model) {
    console.log("C用户收到:" + brand + model + "手机降价了");
})
//双11 商家发布消息华为降价的信息
shopObj.publish("华为", "p30");
shopObj.publish("小米", "Mix4");

8.发布订阅模式

我们使用的vue框架就是发布订阅模式,先借用官网的双向绑定原理图:

img

下面稍微解释一下这个图(框架源码整个过程比较复杂,如果现在看不懂下面几段也没关系,大致了解一下即可)。

组件渲染函数(Component Render Function)被执行前,会对数据层的数据进行响应式化。响应式化大致就是使用 Object.defineProperty 把数据转为 getter/setter,并为每个数据添加一个订阅者列表的过程。这个列表是 getter 闭包中的属性,将会记录所有依赖这个数据的组件。

  • 也就是说,响应式化后的数据相当于发布者。
  • 每个组件都对应一个 Watcher 订阅者。当每个组件的渲染函数被执行时,都会将本组件的 Watcher 放到自己所依赖的响应式数据的订阅者列表里,这就相当于完成了订阅,一般这个过程被称为依赖收集(Dependency Collect)。
  • 组件渲染函数执行的结果是生成虚拟 DOM 树(Virtual DOM Tree),这个树生成后将被映射为浏览器上的真实的 DOM 树,也就是用户所看到的页面视图。
  • 当响应式数据发生变化的时候,也就是触发了 setter 时,setter 会负责通知(Notify)该数据的订阅者列表里的 WatcherWatcher 会触发组件重渲染(Trigger re-render)来更新(update)视图。

这就是发布订阅模式 有兴趣的同学可以去研究一下源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值