JavaScript面試題(二)

31、http 的理解 ?

HTTP 協議是超文本傳輸協議,是客戶端瀏覽器或其他程序“請求”與 Web 服務器響應之間的應用層通信協議。HTTPS主要是由HTTP+SSL構建的可進行加密傳輸、身份認證的一種安全通信通道。

32、http 和 https 的區別 ?

  • 1、https協議需要到ca申請證書,一般免費證書較少,因而需要一定費用。

  • 2、http是超文本傳輸協議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協議。

  • 3、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。

  • 4、http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

33、git 的常用指令有哪些 ?

git?branch 分支查看git?branch branch_1 增加分支git?checkout branch 分支切換git?merge branch_1 合并分支(合并前要切換當前分支至master)git?branch?-d?branch_1 刪除分支git?remote 查看當前倉庫管理的遠程倉庫信息git?remote show origin 查看指定的遠程倉庫的詳細信息git?push?--set-upstream?origin branch_1 第一次將本地分支推到遠程倉庫git?push <遠程主機名> <本地分支名>:<遠程分支名> 將本地分支推到遠程分支git?pull <遠程主機名> <遠程分支>:<本地分支> 將遠程分支拉到本地分支git?branch?-d?branch_0 刪除本地合并后分支git?brench?-D?branch_0 刪除本地未合并分支it push origin?--delete?branch_0 刪除遠程分支git?restore [filename] 進行清除工作區的改變git?tag 查看標簽git?tag v1.0.0 打標簽git?push origin v1.0.0 將tag同步到遠程服務器

34、平時是使用 git 指令還是圖形化工具 ?

repository:git庫相關操作,基本意思就是字面意思。

  • 1)資源管理器中瀏覽該Git庫工作空間文件,省去查找路徑不斷點擊鼠標的操作。

  • 2)啟動Git bash工具(命令行工具)。

  • 3)查看當前分支文件狀態,不包括未提交的信息。

  • 4)查看某個分支的文件(彈出框中可選擇需要查看的版本、分支或標簽),跟上一條差不多,用的比較少,可能是沒有這方面的額需求。

  • 5)可視化當前分支歷史、可視化所有分支歷史:彈出分支操作歷史,也就是gitk工具,放到gitk工具中介紹。

  • edit:用于操作commit時操作信息輸入,只能操作文字輸入部分,你沒有看錯。常用的快捷鍵大家都知道,何必要單獨做成基本沒啥用的。本來以為對變更的文件進行批量操作、本來以為可以對未版本跟蹤的文件批量刪除、本來、、、,都說了是本來。

  • Branch:新建分支(需要選擇其實版本,可以根據版本號、其他分支或標簽來選擇)、檢出分支(覺得切換分支更合適)、重命名分支、刪除分支、當前分支Reset操作(會丟棄所有未提交的變更,包括工作區和索引區,當然了,有彈出框提示危險操作)。

35、Promsie.all() 使用過嗎, 它是怎么使用的 ?

? promise.all()用于一個異步操作需要在幾個異步操作完成后再進行時使用。promise.all()接受一個promise對象組成的數組參數,返回promise對象。當數組中所有promise都完成了,就執行當前promise對象的then方法,如果數組中有一個promise執行失敗了,就執行當前promise對象的catch方法。

36、什么是三次握手和四次揮手 ?

? 三次握手是網絡客戶端跟網絡服務器之間建立連接,并進行通信的過程。相當于客戶端和服務器之間你來我往的3個步驟。

  • 第一次握手是建立連接,客戶端發送連接請求報文,并傳送規定的數據包;

  • 第二次握手是服務器端表示接收到連接請求報文,并回傳規定的數據包;

  • 第三次握手是客戶端接收到服務器回傳的數據包后,給服務器端再次發送數據包。這樣就完成了客戶端跟服務器的連接和數據傳送。

? 四次揮手表示當前這次連接請求已經結束,要斷開這次連接。

  • 第一次揮手是客戶端對服務器發起斷開請求,

  • 第二次揮手是服務器表示收到這次斷開請求,

  • 第三次揮手是服務器表示已經斷開連接

  • 第四次揮手是客戶端斷開連接。

37、for in 和 for of 循環的區別 ?

??`for in`?用于遍歷對象的鍵(`key`),`for in`會遍歷所有自身的和原型鏈上的可枚舉屬性。如果是數組,for?in會將數組的索引(index)當做對象的key來遍歷,其他的object也是一樣的。
??`for of`是`es6`引入的語法,用于遍歷 所有迭代器iterator,其中包括`HTMLCollection`,`NodeList`,`Array`,`Map`,`Set`,`String`,`TypedArray`,`arguments`等對象的值(`item`)。

38、async/await 怎么拋出錯誤異常 ?

如果可能出錯的代碼比較少的時候可以使用try/catch結構來了處理,如果可能出錯的代碼比較多的時候,可以利用async函數返回一個promise對象的原理來處理,給async修飾的函數調用后返回的promise對象,調用catch方法來處理異常。

39、 函數式編程和命令式編程的區別 ?

  • 命令式編程(過程式編程) :

? 專注于”如何去做”,這樣不管”做什么”,都會按照你的命令去做。解決某一問題的具體算法實現。
  • 函數式編程:把運算過程盡量寫成一系列嵌套的函數調用。

? ? 函數式編程強調沒有”副作用”,意味著函數要保持獨立,所有功能就是返回一個新的值,沒有其他行為,尤其是不得修改外部變量的值。所謂”副作用”,指的是函數內部與外部交互(最典型的情況,就是修改全局變量的值),產生運算以外的其他結果。

40、http 常見的響應狀態碼 ?

