一、单例模式
定义:保证一个类只有一个实例,并提供一个访问它的全局访问点
有一些对象我们往往只需要一个,比如登陆浮窗
let createIframe = (function(){
let iframe
return function(){
if(!iframe){
}
return iframe
}
})()
将变与不变的隔离出来,逻辑始终是:用一个变量标志是否创建过对象,如果是,则在下次直接返回这个已经创建好的对象
二、策略模式
定义:定义一系列的算法,把它们一个个封装起来,并且使他们可以互相替换
比如表单验证,普通的表单验证缺点
Ⅰ函数庞大,包含很多if-else语句
Ⅱ函数缺乏弹性,如果增加了一种新的校验规则,必须深入函数内部实现,违反开放-封闭原则
Ⅲ算法的复用性差,如果在程序中增加了另一个表单,这个表单也需要一些类似的校验,那我很可能将这些校验
function test(){
let strategies = { //将校验逻辑封装成策略模式
isNonEmpty:function(value,errorMsg){
if(value === ''){
return errorMsg
}
},
minLength:function(value,length,errorMsg){
if(value.length<length){
return errorMsg
}
}
}
//校验类
let Validator = function(){
this.cache = []//保存校验规则
}
Validator.prototype.add = function(dom,rule,errorMsg){
let arr = rule.split(':')//把strategy和参数分开
this.cache.push(()=>{
let strategy = arr.shift() //获取要验证的校验逻辑
arr.unshift(dom.value) //添加要验证的值
arr.push(errorMsg) //将errmsg添加进参数列表
return strategies[strategy].apply(dom,arr)
})
}
Validator.prototype.start = function(){ //
for(let i = 0,validator;validator=this.cache[i++];){
let msg = validator() //开始校验规则
if(msg){ //若返回消息说明错误
return msg
}
}
}
let validatorFunc = function(){
let validator = new Validator()
validator.add(document.getElementById('test'),'isNonEmpty','用户名不能为空')
let errorMsg = validator.start() //获得校验结果
console.log(errorMsg)
return errorMsg
}
}
3、js中奇特的for循环写法
//正常的for循环
for(var i=0;i<10;i++){
console.log(i);
}
//输出:1,2,3……10
//简写
for(var i=10;i--;){
console.log(i);
}
//输出:9,8,7,……0
//变种:
for(var i=-10;i++;){
console.log(i*-1);
}
//输出:9,8,7,……0
因为在js中,0,null,undefined,false,'',""作为条件判断时,其结果为false
if(0)相当于if(false)
if(!0)相当于if(true)
for终止循环时是这样的
for(var i=10;0;){}
4、new function()和function()有什么区别
new
做了三件事:
var instance = {};
instance.__proto__ = ShowUsers.prototype;
ShowUsers.call(obj);
简单来说,它改变了内部this
的指向(不适用new时,this
指向全局window
or global
),还有继承了原型链
5、代理模式
定义:为一个对象提供一个代用品或占位符,以便控制对它的访问
保护代理和虚拟代理
保护代理用于控制不同权限的对象对于目标对象的访问,但在js无法判断谁访问了某个对象
虚拟代理把一些开销很大的对象,延迟到真正需要它的时候才去创建
虚拟代理应用:
①通过代理对象在图片被加载好之前,页面中将出现一张占位的loading.gif,来提示用户图片正在加载
let myImage = (function (){
let imgNode = document.createElement('img')
document.body.append(imgNode)
return {
setSrc:function(src){
imgNode.src =src
}
}
})()
let proxyImg = ()=>{
let img = new Image
img.onload = function(){
myImage.setSrc(this.src)
}
return{
setSrc:function(src){
myImage.setSrc('')
img.src = src
}
}
}
如上通过proxyImage间接访问MyImage,proxyImage控制了客户对myImage的访问。并且在此过程中加入一些额外的操作。比如真正的图片加载之前,先把img节点的src设置为一张本地的loading图片
为什么一个小小的图片预加载功能要用到代理模式?,这就需要引入一面向对象设计的原则--单一职责原则
单一原则指的是,就一个类而言,应该仅有一个引起他变化的原因。 如果一个对象承担了多项原则,意味着这个对象将变得巨大,引起他变化的原因可能有多个。
②虚拟代理合并HTTP请求
在web开发中,也许最大的开销就是网络请求。解决方案是,通过一个代理函数proxySysnchronousFile来手机一段时间之内的请求,最后一次性发送给服务器(如果不是对实时性要求非常高的系统,1s/2s的延迟不会带来太大副作用,却能大大减轻服务器的压力)
let proxySysnchronousFile = function(id){
let cache = []
let timer
return function(id){
cache.push(id)//保存请求
if(timer){
return
}
timer = setTimeout(()=>{
//发送请求
clearTimeout(timer)
timer = null
cache.length = 0
},2000)
}
}
5.2、缓存代理
缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时如果传递进来的参数跟之前一致,则可以直接返回前面存储的运算结果。
缓存代理用于ajax异步请求数据