一、工厂模式

工厂模式例子:$() React.createElement()

class Product {
    constructor(name) {
        this.name = name
    }
    init() {
        alert('init')
    }
    func1() {
        console.log('func1')
    }
    func2() {
        console.log('func2')
    }
}
/**
 * 工厂
 */
class Creater {
    create(name) {
        return new Product(name)
    }
}

const creater = new Creater();
const p1 = creater.create('p1');

二、单例模式

单利模式有:$ 登录框 购物车 vuex和redux中的store

class SingleObject {
    constructor(){
        console.log('this',this)
    }
    login() {
        console.log('login...')
    }
}

// 单例模式,实例只是实例一次
// 且只能内部去实例(当然因为js原因,外部去 new SingleObject()也不会报错)
SingleObject.getInstance = (() => {
    let instance;
    return function () {
        if (!instance) {
            instance = new SingleObject();
        }
        return instance;
    }
})()

const obj1 = SingleObject.getInstance();
obj1.login();
const obj2 = SingleObject.getInstance();
obj2.login();
// console.log(obj1 === obj2); // true

登录弹出框实现方式

class LoginForm {
    constructor() {
        this.state = 'hide'
    }
    show() {
        if (this.state === 'show') {
            alert('已经是show了');
            return;
        }
        this.state = 'show'
        console.log('====>show')
    }
    hide() {
        if (this.state === 'hide') {
            alert('已经是hide了');
            return;
        }
        this.state = 'hide'
        console.log('====>hide')
    }
}

LoginForm.getInstance = (() => {
    let form;
    return function () {
        if (!form) {
            form = new LoginForm()
        }
        return form
    }
})();

const page1login = LoginForm.getInstance();
page1login.show();
const page2login = LoginForm.getInstance();
page1login.hide();

三、适配器模式

使用场景:封装旧接口 vue中的computed

class Adaptee {
    specificRequest() {
        return '德国标准插头'
    }
}

class Target {
    constructor() {
        this.adaptee = new Adaptee()
    }
    request(){
        let info = this.adaptee.specificRequest();
        return  `${info} - 转换器 - 中国标准插头`
    }
}

let target = new Target();
console.log(target.request())

四、装饰器模式

装饰器模式:添加新功能 装饰一下,不改变原来的功能,只是扩展

1、手动实现装饰器

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

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

const circle = new Circle();
circle.draw();

const dec = new Decorator(circle);
dec.draw()
dec.setRedBorder()

2、ES6装饰器

@testDec
class Demo {

}

function testDec(target) {
    target.isDec = '黑黑';
}
console.log(Demo)
alert(Demo.isDec)
// 装饰类加参数
@testDec(true)
class Demo {

}

function testDec(isDec) {
    return function (target) {
        target.isDec = isDec;
    }
}
console.log(Demo)
alert(Demo.isDec)

3、实现log装饰器

class Math {
    constructor(a, b) {
        this.a = a;
        this.b = b;
    }
    @log
    add() {
        return this.a + this.b
    }
}

function log(target, name, descripter) {
    const oldValue = descripter.value;
    descripter.value = function () {
        console.log(`calling ${name} with `,arguments)
        return oldValue.apply(this, arguments); // 因为oldValue不是在target里定义的,所以需要指定this
    }
    return descripter;
}

const math = new Math(1,2);
console.log(math.add())

4、mixin

function mixin(...list) {
    return function (target) {
        Object.assign(target.prototype, ...list)
    }
}

const Foo = {
    foo() {
        alert('fool')
    }
}

@mixin(Foo)
class MyClass {

}

const my = new MyClass();
my.foo()

5、readonly

// 装饰方法
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    @readonly
    detail() {
        return `NAME: ${this.name}\n AGE: ${this.age}`
    }
}

/**
 * 装饰方法
 * @param {*} target 默认
 * @param {*} name 默认
 * @param {*} descripter 
 */
function readonly(target, name, descripter) {
    console.log(target,name,descripter)
    descripter.writable = false;
    return descripter  //可以注掉
}

const persion = new Person('lihaixing', 31);

console.log(persion.detail())

// 以下会报错
persion.detail = function () {
    console.log(111)
}

6、装饰器插件

import { readonly, deprecate } from 'core-decorators';
class Person {
    constructor() {
        this.name = 'zhangsan'
    }

    @readonly
    sayName() {
        return this.name
    }

    @deprecate('即将费用')
    say() {
        console.log(this.name)
    }
}

const person = new Person();
// person.sayName = function () {}

person.say()

五、代理模式

    1. 网页事件代理
    1. Jquery中 $.proxy
    1. ES6中 Proxy

1 手动实现代理