??100——客戶必須繼續發出請求101——客戶要求服務器根據請求轉換HTTP協議版本200——交易成功201——提示知道新文件的URL202——接受和處理、但處理未完成203——返回信息不確定或不完整204——請求收到,但返回信息為空205——服務器完成了請求,用戶代理必須復位當前已經瀏覽過的文件206——服務器已經完成了部分用戶的GET請求300——請求的資源可在多處得到301——刪除請求數據302——在其他地址發現了請求數據303——建議客戶訪問其他URL或訪問方式304——客戶端已經執行了GET,但文件未變化305——請求的資源必須從服務器指定的地址得到306——前一版本HTTP中使用的代碼,現行版本中不再使用307——申明請求的資源臨時性刪除400——錯誤請求,如語法錯誤401——請求授權失敗402——保留有效ChargeTo頭響應403——請求不允許404——沒有發現文件、查詢或URl405——用戶在Request-Line字段定義的方法不允許406——根據用戶發送的Accept拖,請求資源不可訪問407——類似401,用戶必須首先在代理服務器上得到授權408——客戶端沒有在用戶指定的餓時間內完成請求409——對當前資源狀態,請求不能完成410——服務器上不再有此資源且無進一步的參考地址411——服務器拒絕用戶定義的Content-Length屬性請求412——一個或多個請求頭字段在當前請求中錯誤413——請求的資源大于服務器允許的大小414——請求的資源URL長于服務器允許的長度415——請求資源不支持請求項目格式416——請求中包含Range請求頭字段,在當前請求資源范圍內沒有range指示值,請求也不包含If-Range請求頭字段417——服務器不滿足請求Expect頭字段指定的期望值,如果是代理服務器,可能是下一級服務器不能滿足請求500——服務器產生內部錯誤501——服務器不支持請求的函數502——服務器暫時不可用,有時是為了防止發生系統過載503——服務器過載或暫停維修504——關口過載,服務器使用另一個關口或服務來響應用戶,等待時間設定值較長505——服務器不支持或拒絕支請求頭中指定的HTTP版本

41、 什么是事件流以及事件流的傳播機制 ?

? 事件觸發后,從開始找目標元素,然后執行目標元素的事件,再到離開目標元素的整個過程稱之為事件流。

? W3C標準瀏覽器事件流的傳播分為3個階段:捕獲階段、目標階段、冒泡階段

  • 捕獲階段指找目標元素的過程,這個找的過程,是從最大的document對象到html,再到body,。。。直到目標元素。

  • 找到目標元素后,調用執行他綁定事件時對應的處理函數,這個過程被稱之為目標階段。

  • 當目標元素的事件執行結束后,再從目標元素,到他的父元素。。。body、html再到document的過程,是冒泡階段。

42、模塊化語法 ? commonJS AMD CMD ES6 Module

  • commonJS是nodejs自帶的一種模塊化語法,將一個文件看做是一個模塊,可以將文件中導出的時候,被另一個文件導入使用。導出使用:module.exports導出。導入使用:require函數導入。

  • AMD是社區開發的模塊化語法,需要依賴require.js實現,分為定義模塊,導出數據和導入模塊,使用數據。AMD語法的導入是依賴前置的,也就是說,需要用到的文件需要在第一次打開頁面全部加載完成,造成的后果就是首屏加載很慢,后續操作會很流暢。

  • CMD是玉伯開發的模塊化語法,需要依賴sea.js實現,也分為模塊定義導出,和模塊導入使用數據。CMD語法可以依賴前置,也可以按需導入,緩解了AMD語法的依賴前置。

  • ES6的模塊化語法,類似于commonJS的語法,分為數據導出和數據導入,導入導出更加靈活。

43、 什么是懶加載和預加載 ?

  • 懶加載:懶加載也叫延遲加載,延遲加載網絡資源或符合某些條件時才加載資源。常見的就是圖片延時加載。懶加載的意義:懶加載的主要目的是作為服務器前端的優化,減少請求數或延遲請求數。懶惰實現方式:

    • 1.第一種是純粹的延遲加載,使用setTimeOut或setInterval進行加載延遲.

    • 2.第二種是條件加載,符合某些條件,或觸發了某些事件才開始異步下載。

    • 3.第三種是可視區加載,即僅加載用戶可以看到的區域,這個主要由監控滾動條來實現,一般會在距用戶看到某圖片前一定距離便開始加載,這樣能保證用戶拉下時正好能看到圖片。

  • 預加載:提前加載圖片,當用戶需要查看時可直接從本地緩存中渲染。

? 兩者的行為是相反的,一個是提前加載,一個是遲緩甚至不加載。懶加載對服務器前端有一定的緩解壓力作用,預加載則會增加服務器前端壓力。預加載應用如廣告彈窗等。

44、token 一般存放在哪里 ? 為什么不存放在 cookie 內 ?

token一般放在本地存儲中。token的存在本身只關心請求的安全性,而不關心token本身的安全,因為token是服務器端生成的,可以理解為一種加密技術。但如果存在cookie內的話,瀏覽器的請求默認會自動在請求頭中攜帶cookie,所以容易受到csrf攻擊。

45、 less 和 sass 的區別 ?

  • 編譯環境不一樣,sass是服務器端處理的,可以用Ruby、node-sass來編譯;less需要引入less.js來處理輸出,也可以使用工具在服務器端處理成css,也有在線編譯的。

  • 變量定義符不一樣,less用的是@,而sass用$。

  • sass支持分支語句,less不支持

44、瀏覽器的同源策略機制 ?

