一:工厂模式javascript
工厂模式相似于现实生活中的工厂能够产生大量类似的商品的流水线,去作一样的事情,实现一样的效果;这时候须要使用工厂模式。html
简单的工厂模式能够理解为解决多个类似的问题;这也是它的优势;以下代码: java
function CreatePerson(name) { var obj = new Object(); obj.name = name; obj.sayName = function(){ return this.name; } return obj; } var p1 = new CreatePerson("longen"); var p2 = new CreatePerson("tugenhua"); console.log(p1.name); // longen console.log(p1.sayName()); // longen console.log(p2.name); // tugenhua console.log(p2.sayName()); // tugenhua // 返回都是object 没法识别对象的类型 不知道他们是哪一个对象的实列 console.log(typeof p1); // object console.log(typeof p2); // object console.log(p1 instanceof Object); // true
如上代码:函数CreatePerson能接受一个参数name参数,能够无数次调用这个函数,每次返回都会包含一个属性和一个方法的对象。ajax
工厂模式是为了解决多个相似对象声明的问题;也就是为了解决实列化对象产生重复的问题。后端
优势:能解决多个类似的问题。数组
缺点:不能知道对象识别的问题(对象的类型不知道)。缓存
抽象工厂模式定义是:将其成员对象的实列化推迟到子类中,子类能够重写父类接口方法以便建立的时候指定本身的对象类型。服务器
父类只对建立过程当中的通常性问题进行处理,这些处理会被子类继承,子类之间是相互独立的,具体的业务逻辑会放在子类中进行编写。网络
父类就变成了一个抽象类,可是父类能够执行子类中相同相似的方法,具体的业务逻辑须要放在子类中去实现;好比我如今开几个自行车店,那么每一个店都有几种型号的自行车出售。咱们如今来使用工厂模式来编写这些代码;app
父类的构造函数以下:
// 定义自行车的构造函数 var BicycleShop = function(){}; BicycleShop.prototype = { constructor: BicycleShop, /* * 买自行车这个方法 * @param {model} 自行车型号 */ sellBicycle: function(model){ var bicycle = this.createBicycle(mode); // 执行A业务 bicycle.A(); // 执行B业务 bicycle.B(); return bicycle; }, createBicycle: function(model){ throw new Error("父类是抽象类不能直接调用,须要子类重写该方法"); } };
上面是定义一个自行车抽象类来编写工厂模式的实例,定义了createBicycle这个方法,可是若是直接实例化父类,调用父类中的这个createBicycle方法,会抛出一个error,由于父类是一个抽象类,他不能被实列化,只能经过子类来实现这个方法,实现本身的业务逻辑,下面咱们来定义子类,咱们学会如何使用工厂模式从新编写这个方法,首先咱们须要继承父类中的成员,而后编写子类;以下代码:
// 定义自行车的构造函数 var BicycleShop = function(name){ this.name = name; this.method = function(){ return this.name; } }; BicycleShop.prototype = { constructor: BicycleShop, /* * 买自行车这个方法 * @param {model} 自行车型号 */ sellBicycle: function(model){ var bicycle = this.createBicycle(model); // 执行A业务 bicycle.A(); // 执行B业务 bicycle.B(); return bicycle; }, createBicycle: function(model){ throw new Error("父类是抽象类不能直接调用,须要子类重写该方法"); } }; // 实现原型继承 function extend(Sub,Sup) { //Sub表示子类,Sup表示超类 // 首先定义一个空函数 var F = function(){}; // 设置空函数的原型为超类的原型 F.prototype = Sup.prototype; // 实例化空函数,并把超类原型引用传递给子类 Sub.prototype = new F(); // 重置子类原型的构造器为子类自身 Sub.prototype.constructor = Sub; // 在子类中保存超类的原型,避免子类与超类耦合 Sub.sup = Sup.prototype; if(Sup.prototype.constructor === Object.prototype.constructor) { // 检测超类原型的构造器是否为原型自身 Sup.prototype.constructor = Sup; } } var BicycleChild = function(name){ this.name = name; // 继承构造函数父类中的属性和方法 BicycleShop.call(this,name); }; // 子类继承父类原型方法 extend(BicycleChild,BicycleShop); // BicycleChild 子类重写父类的方法 BicycleChild.prototype.createBicycle = function(){ var A = function(){ console.log("执行A业务"); }; var B = function(){ console.log("执行B业务"); }; return { A: A, B: B } } var childClass = new BicycleChild("源子"); console.log(childClass);
实例化子类,而后打印出该实例, 以下图所示:
console.log(childClass.name); // 源子
// 下面是实例化后 执行父类中的sellBicycle这个方法后会依次调用父类中的A方法
// 和B方法;A方法和B方法依次在子类中去编写具体的业务逻辑。
childClass.sellBicycle("mode"); // 打印出 执行A业务操做和执行B业务操做
上面只是"源子"自行车这么一个型号的,若是须要生成其余型号的自行车的话,能够编写其余子类,
工厂模式最重要的优势是:能够实现一些相同的方法,这些相同的方法咱们能够放在父类中编写代码,那么须要实现具体的业务逻辑,那么能够放在子类中重写该父类的方法,去实现本身的业务逻辑;使用专业术语来说的话有2点:第一:弱化对象间的耦合,防止代码的重复。在一个方法中进行类的实例化,能够消除重复性的代码。第二:重复性的代码能够放在父类去编写,子类继承于父类的全部成员属性和方法,子类只专一于实现本身的业务逻辑。
二:单例模式
单例模式提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码能够经过单一变量进行访问。
单例模式的优势是:
什么是单例模式?
单例模式是一个用来划分命名空间并将一批属性和方法组织在一块儿的对象,若是它能够被实例化,那么它只能被实例化一次。
可是并不是全部的对象字面量都是单例,好比说模拟数组或容纳数据的话,那么它就不是单例,可是若是是组织一批相关的属性和方法在一块儿的话,那么它有多是单例模式,因此这须要看开发者编写代码的意图;
下面咱们来看看定义一个对象字面量(结构相似于单例模式)的基本结构以下:
// 对象字面量 var Singleton = { attr1: 1, method1: function(){ return this.attr1; }, };
如上面只是简单的字面量结构,上面的全部成员变量都是经过Singleton来访问的,可是它并非单例模式;由于单例模式还有一个更重要的特色,就是能够仅被实例化一次,上面的只是不能被实例化的一个类,所以不是单例模式;对象字面量是用来建立单例模式的方法之一;
使用单例模式的结构以下demo
咱们明白的是单例模式若是有实例化的话,那么只实例化一次,要实现一个单例模式的话,咱们无非就是使用一个变量来标识该类是否被实例化,若是未被实例化的话,那么咱们能够实例化一次,不然的话,直接返回已经被实例化的对象。
以下代码是单例模式的基本结构:
// 单例模式 var Singleton = function(name){ this.name = name; this.instance = null; }; Singleton.prototype.getName = function(){ return this.name; } // 获取实例对象 function getInstance(name) { if(!this.instance) { this.instance = new Singleton(name); } return this.instance; } // 测试单例模式的实例 var a = getInstance("aa"); var b = getInstance("bb");
// 由于单例模式是只实例化一次,因此下面的实例是相等的
console.log(a === b); // true
因为单例模式只实例化一次,所以第一次调用,返回的是a实例对象,当咱们继续调用的时候,b的实例就是a的实例,所以下面都是打印的是aa;
console.log(a.getName());// aa
console.log(b.getName());// aa
上面的封装单例模式也能够改为以下结构写法:
// 单例模式 var Singleton = function(name){ this.name = name; }; Singleton.prototype.getName = function(){ return this.name; } // 获取实例对象 var getInstance = (function() { var instance = null; return function(name) { if(!instance) { instance = new Singleton(name); } return instance; } })(); // 测试单例模式的实例 var a = getInstance("aa"); var b = getInstance("bb");
// 由于单例模式是只实例化一次,因此下面的实例是相等的
console.log(a === b); // true
console.log(a.getName());// aa
console.log(b.getName());// aa
理解使用代理实现单例模式的好处
好比我如今页面上须要建立一个div的元素,那么咱们确定须要有一个建立div的函数,而如今我只须要这个函数只负责建立div元素,其余的它不想管,也就是想实现单一职责原则,就比如淘宝的kissy同样,一开始的时候他们定义kissy只作一件事,而且把这件事作好,具体的单例模式中的实例化类的事情交给代理函数去处理,这样作的好处是具体的业务逻辑分开了,代理只管代理的业务逻辑,在这里代理的做用是实例化对象,而且只实例化一次; 建立div代码只管建立div,其余的无论;以下代码:
// 单例模式 var CreateDiv = function(html) { this.html = html; this.init(); } CreateDiv.prototype.init = function(){ var div = document.createElement("div"); div.innerHTML = this.html; document.body.appendChild(div); }; // 代理实现单例模式 var ProxyMode = (function(){ var instance; return function(html) { if(!instance) { instance = new CreateDiv("我来测试下"); } return instance; } })(); var a = new ProxyMode("aaa"); var b = new ProxyMode("bbb"); console.log(a===b);// true
理解使用单例模式来实现弹窗的基本原理
下面咱们继续来使用单例模式来实现一个弹窗的demo;咱们先不讨论使用单例模式来实现,咱们想下咱们平时是怎么编写代码来实现弹窗效果的; 好比咱们有一个弹窗,默认的状况下确定是隐藏的,当我点击的时候,它须要显示出来;以下编写代码:
// 实现弹窗 var createWindow = function(){ var div = document.createElement("div"); div.innerHTML = "我是弹窗内容"; div.style.display = 'none'; document.body.appendChild('div'); return div; }; document.getElementById("Id").onclick = function(){ // 点击后先建立一个div元素 var win = createWindow(); win.style.display = "block"; }
如上的代码;你们能够看看,有明显的缺点,好比我点击一个元素须要建立一个div,我点击第二个元素又会建立一次div,咱们频繁的点击某某元素,他们会频繁的建立div的元素,虽然当咱们点击关闭的时候能够移除弹出代码,可是呢咱们频繁的建立和删除并很差,特别对于性能会有很大的影响,对DOM频繁的操做会引发重绘等,从而影响性能;所以这是很是很差的习惯;咱们如今可使用单例模式来实现弹窗效果,咱们只实例化一次就能够了;以下代码:
// 实现单例模式弹窗 var createWindow = (function(){ var div; return function(){ if(!div) { div = document.createElement("div"); div.innerHTML = "我是弹窗内容"; div.style.display = 'none'; document.body.appendChild(div); } return div; } })(); document.getElementById("Id").onclick = function(){ // 点击后先建立一个div元素 var win = createWindow(); win.style.display = "block"; }
理解编写通用的单例模式
上面的弹窗的代码虽然完成了使用单例模式建立弹窗效果,可是代码并不通用,好比上面是完成弹窗的代码,假如咱们之后须要在页面中一个iframe呢?咱们是否是须要从新写一套建立iframe的代码呢?好比以下建立iframe:
var createIframe = (function(){ var iframe; return function(){ if(!iframe) { iframe = document.createElement("iframe"); iframe.style.display = 'none'; document.body.appendChild(iframe); } return iframe; }; })();
咱们看到如上代码,建立div的代码和建立iframe代码很相似,咱们如今能够考虑把通用的代码分离出来,使代码变成彻底抽象,咱们如今能够编写一套代码封装在getInstance函数内,以下代码:
var getInstance = function(fn) { var result; return function(){ return result || (result = fn.call(this,arguments)); } };
如上代码:咱们使用一个参数fn传递进去,若是有result这个实例的话,直接返回,不然的话,当前的getInstance函数调用fn这个函数,是this指针指向与这个fn这个函数;以后返回被保存在result里面;如今咱们能够传递一个函数进去,无论他是建立div也好,仍是建立iframe也好,总之若是是这种的话,均可以使用getInstance来获取他们的实例对象;
以下测试建立iframe和建立div的代码以下:
// 建立div var createWindow = function(){ var div = document.createElement("div"); div.innerHTML = "我是弹窗内容"; div.style.display = 'none'; document.body.appendChild(div); return div; }; // 建立iframe var createIframe = function(){ var iframe = document.createElement("iframe"); document.body.appendChild(iframe); return iframe; }; // 获取实例的封装代码 var getInstance = function(fn) { var result; return function(){ return result || (result = fn.call(this,arguments)); } }; // 测试建立div var createSingleDiv = getInstance(createWindow); document.getElementById("Id").onclick = function(){ var win = createSingleDiv(); win.style.display = "block"; }; // 测试建立iframe var createSingleIframe = getInstance(createIframe); document.getElementById("Id").onclick = function(){ var win = createSingleIframe(); win.src = "http://cnblogs.com"; };
三:模块模式
咱们何时使用模块模式?
若是咱们必须建立一个对象并以某些数据进行初始化,同时还要公开一些可以访问这些私有数据的方法,那么咱们这个时候就可使用模块模式了。
咱们经过单例模式理解了是以对象字面量的方式来建立单例模式的;好比以下的对象字面量的方式代码以下:
var singleMode = { name: value, method: function(){ } };
模块模式的思路是为单例模式添加私有变量和私有方法可以减小全局变量的使用;
以下就是一个模块模式的代码结构:
var singleMode = (function(){ // 建立私有变量 var privateNum = 112; // 建立私有函数 function privateFunc(){ // 实现本身的业务逻辑代码 } // 返回一个对象包含公有方法和属性 return { publicMethod1: publicMethod1, publicMethod2: publicMethod1 }; })();
模块模式使用了一个返回对象的匿名函数。在这个匿名函数内部,先定义了私有变量和函数,供内部函数使用,而后将一个对象字面量做为函数的值返回,返回的对象字面量中只包含能够公开的属性和方法。这样的话,能够提供外部使用该方法;因为该返回对象中的公有方法是在匿名函数内部定义的,所以它能够访问内部的私有变量和函数。
加强的模块模式:
function CustomType() { this.name = "tugenhua"; }; CustomType.prototype.getName = function(){ return this.name; } var application = (function(){ // 定义私有 var privateA = "aa"; // 定义私有函数 function A(){}; // 实例化一个对象后,返回该实例,而后为该实例增长一些公有属性和方法 var object = new CustomType(); // 添加公有属性 object.A = "aa"; // 添加公有方法 object.B = function(){ return privateA; } // 返回该对象 return object; })();
下面咱们来打印下application该对象;以下:
console.log(application);
继续打印该公有属性和方法以下:
console.log(application.A);// aa
console.log(application.B()); // aa
console.log(application.name); // tugenhua
console.log(application.getName());// tugenhua
四:代理模式
代理是一个对象,它能够用来控制对本体对象的访问,它与本体对象实现了一样的接口,代理对象会把全部的调用方法传递给本体对象的;代理模式最基本的形式是对访问进行控制,而本体对象则负责执行所分派的那个对象的函数或者类,简单的来说本地对象注重的去执行页面上的代码,代理则控制本地对象什么时候被实例化,什么时候被使用;咱们在上面的单体模式中使用过一些代理模式,就是使用代理模式实现单体模式的实例化,其余的事情就交给本体对象去处理;
代理的优势:
咱们先来理解代理对象代替本体对象被实例化的列子;好比如今京东ceo想送给奶茶妹一个礼物,可是呢假如该ceo很差意思送,或者因为工做忙没有时间送,那么这个时候他就想委托他的经纪人去作这件事,因而咱们可使用代理模式来编写以下代码:
// 先申明一个奶茶妹对象 var TeaAndMilkGirl = function(name) { this.name = name; }; // 这是京东ceo先生 var Ceo = function(girl) { this.girl = girl; // 送结婚礼物 给奶茶妹 this.sendMarriageRing = function(ring) { console.log("Hi " + this.girl.name + ", ceo送你一个礼物:" + ring); } }; // 京东ceo的经纪人是代理,来代替送 var ProxyObj = function(girl){ this.girl = girl; // 经纪人代理送礼物给奶茶妹 this.sendGift = function(gift) { // 代理模式负责本体对象实例化 (new Ceo(this.girl)).sendMarriageRing(gift); } }; // 初始化 var proxy = new ProxyObj(new TeaAndMilkGirl("奶茶妹")); proxy.sendGift("结婚戒"); // Hi 奶茶妹, ceo送你一个礼物:结婚戒
代码如上的基本结构,TeaAndMilkGirl 是一个被送的对象(这里是奶茶妹);Ceo 是送礼物的对象,他保存了奶茶妹这个属性,及有一个本身的特权方法sendMarriageRing 就是送礼物给奶茶妹这么一个方法;而后呢他是想经过他的经纪人去把这件事完成,因而须要建立一个经纪人的代理模式,名字叫ProxyObj ;他的主要作的事情是,把ceo交给他的礼物送给ceo的情人,所以该对象一样须要保存ceo情人的对象做为本身的属性,同时也须要一个特权方法sendGift ,该方法是送礼物,所以在该方法内能够实例化本体对象,这里的本体对象是ceo送花这件事情,所以须要实例化该本体对象后及调用本体对象的方法(sendMarriageRing).
最后咱们初始化是须要代理对象ProxyObj;调用ProxyObj 对象的送花这个方法(sendGift)便可;
对于咱们提到的优势,第二点的话,咱们下面能够来理解下虚拟代理,虚拟代理用于控制对那种建立开销很大的本体访问,它会把本体的实例化推迟到有方法被调用的时候;好比说如今有一个对象的实例化很慢的话,不能在网页加载的时候当即完成,咱们能够为其建立一个虚拟代理,让他把该对象的实例推迟到须要的时候。
理解使用虚拟代理实现图片的预加载
在网页开发中,图片的预加载是一种比较经常使用的技术,若是直接给img标签节点设置src属性的话,若是图片比较大的话,或者网速相对比较慢的话,那么在图片未加载完以前,图片会有一段时间是空白的场景,这样对于用户体验来说并很差,那么这个时候咱们能够在图片未加载完以前咱们可使用一个loading加载图片来做为一个占位符,来提示用户该图片正在加载,等图片加载完后咱们能够对该图片直接进行赋值便可;下面咱们先不用代理模式来实现图片的预加载的状况下代码以下:
第一种方案:不使用代理的预加载图片函数以下:
// 不使用代理的预加载图片函数以下 var myImage = (function(){ var imgNode = document.createElement("img"); document.body.appendChild(imgNode); var img = new Image(); img.onload = function(){ imgNode.src = this.src; }; return { setSrc: function(src) { imgNode.src = "http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif"; img.src = src; } } })(); // 调用方式 myImage.setSrc("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png");
如上代码是不使用代理模式来实现的代码;
第二种方案:使用代理模式来编写预加载图片的代码以下:
var myImage = (function(){ var imgNode = document.createElement("img"); document.body.appendChild(imgNode); return { setSrc: function(src) { imgNode.src = src; } } })(); // 代理模式 var ProxyImage = (function(){ var img = new Image(); img.onload = function(){ myImage.setSrc(this.src); }; return { setSrc: function(src) { myImage.setSrc("http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif"); img.src = src; } } })(); // 调用方式 ProxyImage.setSrc("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png");
第一种方案是使用通常的编码方式实现图片的预加载技术,首先建立imgNode元素,而后调用myImage.setSrc该方法的时候,先给图片一个预加载图片,当图片加载完的时候,再给img元素赋值,第二种方案是使用代理模式来实现的,myImage 函数只负责建立img元素,代理函数ProxyImage 负责给图片设置loading图片,当图片真正加载完后的话,调用myImage中的myImage.setSrc方法设置图片的路径;他们之间的优缺点以下:
从上面代理模式咱们能够看到,
代理模式和本体对象中有相同的方法setSrc,这样设置的话有以下2个优势:
固然若是代理对象和本体对象都返回一个匿名函数的话,那么也能够认为他们也具备一直的接口;好比以下代码:
var myImage = (function(){ var imgNode = document.createElement("img"); document.body.appendChild(imgNode); return function(src){ imgNode.src = src; } })(); // 代理模式 var ProxyImage = (function(){ var img = new Image(); img.onload = function(){ myImage(this.src); }; return function(src) { myImage("http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif"); img.src = src; } })(); // 调用方式 ProxyImage("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png");
虚拟代理合并http请求的理解:
好比在作后端系统中,有表格数据,每一条数据前面有复选框按钮,当点击复选框按钮时候,须要获取该id后须要传递给给服务器发送ajax请求,服务器端须要记录这条数据,去请求,若是咱们每当点击一下向服务器发送一个http请求的话,对于服务器来讲压力比较大,网络请求比较频繁,可是若是如今该系统的实时数据不是很高的话,咱们能够经过一个代理函数收集一段时间内(好比说2-3秒)的全部id,一次性发ajax请求给服务器,相对来讲网络请求下降了, 服务器压力减小了;
// 首先html结构以下: <p> <label>选择框</label> <input type="checkbox" class="j-input" data-id="1"/> </p> <p> <label>选择框</label> <input type="checkbox" class="j-input" data-id = "2"/> </p> <p> <label>选择框</label> <input type="checkbox" class="j-input" data-id="3"/> </p> <p> <label>选择框</label> <input type="checkbox" class="j-input" data-id = "4"/> </p>
通常的状况下 JS以下编写
<script> var checkboxs = document.getElementsByClassName("j-input"); for(var i = 0,ilen = checkboxs.length; i < ilen; i++) { (function(i){ checkboxs[i].onclick = function(){ if(this.checked) { var id = this.getAttribute("data-id"); // 以下是ajax请求 } } })(i); } </script>
下面咱们经过虚拟代理的方式,延迟2秒,在2秒后获取全部被选中的复选框的按钮id,一次性给服务器发请求。
经过点击页面的复选框,选中的时候增长一个属性isflag,没有选中的时候删除该属性isflag,而后延迟个2秒,在2秒后从新判断页面上全部复选框中有isflag的属性上的id,存入数组,而后代理函数调用本体函数的方法,把延迟2秒后的全部id一次性发给本体方法,本体方法能够获取全部的id,能够向服务器端发送ajax请求,这样的话,服务器的请求压力相对来讲减小了。
代码以下:
// 本体函数 var mainFunc = function(ids) { console.log(ids); // 便可打印被选中的全部的id // 再把全部的id一次性发ajax请求给服务器端 }; // 代理函数 经过代理函数获取全部的id 传给本体函数去执行 var proxyFunc = (function(){ var cache = [], // 保存一段时间内的id timer = null; // 定时器 return function(checkboxs) { // 判断若是定时器有的话,不进行覆盖操做 if(timer) { return; } timer = setTimeout(function(){ // 在2秒内获取全部被选中的id,经过属性isflag判断是否被选中 for(var i = 0,ilen = checkboxs.length; i < ilen; i++) { if(checkboxs[i].hasAttribute("isflag")) { var id = checkboxs[i].getAttribute("data-id"); cache[cache.length] = id; } } mainFunc(cache.join(',')); // 2秒后须要给本体函数传递全部的id // 清空定时器 clearTimeout(timer); timer = null; cache = []; },2000); } })(); var checkboxs = document.getElementsByClassName("j-input"); for(var i = 0,ilen = checkboxs.length; i < ilen; i+=1) { (function(i){ checkboxs[i].onclick = function(){ if(this.checked) { // 给当前增长一个属性 this.setAttribute("isflag",1); }else { this.removeAttribute('isflag'); } // 调用代理函数 proxyFunc(checkboxs); } })(i); }
缓存代理:
缓存代理的含义就是对第一次运行时候进行缓存,当再一次运行相同的时候,直接从缓存里面取,这样作的好处是避免重复一次运算功能,若是运算很是复杂的话,对性能很耗费,那么使用缓存对象能够提升性能;咱们能够先来理解一个简单的缓存列子,就是网上常见的加法和乘法的运算。代码以下:
// 计算乘法 var mult = function(){ var a = 1; for(var i = 0,ilen = arguments.length; i < ilen; i+=1) { a = a*arguments[i]; } return a; }; // 计算加法 var plus = function(){ var a = 0; for(var i = 0,ilen = arguments.length; i < ilen; i+=1) { a += arguments[i]; } return a; } // 代理函数 var proxyFunc = function(fn) { var cache = {}; // 缓存对象 return function(){ var args = Array.prototype.join.call(arguments,','); if(args in cache) { return cache[args]; // 使用缓存代理 } return cache[args] = fn.apply(this,arguments); } }; var proxyMult = proxyFunc(mult); console.log(proxyMult(1,2,3,4)); // 24 console.log(proxyMult(1,2,3,4)); // 缓存取 24 var proxyPlus = proxyFunc(plus); console.log(proxyPlus(1,2,3,4)); // 10 console.log(proxyPlus(1,2,3,4)); // 缓存取 10
总结:有什么不懂的问我!!!!