闭包实现面向对象设计
闭包的思想是: 一个函数想用一个引用一个外部变量,但是有不想让这个变量暴露在全局环境中,那么就使用闭包。闭包一般有两种使用形式,一个是立即执行的闭包,一种是用时执行的闭包。两种有和区别呢?
立即执行的闭包,用于全局创建一个闭包对象
用时执行的闭包,可用于全局创建多个闭包对象
//立即执行的模式
var matchEmail = (function() {
var regx = /^\w+(\.\w+)*@\w+\.\w{2,3}(\.\w{2,3})?$/;
return function(email) {
return regx.test(email);
}
})();
console.log(matchEmail('535.fu@qq.com'));
//用时执行的模式
var matchEmail2 = function() {
var regx = /^\w+(\.\w+)*@\w+\.\w{2,3}(\.\w{2,3})?$/;
return function(email) {
return regx.test(email);
}
}
var matchEmail2 = matchEmail2();
console.log(matchEmail('535.fu@qq.com'));
两者有啥区别呢?容易看出,用时执行模式,每次在创建一个新的matchEmail2时候,都会新建一个闭包,和创建一个新的 regx
立即执行啥时候用呢? 一般是在封装的遍历在函数引用中都是有同一个时,如果不同情况需要使用多个,那么使用 用时执行
很显然,我们如果想要创建一个对象系统的话,需要用用时执行模式
var Events = function() {
var handlers = {};
var subscribe = function(type, handler) {
if (!handlers[type]) {
handlers[type] = [];
}
handlers[type].push(handler);
//存储当前这个handler是否被订阅
var isSubscribed = true;
//每次执行一个订阅函数,返回一个取消订阅回调,只要使用这个函数,那么就取消
return function unsubscribe() {
if (!isSubscribed) return; //防止多次执行
isSubscribed = false;
const index = handlers[type].indexOf(handler);
handlers[type].splice(index, 1);
}
}
function dispatch(type) {
if (handlers[type]) {
for (let i = 0; i < handlers[type].length; i++) {
handlers[type][i]();
}
}
}
//闭包对象系统,返回一个对象
return {
subscribe,
dispatch
}
}
//创建一个event对象
var event = Events();
//创建另外一个event对象
var event1 = Events();
var unSubscribe = event.subscribe('click', function() {console.log('event click')});
event1.subscribe('click', function() {console.log('event1 click')});
event.dispatch('click');
event1.dispatch('click');
unSubscribe();
event.dispatch('click');
上面创建的两个对象 event event1 互不干扰
利用闭包创建对象系统的话,利用闭包封装想用的局部变量,然后返回一个对象,对象里面是向外提供的接口
tips:上面的订阅一个函数,然后返回一个取消点阅函数,也是一种非常不错的发布 取消点阅模式中的编程思想哦,利用闭包,在订阅的时候就封闭了订阅时的函数,那么取消点阅的时候,就一定能访问到这个函数