同源策略,又稱SOP,全稱Same Origin Policy,是瀏覽器最基本的安全功能。站在瀏覽器的較短看網頁,如果網絡上的接口可以不受限制、無需授權隨意被人調用,那將是一個非常嚴重的混亂場景。瀏覽器為了安全有序,內部實現了同源策略。同源策略,指的是瀏覽器限制當前網頁只能訪問同源的接口資源。所謂同源,指當前頁面和請求的接口,兩方必須是同協議、且同域名、且同端口。只要有一個不相同,則會受到瀏覽器約束,不允許請求。但當一個項目變的很大的時候,將所有內容放在一個網站或一個服務器中會讓網站變的臃腫且性能低下,所以,在一些場景中,我們需要跨過同源策略,請求到不同源的接口資源,這種場景叫跨域。跨域大致有3種方案:
  • jsonp

    這種方式是利用瀏覽器不限制某些標簽發送跨域請求,例如link、img、iframe、script。通常請求請求回來的資源要在js中進行處理,所以jsonp跨域是利用script標簽進行發送,且這種請求方式只能是get請求。

  • cors

    這種方式是讓接口資源方面進行授權,授權允許訪問。在接口資源處添加響應頭即可通過瀏覽器的同源策略,響應頭具體的鍵值對如下:

    {Access-Control-Allow-Origin:?'*'}

  • proxy

    這種方式屬于找外援的一種方式,瀏覽器只能限制當前正在打開的web頁面發送請求,但無法限制服務器端請求接口資源。所以我們可以將請求發送到自己服務器,然后自己服務器去請求目標接口資源,最后自己服務器將接口資源返回給當前頁面,類似于找外援代替自己請求目標接口資源。

    這種方式通常要對服務器進行代理配置,需要對apache服務器、nginx服務器、nodejs服務器進行配置。

45、 瀏覽器的緩存有哪些 ? 什么時候使用強制緩存 ? 什么時候使用協商緩存 ?

當我們訪問同一個頁面時,請求資源、數據都是需要一定的耗時,如果可以將一些資源緩存下來,那么從第二次訪問開始,就可以減少加載時間,提高用戶體驗,也能減輕服務器的壓力。瀏覽器緩存分為強緩存和協商緩存,當存在緩存時,客戶端第一次向服務器請求數據時,客戶端會緩存到內存或者硬盤當中,當第二次獲取相同的資源,強緩存和協商緩存的應對方式有所不同。強緩存:當客戶端第二次向服務器請求相同的資源時,不會向服務器發送請求,而是直接從內存/硬盤中間讀取。緩存由服務器的響應頭里 cache-control 和 expires 兩個字段決定協商緩存:當客戶端第二次向服務器請求相同的資源時,先向服務器發送請求"詢問"該請求的文件緩存在ben'd與服務器相比是否更改,如果更改,則更新文件,如果沒有就從內存/硬盤中讀取。協商緩存由 last-modified 和 etag兩個字段決定

46、 數組方法 forEach 和 map 的區別 ?

forEach和map都是循環遍歷數組中的每一項。forEach() 和 map() 里面每一次執行匿名函數都支持3個參數:數組中的當前項item,當前項的索引index,原始數組input。匿名函數中的this都是指Window。只能遍歷數組。他們的區別是:forEach沒有返回值,但map中要有返回值,返回處理后的所有新元素組成的數組。

47、 什么是函數作用域 ? 什么是作用域鏈 ?

作用域就是在代碼執行過程中,形成一個獨立的空間,讓空間內的變量不會泄露在空間外,也讓獨立空間內的變量函數在獨立空間內運行,而不會影響到外部的環境。作用域分為全局作用域和局部作用域,也就是本來有一個巨大的空間,空間內定義的函數內部,就形成了一個獨立的小空間,全局作用域是最大的作用域。但是當獨立空間內的數據不能滿足需求時,是可以從外部獲取數據的,也就是說這樣的獨立空間之間是可以有層級關系的,外部的空間不可以從內部的空間獲取數據,但內部的空間可以。當子級空間在父級空間中獲取數據的時,父級空間沒有的話,父級空間也會到他的父級空間中查找數據,這樣形成的鏈式結構叫作用域鏈。當將一個變量當做值使用時,會先在當前作用域中查找這個變量的定義和數據,如果沒有定義的話,就會去父級作用域中查找,如果父級作用域中有的話就使用這個值,如果父級作用域中也沒有的話,就通過父級作用域查找他的父級作用域,直到找到最大的作用域-全局,如果全局也沒有就報錯。當將一個變量當做數據容器存儲,也就是給變量賦值的時候,也要先在自己作用域中查找變量的定義,如果沒有就在上一級作用域中查找,直到全局,如果全局作用域中也沒有這個變量的定義,就在全局定義這個變量并賦值。

48、 ES6 中 Set 和 Map 的原理 ?

Set 是無重復值的有序列表。根據 `Object.is()`方法來判斷其中的值不相等,以保證無重復。Set 會自動移除重復的值,因此你可以使用它來過濾數組中的重復值并返回結果。Set并不是數組的子類型,所以你無法隨機訪問其中的值。但你可以使用`has()` 方法來判斷某個值是否存在于 Set 中,或通過 `size` 屬性來查看其中有多少個值。Set 類型還擁有`forEach()`方法,用于處理每個值Map 是有序的鍵值對,其中的鍵允許是任何類型。與 Set 相似,通過調用 `Object.is()`方法來判斷重復的鍵,這意味著能將數值 5 與字符串 "5" 作為兩個相對獨立的鍵。使用`set()` 方法能將任何類型的值關聯到某個鍵上,并且該值此后能用 `get()` 方法提取出來。Map 也擁有一個 `size` 屬性與一個 `forEach()` 方法,讓項目訪問更容易。

