我是怎样理解闭包的
假设有这个需求,写个函数,动态生成HTML,每次生成的 HTML 有一部分的是固定不变的。
function buildHtml() { var template = ['<table><tr><td>', '', '</td><td>', '', '<td></td></tr></table>']; template[1] = args[0]; template[3] = args[1]; return template.join(''); }
分析下,每次执行函数时,都会重复定义个template,执行完函数后,这个变量就被销毁;这样重复定义销毁,肯定对性能不好,考虑把template这个变量内容提取到外面,
$(function () { //... var template = ['<table><tr><td>', '', '</td><td>', '', '<td></td></tr></table>']; function buildHtml(args) { template[1] = args[0]; template[3] = args[1]; return template.join(''); } //...这里可以调用上面的代码 })
这样移动代码时,貌似就不要考虑两个变量名重复,貌似也解决了一部分问题。可是还有一种更好的方案,比如
var buildHtml = (function () { var template = ['<table><tr><td>', '', '</td><td>', '', '<td></td></tr></table>']; return function (args) { template[1] = args[0]; template[3] = args[1]; return template.join(''); } })();
function xx() { var template = ['<table><tr><td>', '', '</td><td>', '', '<td></td></tr></table>']; return function (args) { template[1] = args[0]; template[3] = args[1]; return template.join(''); } }; var buildHtml = xx();
然后就可以这样调用了buildHtml(/*参数*/);
var win = (function () { var fn1 = function () {}, //私有方法 pro = 1; //私有属性 return { outFns1 : function () { //调用fn1或pro }, outFns2 : function () { //调用fn1或pro } } })();
上面的例子,貌似都用到return,不用return呢?实际上面第二个例子,稍微改造下,也是闭包
$(function () { //... var template = ['<table><tr><td>', '', '</td><td>', '', '<td></td></tr></table>']; buildHtml = function (args) { template[1] = args[0]; template[3] = args[1]; return template.join(''); } //...这里可以调用上面的代码 })
buildHtml因为没有var声明,所以是全局变量,这样在$的回调函数外面,也可以通过buildHtml访问template。
function wrapFns() { var arr = []; for (var i = 10; i--; ) { arr[i] = function () { return i; } } return arr; } var fns = wrapFns(); console.log(fns[10]()); // 值是多少?
(function (window, undefined) { window.ymPrompt = {}; //可以全局访问了 })(window);
2.闭包来实现记忆功能
function aa(num) { if (num == 0) { return 1; } return num * aa(num - 1); }
var aa = (function () { var cache = []; return function (num) { if (!cache[num]) { if (num == 0) { cache[num] = 1; } cache[num] = num * aa(num - 1); } return cache[num]; } })();
function A() { function B() { console.log(this === window); //true 单独的函数 } this.a = 1; } A.method = function () { console.log(this.a); //1 对象方法,this===A } var fn = A.method; fn(); //undefined 单独函数
function Construtor() { var aa; this.aa = '1'; this.fun1 = function () {}; this.fun2 = function () {}; this.fun3... }
在fun1 fun2 fun3中没有使用aa,没有必要用闭包,Construtor.prototype.fun1 = function(){}
据说每个大牛、小牛都应该有自己的库——Ajax
蹉跎到今天终于要写Ajax部分了,平时工作中除了选择器我用jQuery的最多的就是ajax,所以这部分在自己的框架中必不可少。
XMLHttpRequest
我以为对每个使用过Ajax的人来说XMLHttpRequest对象肯定是如雷贯耳,可是在和公司小伙伴儿的讨论中我意识到,这个对象对有些已经使用Ajax很久的人来说仍然很陌生,jQuery等类库把XMLHttpRequest对象封装的太好了,以至于我们都不知道自己在使用它。关于JavaScript原生的Ajax之前写过一篇Ajax初步理解的博客,为了方便下面书写,在这里再介绍一下几个重点概念。
Ajax的核心是JavaScript对象XmlHttpRequest,这个对象为向服务器发送请求和解析服务器响应提供了流畅的接口。XmlHttpRequest可以使用JavaScript向服务器提出请求并处理响应,而不阻塞用户。该对象有两个重要方法open与send
调用send()方法,请求被发往服务器,服务器根据请求生成响应(Response),传回给XHR对象,在收到响应后相应数据会填充到XHR对象的属性,有四个相关属性会被填充:
1. responseText:作为响应主体被返回的文本
2. responseXML:如果响应内容的类型是”text/xml”或”application/xml”,这个属性将保存包含着相应数据的XML文档
3. status:响应的HTTP状态(200,404,500等)
4. statusText:HTTP状态说明
XHR对象有一个readyState属性,该属性表示请求/响应过程中的当前活动阶段,每当readyState值改变的时候都会触发一次onreadystatechange事件。
浏览器兼容的创建XHR对象方法
大家都懂得,IE总会制造些麻烦,看看浏览器兼容的创建XHR对象方法,具体过程可以看看Ajax初步理解中的说明
function __createXHR(){ var xhr = null; try { // Firefox, Opera 8.0+, Safari,IE7+ xhr = new XMLHttpRequest(); } catch (e) { // Internet Explorer try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { xhr = null; } } } return xhr; }
封装
其实看看第一段关于XHR对象的说明就明白为什么jQuery等类库会对XHR做如此彻底的封装了,这个对象实在是太复杂了,参数的设置都要有时机问题,所以我也走上了封装之路。
ajax: function(configs) { var settings = { "url": "", //请求地址 "method": "post", //请求使用方法 "user": "", //用户名 "password": "", //密码 "data": null, //参数(text/json) "responseType": "text", //返回值获取方式 text/xml "headers": {}, //自定义的HttpHeader "enableCache":true, //是否使用缓存 "onSucceed": null, //成功句柄 "onClientError": null, //客户端错误句柄 "onServerError": null //服务器端错误句柄 }; for (s in settings) { settings[s] = configs[s] ? configs[s] : settings[s]; //应用自定义配置 } var xhr = _createXHR(); //创建XHR对象 xhr.onreadystatechange = function() { if (xhr.readyState == 4) { //请求完成,响应就绪 var result = settings["responseType"] == "text" ? xhr.responseText : xhr.responseXML; //返回值类型 if (((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) && typeof settings['onSucceed'] == 'function') { //成功 settings['onSucceed'](result, xhr.status); } else if (xhr.status >= 400 && xhr.status < 500) { //客户端出错,404啊神马的 settings['onClientError'](result, xhr.status); } else if (xhr.status >= 500) { //服务器端出错 settings['onServerError'](result, xhr.status); } } } xhr.open(settings['method'], settings['url'], settings['user'], settings['password']); //发送请求 if (typeof settings['headers'] == 'object') { //设置自定义headers var headers = settings['headers']; for (h in headers) { xhr.setRequestHeader(h, headers[h]); } } if(!settings['enableCache']){ //禁用缓存 xhr.setRequestHeader("If-Modified-Since","0"); } if (settings["method"].toLowerCase() == "post") { //post请求 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"); var data=""; if(typeof settings["data"]=='object') { for(d in settings["data"]){ data+=(d+'='+settings["data"][d]); } }else{ data=settings["data"]; } xhr.send(data); //传递参数 } else { xhr.send(); //get请求 } }
最后
这样一个简单的Ajax封装就完成了,使用的时候和jQuery类似
ssLib.ajax({ "url": "testajax.php", "data":{"name":"Byron"}, "onSucceed": function(result) { alert(result); } });
看起类不错,不过没实际使用过呢还,希望大家多给意见。