适用场景
需要根据场景判断出运行函数,且场景值不改变。
实现示例(惰性加载函数)
lazyLoad = function (...args) {
if (condition1) {
lazyLoad = () => {
// 做了一下事情...
}
} else if (condition2) {
lazyLoad = () => {
// 做了一下事情...
}
} else {
lazyLoad = () => {
// 做了一下事情...
}
}
lazyLoad.apply(this, args);
}
原始版本
function imgPreview(el) {
if (el.target.tagName.toLowerCase() !== 'img') {
return;
}
// ios端纷享侧使用prewiew插件有问题,走内部的软件
if (FS.CONST.isFSBrowser) {
// 用移动端组件...
} else {
// 用web端组件...
}
}
iframe.contentWindow.addEventListener('click', imgPreview);
该方法通过if来判断代码的运行环境,来区分调用不同的预览组件。
但这有个弊端就是,每次触发click事件,都要进行一次if判断,而代码的运行环境是不会在函数每次调用间改变的(至页面加载之后,移动端就会一直运行于移动端,web端就一直运行于web端)。
利用惰性加载函数优化
let imgPreview = (e) => {
// ios端纷享侧使用prewiew插件有问题,走内部的软件
if (FS.CONST.isFSBrowser) {
imgPreview = (el) => {
if (el.target.tagName.toLowerCase() !== 'img') {
return;
}
// 用移动端组件...
};
} else {
imgPreview = (el) => {
if (el.target.tagName.toLowerCase() !== 'img') {
return;
}
// 用web端组件...
};
}
imgPreview(e);
};
利用惰性加载函数,可以在imgPreview的第一次调用时,进行环境判断,并将对应的处理函数重新赋值给imgPreview,使得之后的调用可以直接进行处理而不用再判断环境。
但这仍有一个问题,就是执行函数(重新赋值过后的imgPreview)里面的拦截逻辑需要写两次(判断dom是否是img),且这两处的拦截逻辑是应该一直相同的。
封装变化(代理模式)
let imgPreview = (e) => {
// ios端纷享侧使用prewiew插件有问题,走内部的软件
if (FS.CONST.isFSBrowser) {
imgPreview = (el) => {
// 用移动端组件...
};
} else {
imgPreview = (el) => {
// 用web端组件...
};
}
imgPreview(e);
};
const imgClickHandler = (el) => {
if (el.target.tagName.toLowerCase() !== 'img') {
return;
}
imgPreview(el);
};
iframe.contentWindow.addEventListener('click', imgClickHandler);
这个是代码的最终版本,《JavaScript设计模式与开发实践》中有一句话是“当我们想办法把程序中变化的部分封装好之后,剩下的即是稳定而可复用的部分了”。 我们可以将代码中“不变的”,即imgPreview的拦截逻辑,抽离处理。将“变化的”,即不同环境下不同组件的调用,封装起来。