49、 0.1 + 0.2 為什么不等于 0.3, 在項目中遇到要怎么處理 ?

計算機內部存儲數據使用2進制存儲,兩個數字進行的數學運算,首先是將這兩個數字以2進制形式,存儲在計算機內部,然后在計算機內部使用兩個2進制數字進行計算,最后將計算結果的2進制數字轉為10進制展示出來。由于10進制的小數在轉2進制的時候,規則是小數部分乘以2,判斷是否得到一個整數,如果得到整數,轉換完成;如果沒有得到整數,則繼續乘以2判斷。所以,0.1和0.2在轉換2進制的時候,其實是一個無限死循環,也就是一直乘以2沒有得到整數的時候,但計算機內部對于無限死循環的數據,會根據一個標準保留52位。也就是說,計算機內部在存儲0.1和0.2的時候,本來就不精準,兩個不精準的小數在計算后,距離精準的結果是有一定誤差的。項目中碰到這種情況,有3種處理方法:
  • 將小數乘以10的倍數,轉為整數,然后計算,計算完成后,再縮小10的倍數,例如:

  var result = ((0.1 * 10) + (0.2 * 10)) / 10      // result === 0.3
  • 使用數字的toFixed方法,強制保留小數點后多少位,例

   var result = (0.1 + 0.2).toFixed(2)      // result === 0.30
  • 自定義數字運算方法,當需要進行數學運算的時候,不直接進行,調用自定義的方法進行,例:(加法封裝)

 function add(...args){          var num = args.find(item => {              if(item != 0 && !item){                 throw new Error("數學運算要使用數字")              }          })          var arr = args.map(item => {              var index = (item+'').indexOf('.')              if(index >= 0){                  return (item+'').split('.')[1].length              }          })          arr = arr.filter(item => item)          if(arr.length){              var max = Math.max(...arr)              var data = args.map(item => item * Math.pow(10, max))              var data.reduce((a, b) => a + b) / Math.pow(10, max)          }else{              var data = args              return data.reduce((a, b) => a + b)          }      }      // 調用使用:      var num1 = add(0.1, 0.2)      console.log(num1); // 0.3            var num2 = add(1, 2)      console.log(num2); // 3            var num3 = add(1, 2.1)      console.log(num3); // 3.1

50、 什么是模塊化思想 ?

就是JS中將不同功能的代碼封裝在不同的文件中, 互相引用時不會發生命名沖突的一種思想, 大多數情況下, 一個文件就是一個模塊模塊化的實現,有多種方案:
  • CommonJS:

    CommonJSnodejs中使用的模塊化規范在?nodejs?應用中每個文件就是一個模塊,擁有自己的作用域,文件中的變量、函數都是私有的,與其他文件相隔離。模塊導出:module.exports=數據,模塊導入:require('模塊文件路徑')

  • ES6的模塊化:

    模塊功能主要由兩個命令構成:exportimportexport命令用于規定模塊的對外接口,import命令用于輸入其他模塊提供的功能。

    一個模塊就是一個獨立的文件。該文件內部的所有變量,外部無法獲取。如果你希望外部能夠讀取模塊內部的某個變量,就必須使用export關鍵字輸出該變量。下面是一個 JS 文件,里面使用export命令輸出變量。

  • AMD (Asynchronous Module Definition):

    特點: 提倡依賴前置,在定義模塊的時候就要聲明其依賴的模塊:導入模塊require([module],callback);定義模塊:define('模塊名稱', 函數)

  • CMD (Common Module Definition):

    CMD規范是國內SeaJS的推廣過程中產生的。提倡就近依賴(按需加載),在用到某個模塊的時候再去require。定義模塊:define(function (require, exports, module) {}),使用模塊:seajs.use()

51、 說說怎么用js 寫無縫輪播圖

將所有需要輪播的內容動態復制一份,放在原本的容器中,加定時器讓整個容器中的內容滾動輪播,當內容輪播到left值為-原本的內容寬度時,快速將內容切換到left值為0的狀態。

52、 JS 如何實現多線程 ?

我們都知道JS是一種單線程語言,即使是一些異步的事件也是在JS的主線程上運行的(具體是怎么運行的,可以看我另一篇博客JS代碼運行機制)。像setTimeout、ajax的異步請求,或者是dom元素的一些事件,都是在JS主線程執行的,這些操作并沒有在瀏覽器中開辟新的線程去執行,而是當這些異步操作被操作時或者是被觸發時才進入事件隊列,然后在JS主線程中開始運行。首先說一下瀏覽器的線程,瀏覽器中主要的線程包括,UI渲染線程,JS主線程,GUI事件觸發線程,http請求線程。JS作為腳本語言,它的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復雜的同步問題。(這里這些問題我們不做研究)但是單線程的語言,有一個很致命的確定。如果說一個腳本語言在執行時,其中某一塊的功能在執行時耗費了大量的時間,那么就會造成阻塞。這樣的項目,用戶體驗是非常差的,所以這種現象在項目的開發過程中是不允許存在的。其實JS為我們提供了一個Worker的類,它的作用就是為了解決這種阻塞的現象。當我們使用這個類的時候,它就會向瀏覽器申請一個新的線程。這個線程就用來單獨執行一個js文件。
? var worker?=?new Worker(js文件路徑);
那么這個語句就會申請一個線程用來執行這個js文件。這樣也就實現了js的多線程。

53、 閉包的使用場景 ?