class RealImg {
    constructor(fileName) {
        this.fileName = fileName;
        this.loadFromDisk()
    }
    display(){
        console.log(`display ${this.fileName}`)
    }
    loadFromDisk(){
        console.log(`loading ${this.fileName} from disk`)
    }
}

class ProxyImg {
    constructor(fileName){
        this.realImg = new RealImg(fileName);
    }

    display(){
        this.realImg.display()
    }
}

const proxyImg = new ProxyImg('xxx.png')
proxyImg.display()

2、ES6代理

let star = {
    name: 'zhang xxx',
    age: 25,
    phone: 'star: 13453452359'
}

let agent = new Proxy(star, {
    get: function (target, key) {
        if (key === 'phone') {
            // 返回经纪人电话
            return 'agent: 158588585885'
        }
        if (key === 'price') {
            // 明星不报价,经纪人报价
            return 120000
        }

        return target[key]
    },
    set: function (target, key, value) {
        if (key === 'customPrice') {
            if (value < 100000) {
                throw new Error('价格太低')
            } else {
                target[key] = value
                return true
            }
        }
    }
})

// test
console.log(agent.name)
console.log(agent.age)
console.log(agent.phone)
console.log(agent.price)

agent.customPrice=110000
console.log('agent.customPrice: ',agent.customPrice)

3、jquery代理

import $ from 'jquery'

$('.myText').click(function () {
    setTimeout(function () {
        $(this).css('background-color', 'red')
    })
})

$('.myText').click(function () {
    const fn = function () {
        $(this).css('background-color', 'red')
    }
    setTimeout($.proxy(fn, this))
})

六、观察者模式

观察者模式和发布订阅模式区别:

  • 订阅发布模式需要三种角色,发布者、事件中心和订阅者。
  • 观察者模式需要两种角色,目标和观察者,无事件中心负责通信。

发布订阅场景

    1. jquery网页事件绑定
    1. promise
    1. jquery callbacks
    1. nodejs自定义事件
class Subject {
    constructor() {
        this.state = 0;
        this.observers = [];
    }
    getState() {
        return this.state
    }

    setState(state) {
        this.state = state;
        this.notifyAllObservers()
    }

    notifyAllObservers() {
        this.observers.forEach((observer) => {
            observer.update()
        })
    }

    attach(observer) {
        this.observers.push(observer)
    }
}
  
class Observer {
    constructor(name, subject) {
        this.name = name;
        this.subject = subject;
        // 初始化一个观察者,就要把观察者加到观察者列表中
        this.subject.attach(this);
    }

    update() {
        console.log(`${this.name} updated, state: ${this.subject.getState()}`)
    }
}
  
const s = new Subject();
const observer1 = new Observer('gcz1', s);
const observer2 = new Observer('gcz2', s);
const observer3 = new Observer('gcz3', s);
s.setState(1);
s.setState(2);

七、迭代器模式

1、手写迭代器模式

class Container {
    constructor(list) {
        this.list = list
    }
    getIterator() {
        return new Iterator(this)
    }
}
  
class Iterator {
    constructor(container) {
        this.list = container.list;
        this.index = 0;
    }

    hasNext() {
        return this.index < this.list.length
    }
    next() {
        if (this.hasNext()) {
            return this.list[this.index++]
        }
        return null
    }
}
  
const container = new Container([1, 2, 3, 4, 5]);
window.it1 = container.getIterator();
window.it2 = container.getIterator();

2、es6迭代器

/**
* 场景
* 1. 有序集合:Array Map Set String TypedArray arguments NodeList
* 2. Object 不是有序集合 需要用Map代替
* 3. 一个迭代器可以遍历各种有序数据
* 4. for of 就是迭代器
*/
  
// Array.prototype[Symbol.iterator] 是一个迭代器函数
  
const arr = [1, 2, 3, 4];
const iter = arr[Symbol.iterator]();
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
  
// 也返回迭代器
const iter2 = arr.values()
console.log(iter2.next())
console.log(iter2.next())

八、状态模式

同一个上下文,切换不同的state

class State {
    constructor(color) {
        this.color = color;
    }
    handle(context) {
        context.setState(this)
    }
}
  
class Context {
    constructor() {
        this.state = null
    }
    getState() {
        return this.state;
    }
    setState(state) {
        this.state = state;
    }
}
  
/**
* 状态模式
* state不变,只是一直在改变上下文context中的state
* 场景:不同的页面,相似的数据
*/
const context = new Context();
const red = new State('red');
red.handle(context);
  
const green = new State('green');
green.handle(context);
  
console.log(context.getState())

九、其它模式还有

桥接模式、中介着模式、备忘录模式、原型模式等
github


lihaixing
463 声望719 粉丝

前端就爱瞎折腾


« 上一篇
前端算法题
下一篇 »
webpack3升级4