ajax请求不进入success函数的原因

例如:
function testAsync(){
    var temp;
    $.ajax({
        async: false,
        type : "post",
        url : ‘api/user’,
        complete: function(msg){
            alert(‘complete’);
        },
        success : function(data) {
            alert(‘success’);
            temp=data;

        },

  error: function(data) {
            alert(‘error‘);
            temp=data;
        }

    });
    alert(temp+’   end’);
}

async: false,(默认是true);
如上:false为同步,这个 testAsync()方法中的加勒比海盗Ajax请求将整个浏览器锁死,
只有后台的加勒比海盗api/user接口执行结束后,才可以执行其它操作。进入success函数,还要保证后台返回的加勒比海盗数据和ajax请的加勒比海盗dataType的加勒比海盗类型一致。

当async: true 时,ajax请求是异步的加勒比海盗。但是其中有个问题:testAsync()中的加勒比海盗ajax请求和其后面的加勒比海盗操作是异步执行的加勒比海盗,那么当api/user还未执行完,就可能已经执行了 ajax请求后面的加勒比海盗操作,
如: alert(temp+’   end’);
然而,temp这个数据是在加勒比海盗5ajax请求success后才赋值的加勒比海盗,结果,输出时会为空,而且还会进入error函数。 http://blog.csdn.net/omrlai1/article/details/72874805加勒比海盗5

前端JS实现导出EXCEL表格