一個函數被當作值返回時,也就相當于返回了一個通道,這個通道可以訪問這個函數詞法作用域中的變量,即函數所需要的數據結構保存了下來,數據結構中的值在外層函數執行時創建,外層函數執行完畢時理因銷毀,但由于內部函數作為值返回出去,這些值得以保存下來。而且無法直接訪問,必須通過返回的函數。這也就是私有性。本來執行過程和詞法作用域是封閉的,這種返回的函數就好比是一個蟲洞,開了掛。閉包的形成很簡單,在執行過程完畢后,返回函數,或者將函數得以保留下來,即形成閉包。
  • 防抖:

   function debounce(fn, interval) {        let timer = null; // 定時器        return function() {            // 清除上一次的定時器            clearTimeout(timer);            // 拿到當前的函數作用域            let _this = this;            // 拿到當前函數的參數數組            let args = Array.prototype.slice.call(arguments, 0);            // 開啟倒計時定時器            timer = setTimeout(function() {                // 通過apply傳遞當前函數this,以及參數                fn.apply(_this, args);                // 默認300ms執行            }, interval || 300)        }    }
  • 節流:

  function throttle(fn, interval) {        let timer = null; // 定時器        let firstTime = true; // 判斷是否是第一次執行        // 利用閉包        return function() {            // 拿到函數的參數數組            let args = Array.prototype.slice.call(arguments, 0);            // 拿到當前的函數作用域            let _this = this;            // 如果是第一次執行的話,需要立即執行該函數            if(firstTime) {                // 通過apply,綁定當前函數的作用域以及傳遞參數                fn.apply(_this, args);                // 修改標識為null,釋放內存                firstTime = null;            }            // 如果當前有正在等待執行的函數則直接返回            if(timer) return;            // 開啟一個倒計時定時器            timer = setTimeout(function() {                // 通過apply,綁定當前函數的作用域以及傳遞參數                fn.apply(_this, args);                // 清除之前的定時器                timer = null;                // 默認300ms執行一次            }, interval || 300)        }    }
  • 迭代器:

 var arr =['aa','bb','cc'];    function incre(arr){        var i=0;        return function(){            //這個函數每次被執行都返回數組arr中 i下標對應的元素             return arr[i++] || '數組值已經遍歷完';        }    }    var next = incre(arr);    console.log(next());//aa    console.log(next());//bb    console.log(next());//cc    console.log(next());//數組值已經遍歷完
  • 緩存:

 var fn=(function(){            var cache={};//緩存對象            var calc=function(arr){//計算函數                var sum=0;                //求和                for(var i=0;i<arr.length;i++){                    sum+=arr[i];                }                return sum;            }                          return function(){                var args = Array.prototype.slice.call(arguments,0);//arguments轉換成數組                var key=args.join(",");//將args用逗號連接成字符串                var result , tSum = cache[key];                if(tSum){//如果緩存有                       console.log('從緩存中取:',cache)//打印方便查看                    result = tSum;                }else{                    //重新計算,并存入緩存同時賦值給result                    result = cache[key]=calc(args);                    console.log('存入緩存:',cache)//打印方便查看                }                return result;            }         })();        fn(1,2,3,4,5);        fn(1,2,3,4,5);        fn(1,2,3,4,5,6);        fn(1,2,3,4,5,8);        fn(1,2,3,4,5,6);
  • getter和setter:

  function fn(){            var name='hello'            setName=function(n){                name = n;            }            getName=function(){                return name;            }                          //將setName,getName作為對象的屬性返回            return {                setName:setName,                getName:getName            }        }        var fn1 = fn();//返回對象,屬性setName和getName是兩個函數        console.log(fn1.getName());//getter            fn1.setName('world');//setter修改閉包里面的name        console.log(fn1.getName());//getter
  • 柯里化:

  function curryingCheck(reg) {        return function(txt) {            return reg.test(txt)        }    }        var hasNumber = curryingCheck(/\d+/g)    var hasLetter = curryingCheck(/[a-z]+/g)        hasNumber('test1')      // true    hasNumber('testtest')   // false    hasLetter('21212')      // false
  • 循環中綁定事件或執行異步代碼

   var p1 = "ss";    var p2 = "jj";    function testSetTime(para1,para2){        return (function(){            console.log(para1 + "-" + para2);        })    }    var test = testSetTime(p1, p2);    setTimeout(test, 1000);    setTimeout(function(){        console.log(p1 + "-" + p2)    },1000)
  • 單例模式:

  var Singleton = (function () {        var instance;            function createInstance() {            return new Object("I am the instance");        }             return {            getInstance: function () {                if (!instance) {                    instance = createInstance();                }                return instance;            }        };    })();

54、 常見的兼容問題有哪些 ?

  • 獲取標簽節點:

    document.getElementsByClassName('類名')在低版本ie中不兼容。解決方法是使用其他方式獲取:

   document.getElementById('id名')      document.getElementsByTagName('標簽名')      document.getElementsByName('name屬性值')      document.querySelector('css選擇器')      document.querySelectorAll('css選擇器')

獲取卷去的高度

      // 當有文檔聲明的時候      document.documentElement.scrollTop      document.documentElement.srollLeft      // 沒有文檔聲明的時候      document.body.scrollTop      document.body.scrollLeft

?解決辦法使用兼容寫法:

???????

      // 獲取      var t = document.documentElement.scrollTop || document.body.scrollTop      var l = document.documentElement.srollLeft || document.body.scrollLeft      // 設置      document.documentElement.scrollTop = document.body.scrollTop = 數值      document.documentElement.srollLeft = document.body.scrollLeft = 數值
  • 獲取樣式

   // W3C標準瀏覽器      window.getComputedStyle(元素)      // 低版本IE中      元素.currentStyle
  • 使用函數封裝的方式兼容:

  function getStyle(ele,attr){          if(window.getComputedStyle){             return getComputedStyle(ele)[attr]          }else{              return ele.currentStyle[attr]          }      }
  • 事件偵聽器

    // W3C瀏覽器      ele.addEventListener(事件類型,函數)      // 低版本Ie      ele.attachEvent('on事件類型',函數)
  • 使用函數封裝的方式解決:

    function bindEvent(ele,type,handler){          if(ele.addEventListener){              ele.addEventListener(type,handler)          }else if(ele.attachEvent){              ele.attachEvent('on'+type,handler)          }else{              ele['on'+type] = handler          }      }
  • 事件解綁

    // W3C瀏覽器      ele.removeEventListener(事件類型,函數)      // 低版本Ie      ele.detachEvent('on事件類型',函數)
  • 使用函數封裝的方式解決:

  function unBind(ele,type,handler){          if(ele.removeEventListener){              ele.removeEventListener(type,handler)          }else if(ele.detachEvent){              ele.detachEvent('on'+type,handler)          }else{              ele['on'+type] = null          }      }
  • 事件對象的獲取

   // W3C瀏覽器      元素.on事件類型 = function(e){}      元素.addEventListener(事件類型,fn)      function fn(e){                }      // 在低版本IE中      元素.on事件類型 = function(){ window.event }      元素.addEventListener(事件類型,fn)      function fn(){          window.event      }
  • 使用短路運算符解決:

  元素.on事件類型 = function(e){          var e = e || window.event      }      元素.addEventListener(事件類型,fn)      function fn(e){          var e = e || window.event      }
  • 阻止默認行為

   // W3C瀏覽器      元素.on事件類型 = function(e){          e.preventDefault()      }      // 在低版本IE中      元素.on事件類型 = function(){ window.event.returnValue = false }
  • 通過封裝函數解決

  元素.on事件類型 = function(e){          var e = e || window.event          e.preventDefault?e.preventDefault():e.returnValue=false      }
  • 阻止事件冒泡

  // W3C瀏覽器      元素.on事件類型 = function(e){          e.stopPropagation()      }      // 在低版本IE中      元素.on事件類型 = function(){ window.event.cancelBubble = true }
  • 通過函數封裝解決:

     元素.on事件類型 = function(e){          var e = e || window.event          e.stopPropagation?e.stopPropagation():e.cancelBubble=true      }
  • 獲取精準的目標元素

  // W3C瀏覽器      元素.on事件類型 = function(e){          e.target      }      // 在低版本IE中      元素.on事件類型 = function(){ window.event.srcElement }
  • 通過短路運算符解決:

  元素.on事件類型 = function(e){          var e = e || window.event          var target = e.target || e.srcElement;      }
  • 獲取鍵盤碼

 // W3C瀏覽器      元素.on事件類型 = function(e){          e.keyCode      }      // 在低版本火狐中      元素.on事件類型 = function(e){        e.which      }
  • 通過短路運算符解決:

      元素.on事件類型 = function(e){          var e = e || window.event          var keycode = e.keyCode || e.which;      }

55、 在 JS 中如何阻止事件冒泡 ?

使用事件對象阻止事件冒泡,以前的w3c瀏覽器中,使用事件對象的方法阻止:

? 事件對象.stopPropagation()

在ie低版本瀏覽器中,使用事件對象的屬性阻止:

? 事件對象.cancelBubble?=?true

現在的w3c瀏覽器也支持ie低版本瀏覽器中的寫法,所以以前在阻止事件冒泡的時候,需要考慮兼容寫法,現在就不需要了,直接用ie低版本瀏覽器中的寫法即可。

56、兩個數組 var A = [1, 5, 6]; var B = [2, 6, 7],實現一個方法,找出僅存在于A 或者 僅 存在于B中的所有數字。

???????

  function getDiff(arr, brr){      // 僅存在于arr中的內容        var onlyArr = arr.filter(item => !brr.some(v => item === v))        // 僅存在于brr中的內容        var onlyBrr = brr.filter(v => !arr.some(item => v === item))        // 需要哪個就返回哪個,或者一起返回        return {            "僅存在于arr中的內容": onlyArr,            "僅存在于brr中的內容": onlyBrr        }    }

57、 你了解構造函數嗎 ? class 是什么 ? 兩者有什么區別 ?

在es5中構造函數其實就是在定義一個類,可以實例化對象,es6中class其實是構造函數的語法糖。但還是有點區別的:
  • 在class內部和class的方法內部,默認使用嚴格模式

  • class類不存在預解析,也就是不能先調用class生成實例,再定義class類,但是構造函數可以。

  • class中定義的方法默認不能被枚舉,也就是不能被遍歷。

  • class必須使用new執行,但是構造函數沒有new也可以執行。

  • class中的所有方法都沒有原型,也就不能被new

  • class中繼承可以繼承靜態方法,但是構造函數的繼承不能。

58、是否存在a的值(a==0 && a==1)為true 的情況 ?

???????

 var value = -1    Object.defineProperty(window,'a',{        get(){            return value+=1;        }    })    if(a===0&&a===1){ // true        console.log('success')    }

59、for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, 1000); } 要求:輸出0,1,2,3,4

首先這個面試題考察的是對于js中異步代碼以及作用域的理解:js中常見的異步代碼包括定時器和ajax。js執行代碼的流程是碰到同步代碼就執行,碰到異步就交給瀏覽器的webAPI處理,當webAPI中的異步該執行時,webAPI會將需要執行的回調函數放在任務隊列中,等候執行,所以,js中所有的異步代碼總會在所有同步代碼執行結束后,再執行任務隊列中的代碼。在這個問題中,循環是同步代碼,定時器是異步代碼,所以整個循環都執行結束以后才會執行定時器代碼。for循環中使用var定義的變量是全局變量,定時器回調函數中輸出變量的時候,根據作用域規則,先在當前作用域中變量i的定義表達式,如果沒有找到,就去上一級作用域中找,此時,在局部作用域中沒有找到,去上級作用域中,也就是全局找到了,全局中的i,因為循環已經執行結束了,所以i的值是5。最終,會輸出5個5。其次考察的是對于類似問題的解決方式,間接性判斷你是否有過類似情況的開發:這個問題的解決思路就是讓回調函數中輸出i的時候,不要去全局中找i,因為全局的i在循環執行結束后已經變成5了,根據這個思路,有2種解決辦法:
  • 在異步代碼外面嵌套一層函數作用域

       for(var i = 0;i < 5; i++){           (function(i) {               setTimeout(function() {                   console.log(i)               }, 1000)           })(i)       }

原理是自調用函數會產生作用域,循環5次就會產生5個作用域,每個作用域代碼在執行的時候都有形參i傳遞。所以每個作用域中的i都是不同的,分別是:0 1 2 3 4。當作用域中的異步代碼執行的時候,自己作用域中沒有i變量的定義,然后上級作用域就是自調用函數的作用域,找到了單獨的i。最終可以輸出:0 1 2 3 4

  1. 將循環代碼中的var換成es6的let

  for(let i = 0;i < 5; i++){           setTimeout(function() {               console.log(i)           }, 1000)       }

es6的let自帶塊級作用域,原理跟第一種解決思路是一樣的,轉成es5后,代碼是一樣的。

60、實現一個 add 方法 使計算結果能夠滿足如下預期:?- add(1)(2)(3)() = 6 - add(1,2,3)(4)() = 10

??????????????

    function add (...args) {        if(args.length === 3){            return -(args[0] * args[1] * 2 + args[2] * 2)        }else{            return -args[args.length-1]        }            }         function currying (fn) {      let args = []      return function _c (...newArgs) {        if (newArgs.length) {          args = [            ...args,            ...newArgs          ]          return _c        } else {          return fn.apply(this, args)        }      }    }    let addCurry = currying(add)        var a = addCurry(1)(2)(3)()    console.log(-a); // 10        var b = addCurry(1,2,3)(4)()    console.log(6 - b); // 10

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/39562.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/39562.shtml
英文地址,請注明出處:http://en.pswp.cn/news/39562.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于DEM tif影像的插值平滑和tif紋理貼圖構建方法

文章目錄 基于CDT的無縫融合基于拓撲糾正的地上-地表的Bool運算融合 基于CDT的無縫融合 準備數據是一個10米分辨率的Tif影像&#xff0c;直接用于生成DEM會十分的不平滑。如下圖所示&#xff0c;平滑前后的對比效果圖差異&#xff1a; 基于ArcGIS的DEM平滑插值 等值線生成&…

Oracle增加列

在Oracle數據庫中&#xff0c;使用ALTER TABLE語句可以很方便地為表增加新列。在進行操作時&#xff0c;需要謹慎考慮新列的數據類型、名稱、默認值、約束等因素&#xff0c;以確保操作的安全性和可靠性。同時&#xff0c;也需要注意備份數據、避免在高峰期進行操作等注意事項 …

GPT內功心法:搜索思維到GPT思維的轉換

大家好,我是herosunly。985院校碩士畢業,現擔任算法研究員一職,熱衷于機器學習算法研究與應用。曾獲得阿里云天池比賽第一名,CCF比賽第二名,科大訊飛比賽第三名。擁有多項發明專利。對機器學習和深度學習擁有自己獨到的見解。曾經輔導過若干個非計算機專業的學生進入到算法…

Linux6.38 Kubernetes 集群存儲

文章目錄 計算機系統5G云計算第三章 LINUX Kubernetes 集群存儲一、emptyDir存儲卷2.hostPath存儲卷3.nfs共享存儲卷4.PVC 和 PV 計算機系統 5G云計算 第三章 LINUX Kubernetes 集群存儲 容器磁盤上的文件的生命周期是短暫的&#xff0c;這就使得在容器中運行重要應用時會出…

編寫 loading、加密解密 發布NPM依賴包,并實施落地使用

你的 Loading 開箱即可用的 loading&#xff0c; 說明&#xff1a;vue3-loading 是一個方便在 Vue 3 項目中使用的加載指示器組件的 npm 插件。它允許您輕松地在項目中添加加載動畫&#xff0c;提升用戶體驗。 目錄 你的 Loading&#x1f30d; 安裝&#x1f6f9; 演示地址&…

C# WPF 無焦點自動獲取USB 二維碼掃碼槍內容,包含中文

C# WPF 無焦點自動獲取USB 二維碼掃碼槍內容&#xff0c;包含中文 前言項目背景 需要預知的知識實現方案第一步 安裝鍵盤鉤子第二步 獲取輸入的值第3 步 解決中文亂碼問題分析解決思路工具函數 結束 前言 USB接口的掃碼槍基本就相當于一個電腦外設&#xff0c;等同于一個快速輸…

Oracle Data Redaction與Data Pump

如果表定義了Redaction Policy&#xff0c;導出時數據會脫敏嗎&#xff1f;本文解答這個問題。 按照Oracle文檔Advanced Security Guide第13章&#xff0c;13.6.5的Tutorial&#xff0c;假設表HR.jobs定義了Redaction Policy。 假設HR用戶被授予了訪問目錄對象的權限&#xf…

Unity引擎使用InteriorCubeMap采樣制作假室內效果

Unity引擎制作假室內效果 大家好&#xff0c;我是阿趙。 ??這次來介紹一種使用CubeMap做假室內效果的方式。這種技術名叫InteriorCubeMap&#xff0c;是UE引擎自帶的節點效果。我這里是在Unity引擎里面的實現。 一、效果展示 這個假室內效果&#xff0c;要動態看才能看出效…

柏睿向量數據庫Rapids VectorDB賦能企業級大模型構建及智能應用

ChatGPT的問世,在為沉寂已久的人工智能重新注入活力的同時,也把長期默默無聞的向量數據庫推上舞臺。今年4月以來,全球已有4家知名向量數據庫公司先后獲得融資,更加印證了向量數據庫在AI大模型時代的價值。 什么是向量數據庫? 在認識向量數據庫前,先來了解一下最常見的關…

【業務功能篇62】Spring boot maven多模塊打包時子模塊報錯問題

程序包 com.xxx.common.utils不存在或者xxx找不到符號 我們項目中一般都是會分成多個module模塊&#xff0c;做到解耦&#xff0c;方便后續做微服務拆分模塊&#xff0c;可以直接就每個模塊進行打包拎出來執行部署這樣就會有模塊之間的調用&#xff0c;比如API模塊會被Service…

【SpringBoot】SpringBoot獲取不到用戶真實IP怎么辦

文章目錄 前言問題原因解決方案修改Nginx配置文件SpringBoot代碼實現 前言 項目部署后發現服務端無法獲取到客戶端真實的IP地址&#xff0c;這是怎么回事呢&#xff1f;給我都整懵逼了&#xff0c;經過短暫的思考&#xff0c;我發現了問題的真兇&#xff0c;那就是我們使用了N…

Vue基礎

Vue基礎 Vue應用 <!DOCTYPE html> <html> <head><meta charset"utf-8"><title></title><!-- 開發環境版本 --><script src"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head&g…

vue所有UI庫通用)tree-select 下拉多選(設置 maxTagPlaceholder 隱藏 tag 時顯示的內容,支持鼠標懸浮展示更多

如果可以實現記得點贊分享&#xff0c;謝謝老鐵&#xff5e; 1.需求描述 引用的下拉樹形結構支持多選&#xff0c;限制選中tag的個數&#xff0c;且超過制定個數&#xff0c;鼠標懸浮展示更多已選中。 2.先看下效果圖 3.實現思路 首先根據API文檔&#xff0c;先設置maxTagC…

【Docker】Docker network之bridge、host、none、container以及自定義網絡的詳細講解

&#x1f680;歡迎來到本文&#x1f680; &#x1f349;個人簡介&#xff1a;陳童學哦&#xff0c;目前學習C/C、算法、Python、Java等方向&#xff0c;一個正在慢慢前行的普通人。 &#x1f3c0;系列專欄&#xff1a;陳童學的日記 &#x1f4a1;其他專欄&#xff1a;CSTL&…

TCP/IP網絡江湖初探:物理層的奧秘與傳承(物理層上篇-基礎與本質)

〇、引言 在這個數字時代,計算機網絡如同廣袤的江湖,數據在其中暢游,信息傳遞成為了生活的常態。然而,在這個充滿虛擬奇觀的網絡江湖中,隱藏著一個不容忽視的存在,那就是物理層,這個江湖的基石。就如同江湖中的土地一樣,物理層作為計算機網絡的基礎,承載著數據的最初轉…

STM32 CubeMX (uart_IAP串口)簡單示例

STM32 CubeMX STM32 CubeMX &#xff08;串口IAP&#xff09; STM32 CubeMXIAP有什么用&#xff1f;整體思路 一、STM32 CubeMX 設置時鐘樹UART使能UART初始化設置 二、代碼部分文件移植![在這里插入圖片描述](https://img-blog.csdnimg.cn/0c4841d8328b4169a8833f15fe3d670c.p…

PHP Smarty中的緩存如何實現?

歡迎來到PHP Smarty的緩存世界&#xff01;這里是一個簡單的指南&#xff0c;幫助你理解如何在這個強大的模板引擎中啟用和配置緩存。 首先&#xff0c;讓我們先了解一下什么是緩存。簡單來說&#xff0c;緩存就是將需要花費大量時間處理的數據或資源存儲起來&#xff0c;以便…

2023/8/16總結

這幾天完成了私信的功能點&#xff0c;用websocket做的。 這是大概的界面&#xff0c;參考的是微信 用戶可以搜索好友&#xff1a; 如果不存在是下面這樣&#xff0c;存在就會在左邊的聊天里面顯示有這個人選項 發送消息 接下來需要把推薦算法給做了

文件IO編程 1 2

頭文件包含路徑 linux 操作系統分為兩大空間&#xff1a;用戶空間和內核空間 這樣劃分&#xff0c;是為了保護內核的核心組件&#xff0c;不被輕易訪問和修改 系統調用&#xff1a;安全的訪問內核空間 其核心是&#xff1a;函數API&#xff08;API&#xff1a;用戶編程接口&…

svn文章五:問題排查與修復 - 出了問題怎么辦?SVN故障排除與修復指南

文章五&#xff1a;問題排查與修復 - “出了問題怎么辦&#xff1f;SVN故障排除與修復指南” 概述&#xff1a;在使用SVN時&#xff0c;難免會遇到一些問題和錯誤。在這篇文章中&#xff0c;我們將教您如何進行故障排查和修復&#xff0c;保護您的SVN倉庫和數據安全。 1. 引言…