两天被问四次,可是我不会,关于前端设计模式

最近面了几家,有一个问题出现的频率过于高了。刚好准备时候没有覆盖到这部分,于是只能和面试官尬聊。 这个问题就是,你平时开发时候用到哪些开发模式。我只能凭着记忆说说单例模式,发布订阅模式啥的,驴头不对马嘴。至于面试结果,想必是不尽人意了。
那么,前端到底有哪些设计模式平时会用到呢。

单例模式

保证一个类只有一个实例,并提供一个全局访问点。
实现方法:先判断实例是否存在,不存在先创建后返回,存在则直接返回。
实际应用: 模态框,以及弹框,vuex中的store,mobx里的store。

let CreateDiv = function(html) {
        this.html = html;
};
let Singleton = (function() {
    let instance;
    return function(html) {
        if (!instance) {
            instance = new CreateDiv(html);
        }
        return instance;
    }
})();
let a = new Singleton('seven1');
let b = new Singleton('seven2');
console.log(a);
console.log(b);
console.log(a === b); // truej

工厂模式

工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型。

class Person {
    constructor(name) {
        this.name = name
    }
    getName() {
        console.log(this.name)
    }
}
class Factory {
    static create(name) {
        return new Person(name)
    }
}
Factory.create('caicai').getName()  //caicai

适配器模式

适配器模式就相当于一个转换接口,大家想想我们手机充电器通常是二岔口的,但是电源只有三岔口的。这时候就需要一个适配器把三岔口的转换成二岔口的。
它的作用其实就是解决两个软件实体间的接口不兼容问题,使用之后就可以一起工作了。

var googleMap = {
    show: function () {
        console.log('googleMap show!');
    }
}
var baiduMap = {
    display: function () {
        console.log('baiduMap show!');
    }
}

var renderMap = function (map) {
    if (map.show instanceof Function) {
        map.show()
    }
}

// 让baiduMap可以调用show方法
var baiduMapAdapter = {
    show:function(){
        return baiduMap.display()
    }
}
renderMap(googleMap);
renderMap(baiduMapAdapter);

代理模式

我们在事件代理的时候其实就是使用了代理模式,通过把监听事件全部交由父节点进行监听,这样你添加节点或者删除节点的时候就不用去改变监听的代码。
实际应用: 跨域、 事件代理

<ul id="ul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>
<script>
    let ul = document.querySelector('#ul')
    ul.addEventListener('click', (event) => {
        console.log(event.target);
    })
</script>
// ES6中的Proxy对象
const target = {}
const handler = {
    get(target, property) {
        if (property in target) {
            return target[property]
        } else {
            throw new ReferenceError("Property \"" + property + "\" does not exist.")
        }
    }
}
const p = new Proxy(target, {})
p.a = 3  // 被转发到代理的操作
console.log(p.c) //

发布-订阅模式

定义了一种依赖关系, 解决了主体对象与观察者之间功能的耦合
实际应用:vue的中央事件总线

// 这里想到一个前几天遇到的面试题,使用 ECMAScript(JS)代码实现一个事件类Event ,包含下面功能:绑定事件、解绑事件和派发事件。这里可以使用发布订阅模式
class Event {
  constructor () {
    // 储存事件的数据结构
    // 为查找迅速, 使用对象(字典)
    this._cache = {}
  }
 
  // 绑定
  on(type, callback) {
    // 为了按类查找方便和节省空间
    // 将同一类型事件放到一个数组中
    // 这里的数组是队列, 遵循先进先出
    // 即新绑定的事件先触发
    let fns = (this._cache[type] = this._cache[type] || [])
    if(fns.indexOf(callback) === -1) {
      fns.push(callback)
    }
    return this
  }
 
  // 触发
  trigger(type, data) {
    let fns = this._cache[type]
    if(Array.isArray(fns)) {
      fns.forEach((fn) => {
        fn(data)
      })
    }
    return this
  }
  
  // 解绑
  off (type, callback) {
    let fns = this._cache[type]
    if(Array.isArray(fns)) {
      if(callback) {
        let index = fns.indexOf(callback)
        if(index !== -1) {
          fns.splice(index, 1)
        }
      } else {
        // 全部清空
        fns.length = 0
      }
    }
    return this
  }
}

策略模式

根据情况进行不一样的方案,比如你想去旅游,明确自己有多少钱然后选择旅游方式。

  • 没钱,走路
  • 有钱,飞机
  • 还行,火车
var strategies = {
    "rich": function () {
        console.log("You can go with plane!");
    },
    "poor": function () {
        console.log("OH, You can go with your feet!");
    },
    "middle": function () {
        console.log("You can go with train!");
    }
}
var howShouldGo = function (money) {
    return strategies[money]();
}
console.log(howShouldGo("rich"));

迭代器模式

迭代器模式是指提供一种按顺序访问的方法。比如说我们经常使用的forEach方法,就是通过顺序访问的模式。我们可以自己去写一下forEach的方法。

var myForEach = function (arr, callback) {
    for (var i = 0, l = arr.length; i < l; i++) {
        callback.call(arr[i], i, arr[i]) //把元素以及下标传递出去
    }
}f

myForEach([1, 2, 3], function (item, n) {
    console.log([item, n]);
})
//[ 0, 1 ]
//[ 1, 2 ]
//[ 2, 3 ]

《两天被问四次,可是我不会,关于前端设计模式》上有1条评论

发表评论

邮箱地址不会被公开。 必填项已用*标注