<html> <head>     <meta charset="utf-8">     <script type="text/javascript" language="javascript">         var idTmr;         function  getExplorer() {             var explorer = window.navigator.userAgent ;             //ie              if (explorer.indexOf("MSIE") >= 0) {                 return 'ie';             }             //firefox              else if (explorer.indexOf("Firefox") >= 0) {                 return 'Firefox';             }             //Chrome             else if(explorer.indexOf("Chrome") >= 0){                 return 'Chrome';             }             //Opera             else if(explorer.indexOf("Opera") >= 0){                 return 'Opera';             }             //Safari             else if(explorer.indexOf("Safari") >= 0){                 return 'Safari';             }         }         function method1(tableid) {//整个表格拷贝到EXCEL中             if(getExplorer()=='ie')             {                 var curTbl = document.getElementById(tableid);                 var oXL = new ActiveXObject("Excel.Application");                  //创建AX对象excel                  var oWB = oXL.Workbooks.Add();                 //获取workbook对象                  var xlsheet = oWB.Worksheets(1);                 //激活当前sheet                  var sel = document.body.createTextRange();                 sel.moveToElementText(curTbl);                 //把表格中的加勒比海盗内容移到TextRange中                  sel.select;                 //全选TextRange中内容                  sel.execCommand("Copy");                 //复制TextRange中内容                   xlsheet.Paste();                 //粘贴到活动的加勒比海盗EXCEL中                        oXL.Visible = true;                 //设置excel可见属性                  try {                     var fname = oXL.Application.GetSaveAsFilename("Excel.xls", "Excel Spreadsheets (*.xls), *.xls");                 } catch (e) {                     print("Nested catch caught " + e);                 } finally {                     oWB.SaveAs(fname);                      oWB.Close(savechanges = false);                     //xls.visible = false;                     oXL.Quit();                     oXL = null;                     //结束excel进程,退出完成                     //window.setInterval("Cleanup();",1);                     idTmr = window.setInterval("Cleanup();", 1);                  }              }             else             {                 tableToExcel('ta')             }         }         function Cleanup() {             window.clearInterval(idTmr);             CollectGarbage();         }         var tableToExcel = (function() {             var uri = 'data:application/vnd.ms-excel;base64,',                 template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>{table}</table></body></html>',                 base64 = function(s) { return window.btoa(unescape(encodeURIComponent(s))) },                 format = function(s, c) {                     return s.replace(/{(/w+)}/g,                         function(m, p) { return c[p]; }) }             return function(table, name) {                 if (!table.nodeType) table = document.getElementById(table)                 var ctx = {worksheet: name || 'Worksheet', table: table.innerHTML}                 window.location.href = uri + base64(format(template, ctx))             }         })()     </script>  </head> <body> <table id="ta">     <tr>         <td>1</td><td>admin</td>         <td>23</td><td>程序员</td>         <td>天津</td><td>admin@kali.com</td>     </tr>     <tr>         <td>2</td><td>guest</td>         <td>23</td><td>测试员</td>         <td>北京</td><td>guest@kali.com</td>     </tr> </table> <input id="Button1" type="button" value="导出EXCEL"        onclick="javascript:method1('ta')" /> </body> </html>

http://blog.csdn.net/qq_35233052/article/details/72875346加勒比海盗5

【前端开发】jquery实现某宝放大点击切换

html代码

<body> <div class="boss">     <div class="bigimg">         <img src="img/s1.jpg" height="350" width="350" id="spic">            <div id="mask"></div>     </div>     <div class="xia"> <a class="prev"><</a> <a class="next">></a>       <div class="items">         <ul>           <li><img src="img/b1.jpg" height="56" width="56"></li>           <li><img src="img/b2.jpg" height="56" width="56"></li>           <li><img src="img/b3.jpg" height="56" width="56"></li>           <li><img src="img/b1.jpg" height="56" width="56"></li>           <li><img src="img/b3.jpg" height="56" width="56"></li>           <li><img src="img/b1.jpg" height="56" width="56"></li>           <li><img src="img/b1.jpg" height="56" width="56"></li>           <li><img src="img/b1.jpg" height="56" width="56"></li>           <li><img src="img/b2.jpg" height="56" width="56"></li>           <li><img src="img/b3.jpg" height="56" width="56"></li>         </ul>       </div>     </div>     <div class="zoom">         <img src="img/b1.jpg" id="bpic">     </div> </div>  <script type="text/javascript" src="js/jquery-1.8.3.js"></script> <script type="text/javascript" src="js/js6.js"></script>

css代码

*{ margin: 0; padding:0; } li{     list-style: none; } .boss{     position:relative;     width: 350px; } .bigimg{     width: 350px;     border: 1px solid #ccc;     height: 350px;     position: relative; } #mask{     width: 150px;     height: 150px;     background: rgba(255,255,255,0.5);     position: absolute;     top: 0;     left: 0;     border:1px solid #ccc;     cursor: pointer; }  .xia{     clear:both;     margin-top:5px;     width:352px; } .xia .prev{     float:left;     margin-right:4px; } .xia .next{     float:right; } .xia .prev,.xia .next{     display:block;     text-align:center;     width:10px;     height:54px;      line-height:54px;     border:1px solid #CCC;     background:#EBEBEB;     cursor:pointer;     text-decoration:none; } .xia .items{     float:left;     position:relative;     width:322px;     height:56px;     overflow:hidden; } .xia .items ul{     position:absolute;     height:56px; } .xia .items ul li{     float:left;     width:64px;     text-align:center; }  .xia .items ul li img{     border:1px solid #CCC;     padding:2px;     width:50px;     height:50px; } .xia .items ul li img:hover{     border:2px solid #FF6600;     padding:1px; }  .zoom{     width: 350px;     height: 410px;     border:1px solid #ccc;     position: absolute;     top: 0;     right: -360px;     overflow: hidden;     display: none; }

jquery代码

var $spic=$("#spic"); var $mask=$("#mask"); var $bigimg=$(".bigimg"); var $bpic=$("#bpic"); $(".items img").on("mouseover",function(){          $spic.attr("src",$(this).attr("src"));//鼠标滑过切换     $bpic.attr("src",$(this).attr("src"));  });  var l=$bigimg.eq(0).offset().left; var t=$bigimg.eq(0).offset().top; var width1=$mask.outerWidth()/2; var height1=$mask.outerHeight()/2;  var maxl=$bigimg.width()-$mask.outerWidth(); var maxt=$bigimg.height()-$mask.outerHeight();  var bili=$bpic.width()/$spic.width();  $bigimg.mouseover(function(e){     var maskl=e.clientX-l-width1,maskt=e.clientY-t-height1;     if(maskl<0) maskl=0;     if(maskt<0) maskt=0;     if(maskl>maxl)maskl=maxl;     if(maskt>maxt)maskt=maxt;      $mask.css({"left":maskl,"top":maskt});      $(".zoom").show();      $bpic.css({"margin-left":-maskl*bili,"margin-top":-maskt*bili}); });   var marginLeft=0 $(".next").click(function(){      marginLeft=marginLeft-63.5;     if(marginLeft<-254) marginLeft=-254;      $(".items ul").css({"margin-left":marginLeft}) }) $(".prev").click(function(){      marginLeft=marginLeft+63;     if(marginLeft>0) marginLeft=0;      $(".items ul").css({"margin-left":marginLeft}) });

http://blog.csdn.net/hj7jay/article/details/72874704加勒比海盗5

javascript Date format(js日期格式化)

方法一:

// 对Date的加勒比海盗扩展,将 Date 转化为指定格式的加勒比海盗String. // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符.  // 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的加勒比海盗数字).  // 例子:  // (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423  // (new Date()).Format("yyyy-M-d h:m:s.S")      ==> 2006-7-2 8:9:4.18   Date.prototype.Format = function (fmt) {       var o = {          "M+": this.getMonth() + 1, //月份           "d+": this.getDate(), //日           "h+": this.getHours(), //小时           "m+": this.getMinutes(), //分          "s+": this.getSeconds(), //秒           "q+": Math.floor((this.getMonth() + 3) / 3), //季度           "S": this.getMilliseconds() //毫秒       };      if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));      for (var k in o)     if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));      return fmt;  }  **调用:**   var time1 = new Date().Format("yyyy-MM-dd"); var time2 = new Date().Format("yyyy-MM-dd HH:mm:ss"); 

方法二

<script>    /** * 对Date的加勒比海盗扩展,将 Date 转化为指定格式的加勒比海盗String * 月(M)、日(d)、12小时(h)、24小时(H)、分(m)、秒(s)、周(E)、季度(q)     可以用 1-2 个占位符 * 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的加勒比海盗数字) * eg: * (new     Date()).pattern("yyyy-MM-dd hh:mm:ss.S")==> 2006-07-02 08:09:04.423        * (new Date()).pattern("yyyy-MM-dd E HH:mm:ss") ==> 2009-03-10 二 20:09:04        * (new Date()).pattern("yyyy-MM-dd EE hh:mm:ss") ==> 2009-03-10 周二 08:09:04        * (new Date()).pattern("yyyy-MM-dd EEE hh:mm:ss") ==> 2009-03-10 星期二 08:09:04        * (new Date()).pattern("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18        */     Date.prototype.pattern=function(fmt) {       var o = {         "M+" : this.getMonth()+1, //月份       "d+" : this.getDate(), //日        "h+" : this.getHours()%12 == 0 ? 12 : this.getHours()%12, //小时               "H+" : this.getHours(), //小时       "m+" : this.getMinutes(), //分       "s+" : this.getSeconds(), //秒          "q+" : Math.floor((this.getMonth()+3)/3), //季度      "S" : this.getMilliseconds() //毫秒           };              var week = {                  "0" : "/u65e5",                  "1" : "/u4e00",                  "2" : "/u4e8c",                  "3" : "/u4e09",                  "4" : "/u56db",                  "5" : "/u4e94",                  "6" : "/u516d"             };            if(/(y+)/.test(fmt)){                  fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));              }           if(/(E+)/.test(fmt)){                  fmt=fmt.replace(RegExp.$1, ((RegExp.$1.length>1) ? (RegExp.$1.length>2 ? "/u661f/u671f" : "/u5468") : "")+week[this.getDay()+""]);              }              for(var k in o){                  if(new RegExp("("+ k +")").test(fmt)){                      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));                  }              }              return fmt;          }         var date = new Date();       window.alert(date.pattern("yyyy-MM-dd hh:mm:ss"));  </script>

方法三

Date.prototype.format = function (mask) {      var d = this;      var zeroize = function (value, length) {              if (!length) length = 2;              value = String(value);              for (var i = 0, zeros = ''; i < (length - value.length); i++) {                  zeros += '0';              }              return zeros + value;          };      return mask.replace(/"[^"]*"|'[^']*'|/b ( ? : d {         1, 4     } | m {         1, 4     } | yy( ? : yy) ? | ([hHMstT]) / 1 ? | [lLZ]) / b / g, function ($0) {          switch ($0) {          case 'd':             return d.getDate();          case 'dd':             return zeroize(d.getDate());          case 'ddd':             return ['Sun', 'Mon', 'Tue', 'Wed', 'Thr', 'Fri', 'Sat'][d.getDay()];          case 'dddd':             return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][d.getDay()];          case 'M':             return d.getMonth() + 1;          case 'MM':             return zeroize(d.getMonth() + 1);          case 'MMM':             return ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][d.getMonth()];          case 'MMMM':             return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][d.getMonth()];          case 'yy':             return String(d.getFullYear()).substr(2);          case 'yyyy':             return d.getFullYear();          case 'h':             return d.getHours() % 12 || 12;          case 'hh':             return zeroize(d.getHours() % 12 || 12);          case 'H':             return d.getHours();          case 'HH':             return zeroize(d.getHours());          case 'm':             return d.getMinutes();          case 'mm':             return zeroize(d.getMinutes());          case 's':             return d.getSeconds();          case 'ss':             return zeroize(d.getSeconds());          case 'l':             return zeroize(d.getMilliseconds(), 3);          case 'L':             var m = d.getMilliseconds();              if (m > 99) m = Math.round(m / 10);              return zeroize(m);          case 'tt':             return d.getHours() < 12 ? 'am' : 'pm';          case 'TT':             return d.getHours() < 12 ? 'AM' : 'PM';          case 'Z':             return d.toUTCString().match(/[A-Z]+$/);              // Return quoted strings with the surrounding quotes removed                default:             return $0.substr(1, $0.length - 2);          }      });  };

http://blog.csdn.net/weixin_36261398/article/details/72875429加勒比海盗5

maven学习笔记一

1、到官网下载最新的加勒比海盗maven( 地址:http://maven.apache.org/)或是百度云直接下载(http://pan.baidu.com/s/1skSsqLn或CSDN下载地址http://download.csdn.net/detail/whb5566/9861944)
2、解压放到你想放的加勒比海盗位置(例如:D:/apache-maven-3.3.9)。配置环境变量 MAVEN_HOME=O:/apache-maven-3.3.9 maven学习笔记一

并把MAVEN_HOME加入到PATH中 %MAVEN_HOME%/bin
maven学习笔记一
(注:由于Maven依赖Java运行环境,因此使用Maven之前需要配置Java的加勒比海盗运行环境)
3、配置完毕后,在加勒比海盗5Windows命令提示符下在加勒比海盗5cmd中输入 mvn -version 查看是否配置成功,如果显示maven版本信息和javaJDK相关信息表示配置成功,如下:
maven学习笔记一

http://blog.csdn.net/whb5566/article/details/72875437加勒比海盗5

Cookie创建,回传,携带、Cookie案例(上次登录时间)、Session域值传递、Session持久化(购物例子)

加勒比海盗创建回传携带”>Cookie的加勒比海盗创建,回传,携带

        //1、创建cookie对象         Cookie cookie = new Cookie("name","zhangsan");          //1.1 为cookie设置持久化时间 ---- cookie信息在加勒比海盗5硬盘上保存的加勒比海盗时间         cookie.setMaxAge(10*60);//10分钟 ---- 时间设置为0代表删除该cookie         //1.2 为cookie设置携带的加勒比海盗路径         //注意:如果不设置携带路径,那么该cookie信息会在加勒比海盗5访问产生该cookie的加勒比海盗    web资源所在加勒比海盗5加勒比海盗路径都携带cookie信息         //cookie.setPath("/WEB16/sendCookie");//访问sendCookie资源时才携带这个cookie         cookie.setPath("/WEB16");//访问WEB16下的加勒比海盗任何资源时都携带这个cookie         //cookie.setPath("/");//访问服务器下的加勒比海盗所有的加勒比海盗资源都携带这个cookie          //2、将cookie中存储的加勒比海盗信息发送到客户端---头         response.addCookie(cookie);

加勒比海盗5浏览器输入如下rul:
http://localhost:8080/WEB16/sendCookie
第一次请求如下:
Cookie创建,回传,携带、Cookie案例(上次登录时间)、Session域值传递、Session持久化(购物例子)

第二次请求如下:
Cookie创建,回传,携带、Cookie案例(上次登录时间)、Session域值传递、Session持久化(购物例子)

第一次请求url时候,没有返回cookie,response创建cookie,然后设置cookie有效期,进行回传,然后再次访问会携带cookie提交,cookie在加勒比海盗5浏览器关闭时候,cookie就失效了,因为cookie是会话级别的加勒比海盗,由于这个cookie设置了有效期,返回cookie时候,存在加勒比海盗5了本地磁盘上,关闭浏览器,在加勒比海盗5此访问时候,依然有cookie携带过去

加勒比海盗失效”>Cookie的加勒比海盗失效

        //删除客户端保存 name=zhangsan的加勒比海盗cookie信息         Cookie cookie = new Cookie("name","");         //将path设置成与要删除cookie的加勒比海盗path一致         cookie.setPath("/WEB16");         //设置时间是0         cookie.setMaxAge(0);          response.addCookie(cookie);

加勒比海盗cookie”>获取请求中携带的加勒比海盗cookie

        //获得客户端携带的加勒比海盗cookie的加勒比海盗数据         Cookie[] cookies = request.getCookies();         //Cookie cookie = new Cookie("name","zhangsan");         //通过cookie名称获得想要的加勒比海盗cookie         if(cookies!=null){             for(Cookie cookie : cookies){                 //获得cookie的加勒比海盗名称                 String cookieName = cookie.getName();                 if(cookieName.equals("name")){                     //获得该cookie的加勒比海盗                     String cookieValue = cookie.getValue();                     System.out.println(cookieValue);                 }             }         }

Cookie例子–获取上次登录时间

    //获得当前时间         Date date = new Date();         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");         String currentTime = format.format(date);          //1、创建Cookie 记录当前的加勒比海盗最新的加勒比海盗访问时间         Cookie cookie = new Cookie("lastAccessTime",currentTime);         cookie.setMaxAge(60*10*500);         response.addCookie(cookie);          //2、获得客户端携带cookie ---- lastAccessTime         String lastAccessTime = null;         Cookie[] cookies = request.getCookies();         if(cookies!=null){             for(Cookie coo : cookies){                 if("lastAccessTime".equals(coo.getName())){                     lastAccessTime = coo.getValue();                 }             }         }          response.setContentType("text/html;charset=UTF-8");         if(lastAccessTime==null){             response.getWriter().write("您是第一次访问");         }else{             response.getWriter().write("您上次的加勒比海盗访问的加勒比海盗时间是:"+lastAccessTime);         } 

思路如下:
将当前时间创建一个cookie,回传给浏览器,下次访问携带cookie,然后获取这个cookie,进而获取上次的加勒比海盗时间,第一次访问url,是不携带cookie的加勒比海盗,所以判断得出是第一次登录,下次访问就携带cookie,cookie带着时间值,然后显示上次登录的加勒比海盗时间

Session域值传递

SessionServlet1

//创建属于该客户端(会话)的加勒比海盗私有的加勒比海盗session区域         /* request.getSession()方法内部会判断 该客户端是否在加勒比海盗5服务器端已经存在加勒比海盗5session          * 如果该客户端在加勒比海盗5此服务器不存在加勒比海盗5session 那么就会创建一个新的加勒比海盗session对象          * 如果该客户端在加勒比海盗5此服务器已经存在加勒比海盗5session 获得已经存在加勒比海盗5加勒比海盗该session返回          */         HttpSession session = request.getSession();          session.setAttribute("name", "jerry");          String id = session.getId();//该session对象的加勒比海盗编号id          response.getWriter().write("JSESSIONID:"+id);

SessionServlet2

    //从session中获得存储的加勒比海盗数据         HttpSession session = request.getSession();          Object attribute =  session.getAttribute("name");          response.getWriter().write(attribute+"");

第一次访问SessionServlet1时,创建session,并且为session设值,为浏览器回传jSessionId(通过cookie的加勒比海盗形式),然后在加勒比海盗5不关闭浏览器的加勒比海盗前提下,进行访问SessionServlet2,这里会携带JsessionId,去获取session域设值的加勒比海盗

Cookie创建,回传,携带、Cookie案例(上次登录时间)、Session域值传递、Session持久化(购物例子)

Cookie创建,回传,携带、Cookie案例(上次登录时间)、Session域值传递、Session持久化(购物例子)

那么关闭浏览器再去访问SessionServlet2会出现null的加勒比海盗情况,也就是获取不到session值
因为JSESSIONID cookie形式是会话级别的加勒比海盗,关闭浏览器,cookie就消失了,访问SessionServlet2会创建一个新的加勒比海盗SessionId

所以我加勒比海盗5们就得需要JsessionId持久化

Session持久化 (购物例子)

    //创建属于该客户端(会话)的加勒比海盗私有的加勒比海盗session区域         /* request.getSession()方法内部会判断 该客户端是否在加勒比海盗5服务器端已经存在加勒比海盗5session          * 如果该客户端在加勒比海盗5此服务器不存在加勒比海盗5session 那么就会创建一个新的加勒比海盗session对象          * 如果该客户端在加勒比海盗5此服务器已经存在加勒比海盗5session 获得已经存在加勒比海盗5加勒比海盗该session返回          */         HttpSession session = request.getSession();          session.setAttribute("name", "jerry");          String id = session.getId();//该session对象的加勒比海盗编号id          //手动创建一个存储JSESSIONID的加勒比海盗Cookie 为该cookie设置持久化时间         Cookie cookie = new Cookie("JSESSIONID",id);         cookie.setPath("/WEB16/");         cookie.setMaxAge(60*10);          response.addCookie(cookie);           response.getWriter().write("JSESSIONID:"+id);

http://blog.csdn.net/u013210620/article/details/72872436加勒比海盗5

underscore源码分析(doing)

  准确说是源码注释,status:doing

//     Underscore.js 1.8.3 (function() {   //创建一个root对象,在加勒比海盗5浏览器中表示为window(self)对象,在加勒比海盗5node.js中表示global对象   //之所以使用self代替window是为了支持Web Worker   var root = typeof self == 'object' && self.self === self && self ||             typeof global == 'object' && global.global === global && global ||             this ||             {};  //使用"_"表示被覆盖之前的加勒比海盗   var previousUnderscore = root._;  //原型赋值,便于压缩(js保留字符不予以压缩)   var ArrayProto = Array.prototype, ObjProto = Object.prototype;   var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;    //将内置对象原型中的加勒比海盗常用方法赋值给变量引用,方便更方便的加勒比海盗引用(类似于工厂函数封装)   var push = ArrayProto.push,       slice = ArrayProto.slice,       toString = ObjProto.toString,       hasOwnProperty = ObjProto.hasOwnProperty;  //定义了一些ES5的加勒比海盗方法   var nativeIsArray = Array.isArray,//是否为数组       nativeKeys = Object.keys,//获取所有的加勒比海盗可枚举的加勒比海盗属性,返回一个数组       nativeCreate = Object.create;//创建一个对象,并把其prototype属性赋值为第一个参数   //未知(希望有知道的加勒比海盗告诉下)   var Ctor = function(){};  //下划线函数创建   var _ = function(obj) {     //判断obj是否是"_"的加勒比海盗实例,即_的加勒比海盗prototype所指向的加勒比海盗对象是否跟obj是同一个对象,要满足"==="的加勒比海盗关系     if (obj instanceof _) return obj;     //如果不是,则构造一个     if (!(this instanceof _)) return new _(obj);     //将underscore对象存放在加勒比海盗5_.wrapped属性中     this._wrapped = obj;   };    //针对不同的加勒比海盗宿主环境,将underscore的加勒比海盗命名变量存放到不同的加勒比海盗对象中   if (typeof exports != 'undefined' && !exports.nodeType) {     //node     if (typeof module != 'undefined' && !module.nodeType && module.exports) {       exports = module.exports = _;     }     exports._ = _;   } else {//浏览器     root._ = _;   }  //当前版本   _.VERSION = '1.8.3';    // Internal function that returns an efficient (for current engines) version   // of the passed-in callback, to be repeatedly applied in other Underscore   // functions.   var optimizeCb = function(func, context, argCount) {     if (context === void 0) return func;     switch (argCount) {       case 1: return function(value) {         return func.call(context, value);       };       // The 2-parameter case has been omitted only because no current consumers       // made use of it.       case null:       case 3: return function(value, index, collection) {         return func.call(context, value, index, collection);       };       case 4: return function(accumulator, value, index, collection) {         return func.call(context, accumulator, value, index, collection);       };     }     return function() {       return func.apply(context, arguments);     };   };    var builtinIteratee;    // An internal function to generate callbacks that can be applied to each   // element in a collection, returning the desired result — either `identity`,   // an arbitrary callback, a property matcher, or a property accessor.   var cb = function(value, context, argCount) {     if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);     if (value == null) return _.identity;     if (_.isFunction(value)) return optimizeCb(value, context, argCount);     if (_.isObject(value) && !_.isArray(value)) return _.matcher(value);     return _.property(value);   };    // External wrapper for our callback generator. Users may customize   // `_.iteratee` if they want additional predicate/iteratee shorthand styles.   // This abstraction hides the internal-only argCount argument.   _.iteratee = builtinIteratee = function(value, context) {     return cb(value, context, Infinity);   };    // Similar to ES6's rest param (http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html)   // This accumulates the arguments passed into an array, after a given index.   var restArgs = function(func, startIndex) {     startIndex = startIndex == null ? func.length - 1 : +startIndex;     return function() {       var length = Math.max(arguments.length - startIndex, 0),           rest = Array(length),           index = 0;       for (; index < length; index++) {         rest[index] = arguments[index + startIndex];       }       switch (startIndex) {         case 0: return func.call(this, rest);         case 1: return func.call(this, arguments[0], rest);         case 2: return func.call(this, arguments[0], arguments[1], rest);       }       var args = Array(startIndex + 1);       for (index = 0; index < startIndex; index++) {         args[index] = arguments[index];       }       args[startIndex] = rest;       return func.apply(this, args);     };   };    // An internal function for creating a new object that inherits from another.   var baseCreate = function(prototype) {     if (!_.isObject(prototype)) return {};     if (nativeCreate) return nativeCreate(prototype);     Ctor.prototype = prototype;     var result = new Ctor;     Ctor.prototype = null;     return result;   };    var shallowProperty = function(key) {     return function(obj) {       return obj == null ? void 0 : obj[key];     };   };    var deepGet = function(obj, path) {     var length = path.length;     for (var i = 0; i < length; i++) {       if (obj == null) return void 0;       obj = obj[path[i]];     }     return length ? obj : void 0;   };    // Helper for collection methods to determine whether a collection   // should be iterated as an array or as an object.   // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength   // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094   var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;   var getLength = shallowProperty('length');   var isArrayLike = function(collection) {     var length = getLength(collection);     return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;   };    // Collection Functions   // --------------------    // The cornerstone, an `each` implementation, aka `forEach`.   // Handles raw objects in addition to array-likes. Treats all   // sparse array-likes as if they were dense.   _.each = _.forEach = function(obj, iteratee, context) {     iteratee = optimizeCb(iteratee, context);     var i, length;     if (isArrayLike(obj)) {       for (i = 0, length = obj.length; i < length; i++) {         iteratee(obj[i], i, obj);       }     } else {       var keys = _.keys(obj);       for (i = 0, length = keys.length; i < length; i++) {         iteratee(obj[keys[i]], keys[i], obj);       }     }     return obj;   };    // Return the results of applying the iteratee to each element.   _.map = _.collect = function(obj, iteratee, context) {     iteratee = cb(iteratee, context);     var keys = !isArrayLike(obj) && _.keys(obj),         length = (keys || obj).length,         results = Array(length);     for (var index = 0; index < length; index++) {       var currentKey = keys ? keys[index] : index;       results[index] = iteratee(obj[currentKey], currentKey, obj);     }     return results;   };    // Create a reducing function iterating left or right.   var createReduce = function(dir) {     // Wrap code that reassigns argument variables in a separate function than     // the one that accesses `arguments.length` to avoid a perf hit. (#1991)     var reducer = function(obj, iteratee, memo, initial) {       var keys = !isArrayLike(obj) && _.keys(obj),           length = (keys || obj).length,           index = dir > 0 ? 0 : length - 1;       if (!initial) {         memo = obj[keys ? keys[index] : index];         index += dir;       }       for (; index >= 0 && index < length; index += dir) {         var currentKey = keys ? keys[index] : index;         memo = iteratee(memo, obj[currentKey], currentKey, obj);       }       return memo;     };      return function(obj, iteratee, memo, context) {       var initial = arguments.length >= 3;       return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial);     };   };    // **Reduce** builds up a single result from a list of values, aka `inject`,   // or `foldl`.   _.reduce = _.foldl = _.inject = createReduce(1);    // The right-associative version of reduce, also known as `foldr`.   _.reduceRight = _.foldr = createReduce(-1);    // Return the first value which passes a truth test. Aliased as `detect`.   _.find = _.detect = function(obj, predicate, context) {     var keyFinder = isArrayLike(obj) ? _.findIndex : _.findKey;     var key = keyFinder(obj, predicate, context);     if (key !== void 0 && key !== -1) return obj[key];   };    // Return all the elements that pass a truth test.   // Aliased as `select`.   _.filter = _.select = function(obj, predicate, context) {     var results = [];     predicate = cb(predicate, context);     _.each(obj, function(value, index, list) {       if (predicate(value, index, list)) results.push(value);     });     return results;   };    // Return all the elements for which a truth test fails.   _.reject = function(obj, predicate, context) {     return _.filter(obj, _.negate(cb(predicate)), context);   };    // Determine whether all of the elements match a truth test.   // Aliased as `all`.   _.every = _.all = function(obj, predicate, context) {     predicate = cb(predicate, context);     var keys = !isArrayLike(obj) && _.keys(obj),         length = (keys || obj).length;     for (var index = 0; index < length; index++) {       var currentKey = keys ? keys[index] : index;       if (!predicate(obj[currentKey], currentKey, obj)) return false;     }     return true;   };    // Determine if at least one element in the object matches a truth test.   // Aliased as `any`.   _.some = _.any = function(obj, predicate, context) {     predicate = cb(predicate, context);     var keys = !isArrayLike(obj) && _.keys(obj),         length = (keys || obj).length;     for (var index = 0; index < length; index++) {       var currentKey = keys ? keys[index] : index;       if (predicate(obj[currentKey], currentKey, obj)) return true;     }     return false;   };    // Determine if the array or object contains a given item (using `===`).   // Aliased as `includes` and `include`.   _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {     if (!isArrayLike(obj)) obj = _.values(obj);     if (typeof fromIndex != 'number' || guard) fromIndex = 0;     return _.indexOf(obj, item, fromIndex) >= 0;   };    // Invoke a method (with arguments) on every item in a collection.   _.invoke = restArgs(function(obj, path, args) {     var contextPath, func;     if (_.isFunction(path)) {       func = path;     } else if (_.isArray(path)) {       contextPath = path.slice(0, -1);       path = path[path.length - 1];     }     return _.map(obj, function(context) {       var method = func;       if (!method) {         if (contextPath && contextPath.length) {           context = deepGet(context, contextPath);         }         if (context == null) return void 0;         method = context[path];       }       return method == null ? method : method.apply(context, args);     });   });    // Convenience version of a common use case of `map`: fetching a property.   _.pluck = function(obj, key) {     return _.map(obj, _.property(key));   };    // Convenience version of a common use case of `filter`: selecting only objects   // containing specific `key:value` pairs.   _.where = function(obj, attrs) {     return _.filter(obj, _.matcher(attrs));   };    // Convenience version of a common use case of `find`: getting the first object   // containing specific `key:value` pairs.   _.findWhere = function(obj, attrs) {     return _.find(obj, _.matcher(attrs));   };    // Return the maximum element (or element-based computation).   _.max = function(obj, iteratee, context) {     var result = -Infinity, lastComputed = -Infinity,         value, computed;     if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object') && obj != null) {       obj = isArrayLike(obj) ? obj : _.values(obj);       for (var i = 0, length = obj.length; i < length; i++) {         value = obj[i];         if (value != null && value > result) {           result = value;         }       }     } else {       iteratee = cb(iteratee, context);       _.each(obj, function(v, index, list) {         computed = iteratee(v, index, list);         if (computed > lastComputed || computed === -Infinity && result === -Infinity) {           result = v;           lastComputed = computed;         }       });     }     return result;   };    // Return the minimum element (or element-based computation).   _.min = function(obj, iteratee, context) {     var result = Infinity, lastComputed = Infinity,         value, computed;     if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object') && obj != null) {       obj = isArrayLike(obj) ? obj : _.values(obj);       for (var i = 0, length = obj.length; i < length; i++) {         value = obj[i];         if (value != null && value < result) {           result = value;         }       }     } else {       iteratee = cb(iteratee, context);       _.each(obj, function(v, index, list) {         computed = iteratee(v, index, list);         if (computed < lastComputed || computed === Infinity && result === Infinity) {           result = v;           lastComputed = computed;         }       });     }     return result;   };    // Shuffle a collection.   _.shuffle = function(obj) {     return _.sample(obj, Infinity);   };    // Sample **n** random values from a collection using the modern version of the   // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).   // If **n** is not specified, returns a single random element.   // The internal `guard` argument allows it to work with `map`.   _.sample = function(obj, n, guard) {     if (n == null || guard) {       if (!isArrayLike(obj)) obj = _.values(obj);       return obj[_.random(obj.length - 1)];     }     var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj);     var length = getLength(sample);     n = Math.max(Math.min(n, length), 0);     var last = length - 1;     for (var index = 0; index < n; index++) {       var rand = _.random(index, last);       var temp = sample[index];       sample[index] = sample[rand];       sample[rand] = temp;     }     return sample.slice(0, n);   };    // Sort the object's values by a criterion produced by an iteratee.   _.sortBy = function(obj, iteratee, context) {     var index = 0;     iteratee = cb(iteratee, context);     return _.pluck(_.map(obj, function(value, key, list) {       return {         value: value,         index: index++,         criteria: iteratee(value, key, list)       };     }).sort(function(left, right) {       var a = left.criteria;       var b = right.criteria;       if (a !== b) {         if (a > b || a === void 0) return 1;         if (a < b || b === void 0) return -1;       }       return left.index - right.index;     }), 'value');   };    // An internal function used for aggregate "group by" operations.   var group = function(behavior, partition) {     return function(obj, iteratee, context) {       var result = partition ? [[], []] : {};       iteratee = cb(iteratee, context);       _.each(obj, function(value, index) {         var key = iteratee(value, index, obj);         behavior(result, value, key);       });       return result;     };   };    // Groups the object's values by a criterion. Pass either a string attribute   // to group by, or a function that returns the criterion.   _.groupBy = group(function(result, value, key) {     if (_.has(result, key)) result[key].push(value); else result[key] = [value];   });    // Indexes the object's values by a criterion, similar to `groupBy`, but for   // when you know that your index values will be unique.   _.indexBy = group(function(result, value, key) {     result[key] = value;   });    // Counts instances of an object that group by a certain criterion. Pass   // either a string attribute to count by, or a function that returns the   // criterion.   _.countBy = group(function(result, value, key) {     if (_.has(result, key)) result[key]++; else result[key] = 1;   });    var reStrSymbol = /[^/ud800-/udfff]|[/ud800-/udbff][/udc00-/udfff]|[/ud800-/udfff]/g;   // Safely create a real, live array from anything iterable.   _.toArray = function(obj) {     if (!obj) return [];     if (_.isArray(obj)) return slice.call(obj);     if (_.isString(obj)) {       // Keep surrogate pair characters together       return obj.match(reStrSymbol);     }     if (isArrayLike(obj)) return _.map(obj, _.identity);     return _.values(obj);   };    // Return the number of elements in an object.   _.size = function(obj) {     if (obj == null) return 0;     return isArrayLike(obj) ? obj.length : _.keys(obj).length;   };    // Split a collection into two arrays: one whose elements all satisfy the given   // predicate, and one whose elements all do not satisfy the predicate.   _.partition = group(function(result, value, pass) {     result[pass ? 0 : 1].push(value);   }, true);    // Array Functions   // ---------------    // Get the first element of an array. Passing **n** will return the first N   // values in the array. Aliased as `head` and `take`. The **guard** check   // allows it to work with `_.map`.   _.first = _.head = _.take = function(array, n, guard) {     if (array == null || array.length < 1) return void 0;     if (n == null || guard) return array[0];     return _.initial(array, array.length - n);   };    // Returns everything but the last entry of the array. Especially useful on   // the arguments object. Passing **n** will return all the values in   // the array, excluding the last N.   _.initial = function(array, n, guard) {     return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));   };    // Get the last element of an array. Passing **n** will return the last N   // values in the array.   _.last = function(array, n, guard) {     if (array == null || array.length < 1) return void 0;     if (n == null || guard) return array[array.length - 1];     return _.rest(array, Math.max(0, array.length - n));   };    // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.   // Especially useful on the arguments object. Passing an **n** will return   // the rest N values in the array.   _.rest = _.tail = _.drop = function(array, n, guard) {     return slice.call(array, n == null || guard ? 1 : n);   };    // Trim out all falsy values from an array.   _.compact = function(array) {     return _.filter(array, Boolean);   };    // Internal implementation of a recursive `flatten` function.   var flatten = function(input, shallow, strict, output) {     output = output || [];     var idx = output.length;     for (var i = 0, length = getLength(input); i < length; i++) {       var value = input[i];       if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {         // Flatten current level of array or arguments object.         if (shallow) {           var j = 0, len = value.length;           while (j < len) output[idx++] = value[j++];         } else {           flatten(value, shallow, strict, output);           idx = output.length;         }       } else if (!strict) {         output[idx++] = value;       }     }     return output;   };    // Flatten out an array, either recursively (by default), or just one level.   _.flatten = function(array, shallow) {     return flatten(array, shallow, false);   };    // Return a version of the array that does not contain the specified value(s).   _.without = restArgs(function(array, otherArrays) {     return _.difference(array, otherArrays);   });    // Produce a duplicate-free version of the array. If the array has already   // been sorted, you have the option of using a faster algorithm.   // Aliased as `unique`.   _.uniq = _.unique = function(array, isSorted, iteratee, context) {     if (!_.isBoolean(isSorted)) {       context = iteratee;       iteratee = isSorted;       isSorted = false;     }     if (iteratee != null) iteratee = cb(iteratee, context);     var result = [];     var seen = [];     for (var i = 0, length = getLength(array); i < length; i++) {       var value = array[i],           computed = iteratee ? iteratee(value, i, array) : value;       if (isSorted) {         if (!i || seen !== computed) result.push(value);         seen = computed;       } else if (iteratee) {         if (!_.contains(seen, computed)) {           seen.push(computed);           result.push(value);         }       } else if (!_.contains(result, value)) {         result.push(value);       }     }     return result;   };    // Produce an array that contains the union: each distinct element from all of   // the passed-in arrays.   _.union = restArgs(function(arrays) {     return _.uniq(flatten(arrays, true, true));   });    // Produce an array that contains every item shared between all the   // passed-in arrays.   _.intersection = function(array) {     var result = [];     var argsLength = arguments.length;     for (var i = 0, length = getLength(array); i < length; i++) {       var item = array[i];       if (_.contains(result, item)) continue;       var j;       for (j = 1; j < argsLength; j++) {         if (!_.contains(arguments[j], item)) break;       }       if (j === argsLength) result.push(item);     }     return result;   };    // Take the difference between one array and a number of other arrays.   // Only the elements present in just the first array will remain.   _.difference = restArgs(function(array, rest) {     rest = flatten(rest, true, true);     return _.filter(array, function(value){       return !_.contains(rest, value);     });   });    // Complement of _.zip. Unzip accepts an array of arrays and groups   // each array's elements on shared indices.   _.unzip = function(array) {     var length = array && _.max(array, getLength).length || 0;     var result = Array(length);      for (var index = 0; index < length; index++) {       result[index] = _.pluck(array, index);     }     return result;   };    // Zip together multiple lists into a single array -- elements that share   // an index go together.   _.zip = restArgs(_.unzip);    // Converts lists into objects. Pass either a single array of `[key, value]`   // pairs, or two parallel arrays of the same length -- one of keys, and one of   // the corresponding values. Passing by pairs is the reverse of _.pairs.   _.object = function(list, values) {     var result = {};     for (var i = 0, length = getLength(list); i < length; i++) {       if (values) {         result[list[i]] = values[i];       } else {         result[list[i][0]] = list[i][1];       }     }     return result;   };    // Generator function to create the findIndex and findLastIndex functions.   var createPredicateIndexFinder = function(dir) {     return function(array, predicate, context) {       predicate = cb(predicate, context);       var length = getLength(array);       var index = dir > 0 ? 0 : length - 1;       for (; index >= 0 && index < length; index += dir) {         if (predicate(array[index], index, array)) return index;       }       return -1;     };   };    // Returns the first index on an array-like that passes a predicate test.   _.findIndex = createPredicateIndexFinder(1);   _.findLastIndex = createPredicateIndexFinder(-1);    // Use a comparator function to figure out the smallest index at which   // an object should be inserted so as to maintain order. Uses binary search.   _.sortedIndex = function(array, obj, iteratee, context) {     iteratee = cb(iteratee, context, 1);     var value = iteratee(obj);     var low = 0, high = getLength(array);     while (low < high) {       var mid = Math.floor((low + high) / 2);       if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;     }     return low;   };    // Generator function to create the indexOf and lastIndexOf functions.   var createIndexFinder = function(dir, predicateFind, sortedIndex) {     return function(array, item, idx) {       var i = 0, length = getLength(array);       if (typeof idx == 'number') {         if (dir > 0) {           i = idx >= 0 ? idx : Math.max(idx + length, i);         } else {           length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;         }       } else if (sortedIndex && idx && length) {         idx = sortedIndex(array, item);         return array[idx] === item ? idx : -1;       }       if (item !== item) {         idx = predicateFind(slice.call(array, i, length), _.isNaN);         return idx >= 0 ? idx + i : -1;       }       for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {         if (array[idx] === item) return idx;       }       return -1;     };   };    // Return the position of the first occurrence of an item in an array,   // or -1 if the item is not included in the array.   // If the array is large and already in sort order, pass `true`   // for **isSorted** to use binary search.   _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);   _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);    // Generate an integer Array containing an arithmetic progression. A port of   // the native Python `range()` function. See   // [the Python documentation](http://docs.python.org/library/functions.html#range).   _.range = function(start, stop, step) {     if (stop == null) {       stop = start || 0;       start = 0;     }     if (!step) {       step = stop < start ? -1 : 1;     }      var length = Math.max(Math.ceil((stop - start) / step), 0);     var range = Array(length);      for (var idx = 0; idx < length; idx++, start += step) {       range[idx] = start;     }      return range;   };    // Split an **array** into several arrays containing **count** or less elements   // of initial array.   _.chunk = function(array, count) {     if (count == null || count < 1) return [];      var result = [];     var i = 0, length = array.length;     while (i < length) {       result.push(slice.call(array, i, i += count));     }     return result;   };    // Function (ahem) Functions   // ------------------    // Determines whether to execute a function as a constructor   // or a normal function with the provided arguments.   var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {     if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);     var self = baseCreate(sourceFunc.prototype);     var result = sourceFunc.apply(self, args);     if (_.isObject(result)) return result;     return self;   };    // Create a function bound to a given object (assigning `this`, and arguments,   // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if   // available.   _.bind = restArgs(function(func, context, args) {     if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');     var bound = restArgs(function(callArgs) {       return executeBound(func, bound, context, this, args.concat(callArgs));     });     return bound;   });    // Partially apply a function by creating a version that has had some of its   // arguments pre-filled, without changing its dynamic `this` context. _ acts   // as a placeholder by default, allowing any combination of arguments to be   // pre-filled. Set `_.partial.placeholder` for a custom placeholder argument.   _.partial = restArgs(function(func, boundArgs) {     var placeholder = _.partial.placeholder;     var bound = function() {       var position = 0, length = boundArgs.length;       var args = Array(length);       for (var i = 0; i < length; i++) {         args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i];       }       while (position < arguments.length) args.push(arguments[position++]);       return executeBound(func, bound, this, this, args);     };     return bound;   });    _.partial.placeholder = _;    // Bind a number of an object's methods to that object. Remaining arguments   // are the method names to be bound. Useful for ensuring that all callbacks   // defined on an object belong to it.   _.bindAll = restArgs(function(obj, keys) {     keys = flatten(keys, false, false);     var index = keys.length;     if (index < 1) throw new Error('bindAll must be passed function names');     while (index--) {       var key = keys[index];       obj[key] = _.bind(obj[key], obj);     }   });    // Memoize an expensive function by storing its results.   _.memoize = function(func, hasher) {     var memoize = function(key) {       var cache = memoize.cache;       var address = '' + (hasher ? hasher.apply(this, arguments) : key);       if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);       return cache[address];     };     memoize.cache = {};     return memoize;   };    // Delays a function for the given number of milliseconds, and then calls   // it with the arguments supplied.   _.delay = restArgs(function(func, wait, args) {     return setTimeout(function() {       return func.apply(null, args);     }, wait);   });    // Defers a function, scheduling it to run after the current call stack has   // cleared.   _.defer = _.partial(_.delay, _, 1);    // Returns a function, that, when invoked, will only be triggered at most once   // during a given window of time. Normally, the throttled function will run   // as much as it can, without ever going more than once per `wait` duration;   // but if you'd like to disable the execution on the leading edge, pass   // `{leading: false}`. To disable execution on the trailing edge, ditto.   _.throttle = function(func, wait, options) {     var timeout, context, args, result;     var previous = 0;     if (!options) options = {};      var later = function() {       previous = options.leading === false ? 0 : _.now();       timeout = null;       result = func.apply(context, args);       if (!timeout) context = args = null;     };      var throttled = function() {       var now = _.now();       if (!previous && options.leading === false) previous = now;       var remaining = wait - (now - previous);       context = this;       args = arguments;       if (remaining <= 0 || remaining > wait) {         if (timeout) {           clearTimeout(timeout);           timeout = null;         }         previous = now;         result = func.apply(context, args);         if (!timeout) context = args = null;       } else if (!timeout && options.trailing !== false) {         timeout = setTimeout(later, remaining);       }       return result;     };      throttled.cancel = function() {       clearTimeout(timeout);       previous = 0;       timeout = context = args = null;     };      return throttled;   };    // Returns a function, that, as long as it continues to be invoked, will not   // be triggered. The function will be called after it stops being called for   // N milliseconds. If `immediate` is passed, trigger the function on the   // leading edge, instead of the trailing.   _.debounce = function(func, wait, immediate) {     var timeout, result;      var later = function(context, args) {       timeout = null;       if (args) result = func.apply(context, args);     };      var debounced = restArgs(function(args) {       if (timeout) clearTimeout(timeout);       if (immediate) {         var callNow = !timeout;         timeout = setTimeout(later, wait);         if (callNow) result = func.apply(this, args);       } else {         timeout = _.delay(later, wait, this, args);       }        return result;     });      debounced.cancel = function() {       clearTimeout(timeout);       timeout = null;     };      return debounced;   };    // Returns the first function passed as an argument to the second,   // allowing you to adjust arguments, run code before and after, and   // conditionally execute the original function.   _.wrap = function(func, wrapper) {     return _.partial(wrapper, func);   };    // Returns a negated version of the passed-in predicate.   _.negate = function(predicate) {     return function() {       return !predicate.apply(this, arguments);     };   };    // Returns a function that is the composition of a list of functions, each   // consuming the return value of the function that follows.   _.compose = function() {     var args = arguments;     var start = args.length - 1;     return function() {       var i = start;       var result = args[start].apply(this, arguments);       while (i--) result = args[i].call(this, result);       return result;     };   };    // Returns a function that will only be executed on and after the Nth call.   _.after = function(times, func) {     return function() {       if (--times < 1) {         return func.apply(this, arguments);       }     };   };    // Returns a function that will only be executed up to (but not including) the Nth call.   _.before = function(times, func) {     var memo;     return function() {       if (--times > 0) {         memo = func.apply(this, arguments);       }       if (times <= 1) func = null;       return memo;     };   };    // Returns a function that will be executed at most one time, no matter how   // often you call it. Useful for lazy initialization.   _.once = _.partial(_.before, 2);    _.restArgs = restArgs;    // Object Functions   // ----------------    // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.   var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');   var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',                       'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];    var collectNonEnumProps = function(obj, keys) {     var nonEnumIdx = nonEnumerableProps.length;     var constructor = obj.constructor;     var proto = _.isFunction(constructor) && constructor.prototype || ObjProto;      // Constructor is a special case.     var prop = 'constructor';     if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);      while (nonEnumIdx--) {       prop = nonEnumerableProps[nonEnumIdx];       if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {         keys.push(prop);       }     }   };    // Retrieve the names of an object's own properties.   // Delegates to **ECMAScript 5**'s native `Object.keys`.   _.keys = function(obj) {     if (!_.isObject(obj)) return [];     if (nativeKeys) return nativeKeys(obj);     var keys = [];     for (var key in obj) if (_.has(obj, key)) keys.push(key);     // Ahem, IE < 9.     if (hasEnumBug) collectNonEnumProps(obj, keys);     return keys;   };    // Retrieve all the property names of an object.   _.allKeys = function(obj) {     if (!_.isObject(obj)) return [];     var keys = [];     for (var key in obj) keys.push(key);     // Ahem, IE < 9.     if (hasEnumBug) collectNonEnumProps(obj, keys);     return keys;   };    // Retrieve the values of an object's properties.   _.values = function(obj) {     var keys = _.keys(obj);     var length = keys.length;     var values = Array(length);     for (var i = 0; i < length; i++) {       values[i] = obj[keys[i]];     }     return values;   };    // Returns the results of applying the iteratee to each element of the object.   // In contrast to _.map it returns an object.   _.mapObject = function(obj, iteratee, context) {     iteratee = cb(iteratee, context);     var keys = _.keys(obj),         length = keys.length,         results = {};     for (var index = 0; index < length; index++) {       var currentKey = keys[index];       results[currentKey] = iteratee(obj[currentKey], currentKey, obj);     }     return results;   };    // Convert an object into a list of `[key, value]` pairs.   // The opposite of _.object.   _.pairs = function(obj) {     var keys = _.keys(obj);     var length = keys.length;     var pairs = Array(length);     for (var i = 0; i < length; i++) {       pairs[i] = [keys[i], obj[keys[i]]];     }     return pairs;   };    // Invert the keys and values of an object. The values must be serializable.   _.invert = function(obj) {     var result = {};     var keys = _.keys(obj);     for (var i = 0, length = keys.length; i < length; i++) {       result[obj[keys[i]]] = keys[i];     }     return result;   };    // Return a sorted list of the function names available on the object.   // Aliased as `methods`.   _.functions = _.methods = function(obj) {     var names = [];     for (var key in obj) {       if (_.isFunction(obj[key])) names.push(key);     }     return names.sort();   };    // An internal function for creating assigner functions.   var createAssigner = function(keysFunc, defaults) {     return function(obj) {       var length = arguments.length;       if (defaults) obj = Object(obj);       if (length < 2 || obj == null) return obj;       for (var index = 1; index < length; index++) {         var source = arguments[index],             keys = keysFunc(source),             l = keys.length;         for (var i = 0; i < l; i++) {           var key = keys[i];           if (!defaults || obj[key] === void 0) obj[key] = source[key];         }       }       return obj;     };   };    // Extend a given object with all the properties in passed-in object(s).   _.extend = createAssigner(_.allKeys);    // Assigns a given object with all the own properties in the passed-in object(s).   // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)   _.extendOwn = _.assign = createAssigner(_.keys);    // Returns the first key on an object that passes a predicate test.   _.findKey = function(obj, predicate, context) {     predicate = cb(predicate, context);     var keys = _.keys(obj), key;     for (var i = 0, length = keys.length; i < length; i++) {       key = keys[i];       if (predicate(obj[key], key, obj)) return key;     }   };    // Internal pick helper function to determine if `obj` has key `key`.   var keyInObj = function(value, key, obj) {     return key in obj;   };    // Return a copy of the object only containing the whitelisted properties.   _.pick = restArgs(function(obj, keys) {     var result = {}, iteratee = keys[0];     if (obj == null) return result;     if (_.isFunction(iteratee)) {       if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]);       keys = _.allKeys(obj);     } else {       iteratee = keyInObj;       keys = flatten(keys, false, false);       obj = Object(obj);     }     for (var i = 0, length = keys.length; i < length; i++) {       var key = keys[i];       var value = obj[key];       if (iteratee(value, key, obj)) result[key] = value;     }     return result;   });    // Return a copy of the object without the blacklisted properties.   _.omit = restArgs(function(obj, keys) {     var iteratee = keys[0], context;     if (_.isFunction(iteratee)) {       iteratee = _.negate(iteratee);       if (keys.length > 1) context = keys[1];     } else {       keys = _.map(flatten(keys, false, false), String);       iteratee = function(value, key) {         return !_.contains(keys, key);       };     }     return _.pick(obj, iteratee, context);   });    // Fill in a given object with default properties.   _.defaults = createAssigner(_.allKeys, true);    // Creates an object that inherits from the given prototype object.   // If additional properties are provided then they will be added to the   // created object.   _.create = function(prototype, props) {     var result = baseCreate(prototype);     if (props) _.extendOwn(result, props);     return result;   };    // Create a (shallow-cloned) duplicate of an object.   _.clone = function(obj) {     if (!_.isObject(obj)) return obj;     return _.isArray(obj) ? obj.slice() : _.extend({}, obj);   };    // Invokes interceptor with the obj, and then returns obj.   // The primary purpose of this method is to "tap into" a method chain, in   // order to perform operations on intermediate results within the chain.   _.tap = function(obj, interceptor) {     interceptor(obj);     return obj;   };    // Returns whether an object has a given set of `key:value` pairs.   _.isMatch = function(object, attrs) {     var keys = _.keys(attrs), length = keys.length;     if (object == null) return !length;     var obj = Object(object);     for (var i = 0; i < length; i++) {       var key = keys[i];       if (attrs[key] !== obj[key] || !(key in obj)) return false;     }     return true;   };     // Internal recursive comparison function for `isEqual`.   var eq, deepEq;   eq = function(a, b, aStack, bStack) {     // Identical objects are equal. `0 === -0`, but they aren't identical.     // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).     if (a === b) return a !== 0 || 1 / a === 1 / b;     // `null` or `undefined` only equal to itself (strict comparison).     if (a == null || b == null) return false;     // `NaN`s are equivalent, but non-reflexive.     if (a !== a) return b !== b;     // Exhaust primitive checks     var type = typeof a;     if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;     return deepEq(a, b, aStack, bStack);   };    // Internal recursive comparison function for `isEqual`.   deepEq = function(a, b, aStack, bStack) {     // Unwrap any wrapped objects.     if (a instanceof _) a = a._wrapped;     if (b instanceof _) b = b._wrapped;     // Compare `[[Class]]` names.     var className = toString.call(a);     if (className !== toString.call(b)) return false;     switch (className) {       // Strings, numbers, regular expressions, dates, and booleans are compared by value.       case '[object RegExp]':       // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')       case '[object String]':         // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is         // equivalent to `new String("5")`.         return '' + a === '' + b;       case '[object Number]':         // `NaN`s are equivalent, but non-reflexive.         // Object(NaN) is equivalent to NaN.         if (+a !== +a) return +b !== +b;         // An `egal` comparison is performed for other numeric values.         return +a === 0 ? 1 / +a === 1 / b : +a === +b;       case '[object Date]':       case '[object Boolean]':         // Coerce dates and booleans to numeric primitive values. Dates are compared by their         // millisecond representations. Note that invalid dates with millisecond representations         // of `NaN` are not equivalent.         return +a === +b;       case '[object Symbol]':         return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);     }      var areArrays = className === '[object Array]';     if (!areArrays) {       if (typeof a != 'object' || typeof b != 'object') return false;        // Objects with different constructors are not equivalent, but `Object`s or `Array`s       // from different frames are.       var aCtor = a.constructor, bCtor = b.constructor;       if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&                                _.isFunction(bCtor) && bCtor instanceof bCtor)                           && ('constructor' in a && 'constructor' in b)) {         return false;       }     }     // Assume equality for cyclic structures. The algorithm for detecting cyclic     // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.      // Initializing stack of traversed objects.     // It's done here since we only need them for objects and arrays comparison.     aStack = aStack || [];     bStack = bStack || [];     var length = aStack.length;     while (length--) {       // Linear search. Performance is inversely proportional to the number of       // unique nested structures.       if (aStack[length] === a) return bStack[length] === b;     }      // Add the first object to the stack of traversed objects.     aStack.push(a);     bStack.push(b);      // Recursively compare objects and arrays.     if (areArrays) {       // Compare array lengths to determine if a deep comparison is necessary.       length = a.length;       if (length !== b.length) return false;       // Deep compare the contents, ignoring non-numeric properties.       while (length--) {         if (!eq(a[length], b[length], aStack, bStack)) return false;       }     } else {       // Deep compare objects.       var keys = _.keys(a), key;       length = keys.length;       // Ensure that both objects contain the same number of properties before comparing deep equality.       if (_.keys(b).length !== length) return false;       while (length--) {         // Deep compare each member         key = keys[length];         if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;       }     }     // Remove the first object from the stack of traversed objects.     aStack.pop();     bStack.pop();     return true;   };    // Perform a deep comparison to check if two objects are equal.   _.isEqual = function(a, b) {     return eq(a, b);   };    // Is a given array, string, or object empty?   // An "empty" object has no enumerable own-properties.   _.isEmpty = function(obj) {     if (obj == null) return true;     if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;     return _.keys(obj).length === 0;   };    // Is a given value a DOM element?   _.isElement = function(obj) {     return !!(obj && obj.nodeType === 1);   };    // Is a given value an array?   // Delegates to ECMA5's native Array.isArray   _.isArray = nativeIsArray || function(obj) {     return toString.call(obj) === '[object Array]';   };    // Is a given variable an object?   _.isObject = function(obj) {     var type = typeof obj;     return type === 'function' || type === 'object' && !!obj;   };    // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError, isMap, isWeakMap, isSet, isWeakSet.   _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error', 'Symbol', 'Map', 'WeakMap', 'Set', 'WeakSet'], function(name) {     _['is' + name] = function(obj) {       return toString.call(obj) === '[object ' + name + ']';     };   });    // Define a fallback version of the method in browsers (ahem, IE < 9), where   // there isn't any inspectable "Arguments" type.   if (!_.isArguments(arguments)) {     _.isArguments = function(obj) {       return _.has(obj, 'callee');     };   }    // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,   // IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236).   var nodelist = root.document && root.document.childNodes;   if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') {     _.isFunction = function(obj) {       return typeof obj == 'function' || false;     };   }    // Is a given object a finite number?   _.isFinite = function(obj) {     return !_.isSymbol(obj) && isFinite(obj) && !isNaN(parseFloat(obj));   };    // Is the given value `NaN`?   _.isNaN = function(obj) {     return _.isNumber(obj) && isNaN(obj);   };    // Is a given value a boolean?   _.isBoolean = function(obj) {     return obj === true || obj === false || toString.call(obj) === '[object Boolean]';   };    // Is a given value equal to null?   _.isNull = function(obj) {     return obj === null;   };    // Is a given variable undefined?   _.isUndefined = function(obj) {     return obj === void 0;   };    // Shortcut function for checking if an object has a given property directly   // on itself (in other words, not on a prototype).   _.has = function(obj, path) {     if (!_.isArray(path)) {       return obj != null && hasOwnProperty.call(obj, path);     }     var length = path.length;     for (var i = 0; i < length; i++) {       var key = path[i];       if (obj == null || !hasOwnProperty.call(obj, key)) {         return false;       }       obj = obj[key];     }     return !!length;   };    // Utility Functions   // -----------------    // Run Underscore.js in *noConflict* mode, returning the `_` variable to its   // previous owner. Returns a reference to the Underscore object.   _.noConflict = function() {     root._ = previousUnderscore;     return this;   };    // Keep the identity function around for default iteratees.   _.identity = function(value) {     return value;   };    // Predicate-generating functions. Often useful outside of Underscore.   _.constant = function(value) {     return function() {       return value;     };   };    _.noop = function(){};    _.property = function(path) {     if (!_.isArray(path)) {       return shallowProperty(path);     }     return function(obj) {       return deepGet(obj, path);     };   };    // Generates a function for a given object that returns a given property.   _.propertyOf = function(obj) {     if (obj == null) {       return function(){};     }     return function(path) {       return !_.isArray(path) ? obj[path] : deepGet(obj, path);     };   };    // Returns a predicate for checking whether an object has a given set of   // `key:value` pairs.   _.matcher = _.matches = function(attrs) {     attrs = _.extendOwn({}, attrs);     return function(obj) {       return _.isMatch(obj, attrs);     };   };    // Run a function **n** times.   _.times = function(n, iteratee, context) {     var accum = Array(Math.max(0, n));     iteratee = optimizeCb(iteratee, context, 1);     for (var i = 0; i < n; i++) accum[i] = iteratee(i);     return accum;   };    // Return a random integer between min and max (inclusive).   _.random = function(min, max) {     if (max == null) {       max = min;       min = 0;     }     return min + Math.floor(Math.random() * (max - min + 1));   };    // A (possibly faster) way to get the current timestamp as an integer.   _.now = Date.now || function() {     return new Date().getTime();   };    // List of HTML entities for escaping.   var escapeMap = {     '&': '&amp;',     '<': '&lt;',     '>': '&gt;',     '"': '&quot;',     "'": '&#x27;',     '`': '&#x60;'   };   var unescapeMap = _.invert(escapeMap);    // Functions for escaping and unescaping strings to/from HTML interpolation.   var createEscaper = function(map) {     var escaper = function(match) {       return map[match];     };     // Regexes for identifying a key that needs to be escaped.     var source = '(?:' + _.keys(map).join('|') + ')';     var testRegexp = RegExp(source);     var replaceRegexp = RegExp(source, 'g');     return function(string) {       string = string == null ? '' : '' + string;       return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;     };   };   _.escape = createEscaper(escapeMap);   _.unescape = createEscaper(unescapeMap);    // Traverses the children of `obj` along `path`. If a child is a function, it   // is invoked with its parent as context. Returns the value of the final   // child, or `fallback` if any child is undefined.   _.result = function(obj, path, fallback) {     if (!_.isArray(path)) path = [path];     var length = path.length;     if (!length) {       return _.isFunction(fallback) ? fallback.call(obj) : fallback;     }     for (var i = 0; i < length; i++) {       var prop = obj == null ? void 0 : obj[path[i]];       if (prop === void 0) {         prop = fallback;         i = length; // Ensure we don't continue iterating.       }       obj = _.isFunction(prop) ? prop.call(obj) : prop;     }     return obj;   };    // Generate a unique integer id (unique within the entire client session).   // Useful for temporary DOM ids.   var idCounter = 0;   _.uniqueId = function(prefix) {     var id = ++idCounter + '';     return prefix ? prefix + id : id;   };    // By default, Underscore uses ERB-style template delimiters, change the   // following template settings to use alternative delimiters.   _.templateSettings = {     evaluate: /<%([/s/S]+?)%>/g,     interpolate: /<%=([/s/S]+?)%>/g,     escape: /<%-([/s/S]+?)%>/g   };    // When customizing `templateSettings`, if you don't want to define an   // interpolation, evaluation or escaping regex, we need one that is   // guaranteed not to match.   var noMatch = /(.)^/;    // Certain characters need to be escaped so that they can be put into a   // string literal.   var escapes = {     "'": "'",     '//': '//',     '/r': 'r',     '/n': 'n',     '/u2028': 'u2028',     '/u2029': 'u2029'   };    var escapeRegExp = ///|'|/r|/n|/u2028|/u2029/g;    var escapeChar = function(match) {     return '//' + escapes[match];   };    // JavaScript micro-templating, similar to John Resig's implementation.   // Underscore templating handles arbitrary delimiters, preserves whitespace,   // and correctly escapes quotes within interpolated code.   // NB: `oldSettings` only exists for backwards compatibility.   _.template = function(text, settings, oldSettings) {     if (!settings && oldSettings) settings = oldSettings;     settings = _.defaults({}, settings, _.templateSettings);      // Combine delimiters into one regular expression via alternation.     var matcher = RegExp([       (settings.escape || noMatch).source,       (settings.interpolate || noMatch).source,       (settings.evaluate || noMatch).source     ].join('|') + '|$', 'g');      // Compile the template source, escaping string literals appropriately.     var index = 0;     var source = "__p+='";     text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {       source += text.slice(index, offset).replace(escapeRegExp, escapeChar);       index = offset + match.length;        if (escape) {         source += "'+/n((__t=(" + escape + "))==null?'':_.escape(__t))+/n'";       } else if (interpolate) {         source += "'+/n((__t=(" + interpolate + "))==null?'':__t)+/n'";       } else if (evaluate) {         source += "';/n" + evaluate + "/n__p+='";       }        // Adobe VMs need the match returned to produce the correct offset.       return match;     });     source += "';/n";      // If a variable is not specified, place data values in local scope.     if (!settings.variable) source = 'with(obj||{}){/n' + source + '}/n';      source = "var __t,__p='',__j=Array.prototype.join," +       "print=function(){__p+=__j.call(arguments,'');};/n" +       source + 'return __p;/n';      var render;     try {       render = new Function(settings.variable || 'obj', '_', source);     } catch (e) {       e.source = source;       throw e;     }      var template = function(data) {       return render.call(this, data, _);     };      // Provide the compiled source as a convenience for precompilation.     var argument = settings.variable || 'obj';     template.source = 'function(' + argument + '){/n' + source + '}';      return template;   };    //创建chain函数,用来支持链式调用(优点是代码简洁易读,减少了多次重复使用同一个变量),例如   //$("#id").show().hide().show();   //返回对象或this即可实现   //var obj={};   //obj.a=function(){   //  console.log("a")   //  return this   //}   //obj.b=function(){   //  console.log("n")   //  return this   //}   //obj.a().b();   _.chain = function(obj) {     var instance = _(obj);     instance._chain = true;     return instance;   };   //返回_.chain()里是否调用的加勒比海盗结果,true则返回一个被包装的加勒比海盗underscore对象   var chainResult = function(instance, obj) {     return instance._chain ? _(obj).chain() : obj;   };   //扩展underscore自身的加勒比海盗接口函数   _.mixin = function(obj) {     //通过循环遍历对象来拷贝对象属性,类似es6的加勒比海盗obj=Object.assign({},obj,objOne)     _.each(_.functions(obj), function(name) {       var func = _[name] = obj[name];       _.prototype[name] = function() {         var args = [this._wrapped];         push.apply(args, arguments);         return chainResult(this, func.apply(_, args));       };     });     return _;   };    _.mixin(_);    //将Array.prototype中的加勒比海盗相关方法添加到Underscore对象中,这样Underscore就可以直接调用Array.prototype中的加勒比海盗方法   _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {     //方法引用     var method = ArrayProto[name];     _.prototype[name] = function() {       //赋给obj引用变量方便调用       var obj = this._wrapped;       //调用Array对应的加勒比海盗方法       //apply方法能劫持另外一个对象的加勒比海盗方法,继承另外一个对象的加勒比海盗属性       //Function.apply(obj,args)方法能接收两个参数       //obj:这个对象将代替Function类里this对象       //args:这个是数组,它将作为参数传给Function(args-->arguments)       method.apply(obj, arguments);       if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];       //返回被包装的加勒比海盗underscore对象       return chainResult(this, obj);     };   });  //将Array.prototype中的加勒比海盗相关方法添加到Underscore对象中,这样Underscore就可以直接调用Array.prototype中的加勒比海盗方法 //  支持链式操作   _.each(['concat', 'join', 'slice'], function(name) {     var method = ArrayProto[name];     _.prototype[name] = function() {       //返回Array对象或者封装后的加勒比海盗Array       return chainResult(this, method.apply(this._wrapped, arguments));     };   });    //返回被放在加勒比海盗5_wrapped属性中的加勒比海盗underscore对象   _.prototype.value = function() {     return this._wrapped;   };    //体红会一些其他方法方便使用   _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;    _.prototype.toString = function() {     return String(this._wrapped);   };  //AMD输出 //  AMD模块API: //define(id?, dependencies?, factory); //以下是使用AMD模式开发的加勒比海盗简单三层结构(基础库/UI层/应用层): // //base.js //  define(function() { //    return { //      mix: function(source, target) { //      } //    }; //  }); //  ui.js //  define(['base'], function(base) { //    return { //      show: function() { //        // todo with module base //      } //    } //  }); //  page.js //  define(['data', 'ui'], function(data, ui) { //    // init here //  });   if (typeof define == 'function' && define.amd) {     define('underscore', [], function() {       return _;     });   } }());  //流程: //首先underscore包裹在加勒比海盗5一个匿名自执行的加勒比海盗函数当中 //内部定义了一个"_"变量 //将underscore中的加勒比海盗相关方法添加到_原型中,创建的加勒比海盗_对象就具备了underscore方法 //将Array.prototype中的加勒比海盗相关方法添加到Underscore对象中, 这样Underscore对象也可以直接调用Array.prototype中的加勒比海盗方法

http://blog.csdn.net/chern1992/article/details/72874557加勒比海盗5

前端手机本地调试小技巧

问题:pc调试手机页面经常出现一些问题,所以需要在加勒比海盗5手机上查看,更便于观察问题。

准备工作:手机(与电脑在加勒比海盗5同一局域网下),编辑器(我加勒比海盗5用的加勒比海盗Hbuilder,我加勒比海盗5测试了大多编辑器都有启动本地服务的加勒比海盗功能),电脑(我加勒比海盗5加勒比海盗是windows,mac的加勒比海盗请找自己ip的加勒比海盗方式)

1.本地的加勒比海盗项目,在加勒比海盗5chrome下查看

前端手机本地调试小技巧

2.本地打开效果

前端手机本地调试小技巧

3.打开自己的加勒比海盗终端输入ipconfig  找到自己的加勒比海盗IPv4的加勒比海盗地址

前端手机本地调试小技巧

4.IPv4的加勒比海盗地址替换启动本地项目地址(本地地址有的加勒比海盗尾localhost,有的加勒比海盗为172…,不要把端口替换)

前端手机本地调试小技巧

5.本地查看(这个地址发送给手机,但是一定确保手机和电脑在加勒比海盗5同一网下)

前端手机本地调试小技巧

总结:我加勒比海盗5测试了很多编辑器,但是一定要启动本地服务才行。

http://blog.csdn.net/qq_30916013/article/details/72868056加勒比海盗5

[ES6语法1]let和const

/**学习es6第一篇:let和const命令  * Created by liyanq on 17/6/5.  * http://es6.ruanyifeng.com/#docs/let  */ /*summary  * 1,let是用来声明变量,不是常量(swift是常量),但是所声明的加勒比海盗变量,只在加勒比海盗5let命令所在加勒比海盗5加勒比海盗代码块内有效。  * 2,不存在加勒比海盗5变量提升  * */  for (let i = 0; i < 3; i++) {//块级的加勒比海盗i } //console.log(i);//ReferenceError: i is not defined;//和以前不一样了哦~  var a = []; for (var i = 0; i < 10; i++) {//全局的加勒比海盗i   a[i] = function () {     console.log(i);   } } a[6]();//10 for (let i = 0; i < 10; i++) {//块级的加勒比海盗i,覆盖了全局的加勒比海盗i   a[i] = function () {     console.log(i);   } } a[6]();//6 for (let i = 0; i < 1; i++) {   let i = "abc";   console.log(i);//abc } //-----let不存在加勒比海盗5变量提升--------// /*可放开  console.log(foo);//undefined  var foo = "123";   console.log(bar);  let bar = "bar";//ReferenceError: bar is not defined*/ //-----暂时性死区----------// /*只要块级作用域内存在加勒比海盗5let命令,它所声明的加勒比海盗变量就“绑定”(binding)这个区域,不再受外部的加勒比海盗影响。  即使是在加勒比海盗5后面let声明,ES6明确规定,如果区块中存在加勒比海盗5let和const命令,这个区块对这些命令声明的加勒比海盗变量,  从一开始就形成了封闭作用域。凡是在加勒比海盗5声明之前就使用这些变量,就会报错。*/  /*可放开  var tmp = 123;  {  tmp = "abc";//ReferenceError: tmp is not defined  let tmp = 456;  }  */  /*可放开  function bar(x = y, y = 2) {//ReferenceError: y is not defined  return [x, y]  }  console.log(bar());  */ //-------不允许重复声明------// //-------为什么需要块级作用域?---------//  /*场景1,利用了var变量的加勒比海盗提升,导致内层的加勒比海盗tmp覆盖了外层的加勒比海盗tmp*/  /*可放开  var tmp = "hello";  function show() {  console.log(tmp);//undefined  if (tmp == "hello"){  var tmp = "world";  }  }  show();  */  /*场景2,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量*/  /*可放开  var s = 'hello';  for (var ii = 0; ii < s.length; ii++) {   }  console.log(ii); // 5  */  //------------ES6 的加勒比海盗块级作用域----------// /*1,外层代码块不受内层代码块的加勒比海盗影响  * 2,内层作用域可以定义外层作用域的加勒比海盗同名变量。  * 3,ES5 只有全局作用域和函数作用域  * 4,块级作用域的加勒比海盗出现,实际上使得获得广泛应用的加勒比海盗立即执行函数表达式(IIFE)不再必要了。*/  /*可放开  function show() {  let tmp = "123";  {  let tmp = 456;//如果改成var声明的加勒比海盗话,会提示声明冲突。var在加勒比海盗5函数里面声明就是函数级别的加勒比海盗变量  }  console.log(tmp);  }  show();  */ //-----块级作用域与函数声明------// /*1,ES6 引入了块级作用域,明确允许在加勒比海盗5块级作用域之中声明函数  * 2,ES6 规定,块级作用域之中,函数声明语句的加勒比海盗行为类似于let,在加勒比海盗5块级作用域之外不可引用。*/   /*可放开 function fa() {   console.log('I am outside!'); } (function () {   if (false) {//因为false,声明了函数,没定义     // 重复声明一次函数f     function fa() {       console.log('I am inside!');     }   }   fa();//TypeError: fa is not a function })();*/  /*ES6在加勒比海盗5附录B里面规定,浏览器的加勒比海盗实现可以不遵守上面的加勒比海盗规定,有自己的加勒比海盗行为方式。   1,允许在加勒比海盗5块级作用域内声明函数。   2,函数声明类似于var,即会提升到全局作用域或函数作用域的加勒比海盗头部。   3,同时,函数声明还会提升到所在加勒比海盗5加勒比海盗块级作用域的加勒比海盗头部。   上面里层的加勒比海盗fa明显提升了了作用域,看来node环境就是浏览器的加勒比海盗环境   */  /*function fa1() {   console.log('I am outside!'); } (function () {   if (false) {     // 重复声明一次函数f     let fa1 = function () {       console.log('I am inside!');     }   }   fa1();//I am outside! })(); */  //------const----------// /*1,const的加勒比海盗作用域与let命令相同:只在加勒比海盗5声明所在加勒比海盗5加勒比海盗块级作用域内有效。 * 2,const命令声明的加勒比海盗常量也是不提升,同样存在加勒比海盗5暂时性死区,只能在加勒比海盗5声明的加勒比海盗位置后面使用。 * 3,const实际上保证的加勒比海盗,并不是变量的加勒比海盗值不得改动,而是变量指向的加勒比海盗那个内存地址不得改动。*/ const foo = {}; foo.prop = 123; console.log(foo.prop);//成功 // 不可变的加勒比海盗只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的加勒比海盗,所以依然可以为其添加新属性。 // 如果真的加勒比海盗想将对象冻结,应该使用Object.freeze方法。 const foo2 = Object.freeze({}); foo2.prop = 123; console.log(foo2.prop);//undefined  /*ES6 声明变量的加勒比海盗六种方法   ES5 只有两种声明变量的加勒比海盗方法:var命令和function命令。   ES6除了添加let和const命令,后面章节还会提到,   另外两种声明变量的加勒比海盗方法:import命令和class命令。   所以,ES6 一共有6种声明变量的加勒比海盗方法。*/  //-------顶层对象的加勒比海盗属性--------// /*1,顶层对象,在加勒比海盗5浏览器环境指的加勒比海盗是window对象,在加勒比海盗5Node指的加勒比海盗是global对象。   2,ES5之中,顶层对象的加勒比海盗属性与全局变量是等价的加勒比海盗。   ES6一方面规定,为了保持兼容性,var命令和function命令声明的加勒比海盗全局变量,依旧是顶层对象的加勒比海盗属性;  另一方面规定,let命令、const命令、class命令声明的加勒比海盗全局变量,不属于顶层对象的加勒比海盗属性。  也就是说,从ES6开始,全局变量将逐步与顶层对象的加勒比海盗属性脱钩。*/ 

http://blog.csdn.net/liyanq528/article/details/72874671加勒比海盗5