one question everyDay in my life

這篇文章是用來記錄由魏老師天天分享的技術問題,感謝珠峯教育和魏老師的支持
複製代碼

1.傳統佈局和flex佈局有什麼區別
  (1) 性能上flex容許子元素不設置寬高,而是由算法動態去計算,性能會比設定好寬高的稍慢 但在這個時代大致沒有影響
  (2) 傳統佈局+flex佈局!=全部佈局,除了傳統佈局和flex佈局外還有grid佈局,多列布局等等n多種方法
  (3) 傳統佈局,基於盒模型,依賴 display屬性 、position屬性 、float屬性,而FLEX用來爲盒狀模型提供最大的靈活性,不強制要求子元素的大小,任何一個容器均可以指定爲 Flex 佈局,能夠簡便、完整、響應式地實現各類頁面佈局。
題外擴展:
  (1)不要盒模型和佈局弄混淆了,部局是DOM元素在文檔中的位置排布,而模型指得是DOM元素的寬高大小的計算,模型通常由content-box,border-box,padding-box,-webkit-box等,默認爲content-box
  (2)flex佈局成爲一個新的W3C標準規範
  (3)flex在移動端兼容性:ios8不兼容,android4.4不兼容
  (4)-webkit-box:在移動端開發中,全部的瀏覽器基本上都支持-webkit-box 點擊查看-webkit-box
  (5)文檔流:文檔流指元素在文檔中的位置由元素在html裏的位置決定,塊級元素獨佔一行,自上而下排列;內聯元素從左到右排列
  (6)脫離文檔流的方式:
    浮動,經過設置float屬性
    絕對定位,經過設置position:absolute
    固定定位,經過設置position:fixed
  (7)定位浮動知識:點擊這裏送你去快活快活
php


2.你對vue的源碼瞭解嗎,給我講講雙向綁定原理怎麼實現的,詳細描述何時監聽變化的,何時觸發變化的?
  (1) 一個vue對象實例化的過程當中會生成一個observer對象,Observer經過Object.defineProperty裏面的getter和setter實現數據的變化
  (2)vue.js對模板作編譯會解析生成一個個指令對象,每一個指令對象都會關聯一個watcher,經過wahcher監聽數據變化觸發setter方法
題外擴展:
  (1) 能獲取子組件內容但不能獲取子組件的data裏面的屬性: this.refs.子組件.shoppingaddress也獲取不到,是由於異步的緣由,子組件的沒渲染出來,加一個this.nextTick
  (2)計算屬性在模板中沒有使用,那麼能打印出來嗎
html


3.如何比較兩個顏色的類似程度
  (1) 首先將顏色拆分紅r/g/b三個值,若是是字符串的顏色如#aabbff或者rgb(255,128,100)能夠用正則表達式取出對應的r/g/b值。對於16進制字符串, 可使用parseInt(‘0xaa’)轉10進制整數。
  (2) 而後對於兩個顏色,可使用距離 Math.sqrt( (r1-r2) (r1-r2) +(g1-g2)(g1-g2)+(b1-b2)*(b1-b2) )進行比較, 距離近則類似。 固然能夠用Math.hypot( r1-r2, g1-t2, b1-b2) 來簡化上述運算。vue


4.一個單頁面應用,有6張頁面,F、E、A、B、C、D。 頁面ABCD構成了一個冗長的用戶驗證過程。目前A、B、C對應用戶驗證過程的第1步,第2步,第3步。 頁面F是首頁,E是某張業務相關頁面。用戶到達頁面E後, 系統發現用戶沒有認證,觸發驗證流程,到達頁面A,而後開始A->B->C->D流程。 頁面D是驗證結果頁面(驗證成功頁面)。 請問,若是到達頁面D後, 如何讓用戶點擊返回能夠返回頁面F,而忽略中間流程(注:用戶可能根本沒有到達過F,好比微信分享直接進入了E)
  這個問題初一看是對單頁面路由架構的考察。也是一個很好的引入問題,能夠考察很是多方面。 好比說:如何實現頁面切換動畫? A、B、C都是表單的話,如何緩存用戶輸入完成的表單數據?……回到問題,由於history api提供了push/pop/replace三種操做,不管是其中的任何一種都沒法實現上述的效果。 一個路由系統,首先要監聽瀏覽器地址的變化,而後根據變化渲染不一樣的頁面。java

  1. 在頁面到達D後,關閉對路由變化頁面渲染的監聽。
  2. 路由系統要進行屢次POP,能夠用history.go(-n)實現
  3. 路由棧清空到只剩下一張頁面時,將這張頁面替換爲F。
  4. PUSH一張頁面D。 若是在HTML上有一個相似「輪播圖」的設計,就是每一張頁面是一張輪播圖,將輪播圖設置成只有「F」和「D」。
  5. 恢復路由監聽。 這個問題的另外一個考點是,在上述完整的計算過程中,須要知道當前歷史記錄中的頁面數,頁面數能夠經過localStorage實現,在ls中維護一個變量,每次push的時候+1,並寫入history.state。 POP的時候讀取history.state將變量重置。

5.一個無序數組中,怎麼找到和最大的子序列?
  (1)最簡單也最暴力的解法:首先列出 全部的子序列,而後找出其中和最大的 便可; 實現思路:一個 記錄當前最大值的變量maxSum;一個 子序列開始和結束的遊標
變量;一個 當前子序列的和 的暫存變量,咱們稱之爲 currentSum 或者
tmpSum(下文中 使用currentSum)
找到全部的 子序列 咱們能夠經過兩層循環的方式來解決
node

第一層循環 i 從 0~ length-1; </br>
第二層循環 j 從 i ~ length - 1; </br>
這樣的循環裏 就能夠找到全部的子序列了 </br>
下一步 咱們是要計算出全部子序列的和 </br>
最簡單的辦法 就是 第三層循環從 i ~ j 累加求出和 而後求出來的每一個和 和 maxSum</br> 去比較,若是比maxSum 大 就替換</br>
僞代碼:maxSum = maxSum < currentSum ? currentSum : maxSum; </br>
三層循環結束後 maxSum就是咱們要 求的解 </br>
return maxSum便可 </br>
這個算法的時間複雜度是O(n^3);</br>
2)簡化解法:咱們在第二層循環中,咱們已經知道 當前的</br> i/j以前的方法是在第三層的循環中 計算 i ~ j 的和 </br>
如今 咱們在第二層中 在進入第二層以前 咱們重置一下currentSum </br>
第一次循環 是 i ~ i 當前咱們就把 i 的值 記錄到 currentSum去跟 maxSum 對比 而後 maxSum = maxSum < currentSum ? currentSum : maxSum;</br> 
第二次循環 是 i ~ i + 1 咱們就把 當前的 i+1 累加到currentSum 這時候的</br> currentSum就是 i ~ i+1 的值,再去跟maxSum去比 而後 maxSum = maxSum < currentSum ? currentSum : maxSum; </br>
以此類推 </br>
第二層的循環中 就能夠 計算出 以當前 i 開頭的子序列中 最大的子序列是多少 </br>
如今咱們看回 到 第一層循環 i 的取值 是從 0 ~ length-1 那麼咱們是否是 能夠找到 i 從 0 ~ length-1 全部的子序列中和最大的</br>
僞代碼思路: </br>
第一層 i (0 ~ length-1) </br>
currentSum 清零 </br>
第二層 j(i ~ length-1) </br>
currentSum 累加 </br>
maxSum = maxSum < currentSum ? currentSum : maxSum; </br>
return maxSum; </br>
算法的時間複雜度是 O(n^2)</br>
3)demo數組:[-2, 1, -3, 4, -1, 2 , 1, -5, 4] </br>
首先 咱們能夠簡單的簡化一下 這個數組 把 相鄰 的 同</br> 正負的數字合起來,由於同符號的連續數 必定會同時存在在最大子序列裏 </br>
好比 [-1, -2, -3, 1, 2, 13] 那跟 [-6, 16] 是沒有區別的 </br>
[-2, 1, -3, 4, -1, 2, 1, -5, 4] ==> [-2, 1, -3, 4, -1, 3, -5, 4] </br>
而後 咱們從頭開始看 </br>
-2 這是第一個元素 </br>
那麼 咱們認爲 當前的 最大子序列和 就是 -2 </br>
而後 發現了一個正數 1 </br>
那咱們能夠肯定 -2 必定不包含在 咱們的最大子序列中 </br>
也就是說 數組開頭 若是是負數 能夠忽略過去 </br>
如今 咱們的數組 變成了 [1, -3, 4, -1, 3, -5, 4] </br>
同理 結尾的若是是 負數 也不須要考慮 </br>
如今咱們的數組 變成了 [1, -3, 4, -1, 3, -5, 4] </br>
咱們繼續,如今 第一個元素是 1 最大和 是1 </br>
而後下一個數是 -3 </br>
那麼 -3 對 1 這個數 起到了阻斷做用 也就是說 -3 把 前邊全部正數</br> 積累的能量都磨平了 甚至還變成了一個負數 </br>
那麼 -3 咱們稱之爲 一個阻斷 </br>
當前的 最大和 仍是 1 </br>
如今 咱們到了 4 </br>
那麼如今的最大值 就是4 </br>
咱們繼</br>
下個數字是 -1 以前最大的和是 4 </br>
加起來以後是 3 影響並不大 </br>
咱們繼續帶着他 向後看 </br>
下一個 是個正數 3 </br>
也就是 4 -1 3 這樣的狀況 </br>
咱們是否是能夠認爲 這個 -1 雖然下降了 和 可是 他鏈接了左右的正數</br> 讓咱們當前的最大值 變成了 6 更新最大值 繼續看 </br>
下一個是-5 </br>
同理 以前的 6+ -5 和 仍是1 也沒有阻斷 咱們去看看 後邊
有沒有一個大數 拯救咱們 </br>
後邊 一個數 是 4 </br>
加上咱們剛纔記錄的 1 和是5 最後仍是沒有挑戰成功 因此 最大的和 仍是以前的 6</br>
公式:nums是咱們的源數組 nums[i] 就是咱們的當前元素 currentMax[i] 記錄 咱們以 i 結尾的子序列裏 最大的一個子序列 那麼 </br>
currentMax[i] = max(currentMax[i - 1] + nums[i], nums[i]) </br>
這個公式被稱之爲 狀態轉移公式 咱們的這種解法 稱之爲 動態規劃解法 簡稱:PD </br>
而後咱們去遍歷 currentMax 這個數組 裏邊的最大值 就是咱們要找的 最大值</br>
僞代碼: </br>
var maxSubArray = function(nums) { </br>
// 初始化源數組,初始化An爲結束的最大值 </br>
let A = nums; </br>
let dp = []; </br>
let maxSum = A[0]; </br>
dp[0] = A[0]; </br>
for(let i = 1; i < A.length; i++) { </br>
//狀態轉移公式 </br>
dp[i] = max(A[i], dp[i-1] + A[i]) </br>
maxSum = dp[i] > maxSum ? dp[i] : maxSum; </br>
} </br></br>
return maxSum;</br>
}</br>
function max(a, b) { </br>
return a > b ? a : b; </br>
}</br>
複製代碼

6. 請你說說函數防抖和函數節流的應用場景和原理?
函數節流場景:
  (1)例如:實現一個原生的拖拽功能(若是不用H5 Drag和Drop API),咱們就須要一路監聽mousemove事件,在回調中獲取元素當前位置,而後重置dom的位置。不加以控制,每移動必定像素而出發的回調數量是會很是驚人的,回調中又伴隨着DOM操做,繼而引起瀏覽器的重排和重繪,性能差的瀏覽器可能會直接假死。
  (2)這時,咱們就須要下降觸發回調的頻率,好比讓它500ms觸發一次或者200ms,甚至100ms,這個閥值不能太大,太大了拖拽就會失真,也不能過小,過小了低版本瀏覽器可能會假死,這時的解決方案就是函數節流【throttle】。
  (3)函數節流的核心就是:讓一個函數不要執行得太頻繁,減小一些過快的調用來節流。
函數去抖場景:
  (1)對於瀏覽器窗口,每作一次resize操做,發送一個請求,很顯然,咱們須要監聽resize事件,可是和mousemove同樣,每縮小(或者放大)一次瀏覽器,實際上會觸發N屢次的resize事件,這時的解決方案就是節流【debounce】。
  (2)函數去抖的核心就是:在必定時間段的連續函數調用,只讓其執行一次*
總體函數總結一下:
  (1)對於按鈕防點擊來講的實現:一旦我開始一個定時器,只要我定時器還在,無論你怎麼點擊都不會執行回調函數。一旦定時器結束並設置爲null,就能夠再次點擊了。
  (2)對於延時執行函數來講的實現:每次調用防抖動函數都會判斷本次調用和以前的時間間隔,若是小於須要的時間間隔,就會從新建立一個定時器,而且定時器的延時爲設定時間減去以前的時間間隔。一旦時間到了,就會執行相應的回調函數。
節流
  防抖動和節流本質是不同的。防抖動是將屢次執行變爲最後一次執行,節流是將屢次執行變成每隔一段時間執行。android

  • underscore 節流函數,返回函數連續調用時,func 執行頻率限定爲 次 / wait
  • @param {function} func 回調函數
  • @param {number} wait 表示時間窗口的間隔
  • @param {object} options 若是想忽略開始函數的的調用,傳入{leading: false}。
  • 若是想忽略結尾函數的調用,傳入{trailing: false}
  • 二者不能共存,不然函數不能執行
  • @return {function} 返回客戶調用函數
_.throttle = function(func, wait, options) { 
        var context, args, result; 
        var timeout = null; 
        // 以前的時間戳 
        var previous = 0; 
        // 若是 options 沒傳則設爲空對象 
        if (!options) options = {}; 
        // 定時器回調函數 
        var later = function() { 
            // 若是設置了 leading,就將 previous 設爲 0 
            // 用於下面函數的第一個 if 判斷 
            previous = options.leading === false ? 0 : _.now(); 
            // 置空一是爲了防止內存泄漏,二是爲了下面的定時器判斷 
            timeout = null; 
            result = func.apply(context, args); 
            if (!timeout) context = args = null; 
        }; 
    return function() { 
        // 得到當前時間戳 
        var now = _.now(); 
        // 首次進入前者確定爲 true 
        // 若是須要第一次不執行函數 
        // 就將上次時間戳設爲當前的 
        // 這樣在接下來計算 remaining 的值時會大於0 
        if (!previous && options.leading === false) previous = now; 
        // 計算剩餘時間 
        var remaining = wait - (now - previous); 
        context = this; 
        args = arguments; 
        // 若是當前調用已經大於上次調用時間 + wait 
        // 或者用戶手動調了時間 
        // 若是設置了 trailing,只會進入這個條件 
        // 若是沒有設置 leading,那麼第一次會進入這個條件 
        // 還有一點,你可能會以爲開啓了定時器那麼應該不會進入這個 if 條件了 
        // 其實仍是會進入的,由於定時器的延時 
        // 並非準確的時間,極可能你設置了2秒 
        // 可是他須要2.2秒才觸發,這時候就會進入這個條件 
        if (remaining <= 0 || remaining > wait) { 
            // 若是存在定時器就清理掉不然會調用二次回調 
            if (timeout) { 
            clearTimeout(timeout); 
            timeout = null; 
        } 
        previous = now; 
        result = func.apply(context, args); 
        if (!timeout) context = args = null; 
        } else if (!timeout && options.trailing !== false) { 
            // 判斷是否設置了定時器和 trailing 
            // 沒有的話就開啓一個定時器 
            // 而且不能不能同時設置 leading 和 trailing 
            timeout = setTimeout(later, remaining); 
        } 
        return result; 
      }; 
    };
複製代碼

7.電商網站A和電影票網站B合做,A的用戶,能夠經過A網站下單購買電影票,以後跳轉跳轉到B(不須要登陸)去選座位,若是A、B是同域名,好比,好比a.domain.com,b.d,om,b.domain.com能不能共享cookie?
  若是不一樣域如何處理?這實際上是個單點登陸的問題,同一級域名下設置cookie設在一級域名下, 同級域名下的cookie皆共享
缺點:
  1,同一域名限制
  2,登陸的規則一致,若是不一樣域的話就是跨域問題,跨域問題能夠用jsonp解決
  三、兩者的區別
ios


i、做用域程序員

  相同瀏覽器的不一樣頁面間能夠共享相同的 localStorage(頁面屬於相同域名和端口),可是sessionStorage只能在同源(相同域名相同學口)同學口訪問,可是當sessionStorage在同一窗口下轉到同源頁面仍是能夠訪問的,由於這時候仍是同源同學口,不要單純理解爲兩個不一樣的頁面之間不能訪問相同sessionStorage。好比你在A網頁設置了一個sessionStorage的值,而後你同時在新的窗口下打開B網頁,這時候你嘗試在B網頁獲得A網頁設置的sessionStorage是不能夠的,可是當你在A網頁跳轉到B網頁的時候,這時候你會發現B網頁能夠訪問A網頁中的sessionStorage。因此sessionStorage針對的是同源同學口,不是同源同頁面。web

ii、生命週期正則表達式

  localStorage生命週期是永久,這意味着除非用戶本身清除localStorage信息或者用戶清除瀏覽器緩存,不然這些信息將永遠存在。   sessionStorage生命週期爲當前窗口或標籤頁,一旦窗口或標籤頁被永久關閉了,那麼全部經過sessionStorage存儲的數據也就被清空了 總結:

cookie與sessionStorage、localStorage的區別

一、cookie能夠在瀏覽器端與服務器端之間通訊,是服務器端獲取用戶信息、保持一種持久客戶端狀態的關鍵。而sessionStorage、localStorage

雖然也能夠保存會話數據,可是不能與服務器端進行信息交換。

二、cookie的容量比較小。而sessionStorage、localStorage有較大的容量

三、試用的瀏覽器範圍不一樣。因爲sessionStorage與localStorage是HTML5標準推出的,因此在IE7以及IE7如下的版本不適用。替代方案是採用IE的userData.(有興趣能夠了解一下)

三者的異同

特性 Cookie localStorage sessionStorage 數據的生命期 通常由服務器生成,可設置失效時間。若是在瀏覽器端生成Cookie,默認是關閉瀏覽器後失效 除非被清除,不然永久保存 僅在當前會話下有效,關閉頁面或瀏覽器後被清除 存放數據大小 4K左右 通常爲5MB 與服務器端通訊 每次都會攜帶在HTTP頭中,若是使用cookie保存過多數據會帶來性能問題 僅在客戶端(即瀏覽器)中保存,不參與和服務器的通訊 易用性 須要程序員本身封裝,源生的Cookie接口不友好 源生接口能夠接受,亦可再次封裝來對Object和Array有更好的支持

8. 說說什麼是xss攻擊?如何攻擊,如何防護?
  (1)XSS 跨網站指令碼(英語:Cross-site scripting,一般簡稱爲:XSS)是一種網站應用程式的安全漏洞攻擊,是代碼注入的一種。它容許惡意使用者將程式碼注入到網頁上,其餘使用者在觀看網頁時就會受到影響。這類攻擊一般包含了 HTML 以及使用者端腳本語言。
  (2)XSS 分爲三種:反射型,存儲型和 DOM-based
  (3)如何攻擊:
    XSS 經過修改 HTML 節點或者執行 JS 代碼來攻擊網站。
    例如經過 URL 獲取某些參數
    上述 URL 輸入可能會將 HTML 改成

,這樣頁面中就憑空多了一段可執行腳本。這種攻擊類型是反射型攻擊,也能夠說是 DOM-based 攻擊。 也有另外一種場景,好比寫了一篇包含攻擊代碼 的文章,那麼可能瀏覽文章的用戶都會被攻擊到。這種攻擊類型是存儲型攻擊,也能夠說是 DOM-based 攻擊,而且這種攻擊打擊面更廣。 如何防護 最廣泛的作法是轉義輸入輸出的內容,對於引號,尖括號,斜槓進行轉義 這裏寫圖片描述 內容安全策略 (CSP) 是一個額外的安全層,用於檢測並削弱某些特定類型的攻擊,包括跨站腳本 (XSS) 和數據注入攻擊等。不管是數據盜取、網站內容污染仍是散發惡意軟件,這些攻擊都是主要的手段。 咱們能夠經過 CSP 來儘可能減小 XSS 攻擊。CSP 本質上也是創建白名單,規定了瀏覽器只可以執行特定來源的代碼。 一般能夠經過 HTTP Header 中的 Content-Security-Policy 來開啓 CSP 只容許加載本站資源,只容許加載 HTTPS 協議圖片,容許加載任何來源框架 這裏寫圖片描述 這裏寫圖片描述 這裏寫圖片描述 參考網站 content-security-policy.com/ eggjs.org/zh-cn/core/…


9. CSRF攻擊是什麼?如何防範?
  CSRF概念:CSRF跨站點請求僞造(Cross—Site Request Forgery),跟XSS攻擊同樣,存在巨大的危害性,你能夠這樣來理解: 參考網站 www.phpddt.com/reprint/csr… juejin.im/post/5b6b08…


10. 若是發如今某個用戶的電腦上,網站的靜態資源打不開了,如何肯定是CDN的問題仍是那個用戶機器、瀏覽器的問題?
一、本身的電腦訪問cdn地址,排除是否cdn問題;
二、讓用戶換瀏覽器再試,排除用戶瀏覽器的問題(禁用全部插件、清除緩存);
三、已經排除cdn和用戶瀏覽器的問題,那就是用戶的機器(或者所在的網絡)有問題。有多是用戶所在的公司網絡禁止下載某些資源。
四、推薦一個本地網絡診斷的工具的工具https://cdn.dns-detect.alicdn.com/https/doc.html 能夠檢 能夠檢查dns和本地ip地址是否正常


11. 請說說在hybrid端實現相似原生般流暢的體驗,要注意哪些事項?
  1.資源加載,採用預加載,優先加載到內存中,作到無縫切換,使用原生loading
  2.離線加載靜態資源,不走網絡請求
  3.儘可能作到局部更新,動畫使用transform,will-change來提升性能
  4.使用webkit over scrolling加速滾動條的滾動,去掉user selection,去掉高亮等,手勢交互原生實現,複雜交互如日期選擇器等調用原生組件
  5.遵循APP UI設計規範
  6.考慮文件diff更新,或主動後臺請示,在某個時刻跟新,兩個版本直接的兼容問題
  7.APP方法加上安全性的考慮


12.事件觸發的三個階段
  document 往事件觸發處傳播,遇到註冊的捕獲事件會觸發 傳播到事件觸發處時觸發註冊的事件 從事件觸發處往 document 傳播,遇到註冊的冒泡事件會觸發 事件觸發通常來講會按照上面的順序進行,可是也有特例,若是給一個目標節點同時註冊冒泡和捕獲事件,事件觸發會按照註冊的順序執行。

// 如下會先打印冒泡而後是捕獲
node.addEventListener('click',(event) =>{
	console.log('冒泡')
},false);
node.addEventListener('click',(event) =>{
	console.log('捕獲 ')
},true)
複製代碼

註冊事件
  一般咱們使用 addEventListener 註冊事件,該函數的第三個參數能夠是布爾值,也能夠是對象。對於布爾值 useCapture 參數來講,該參數默認值爲 false 。useCapture 決定了註冊的事件是捕獲事件仍是冒泡事件。對於對象參數來講,可使用如下幾個屬性 capture,布爾值,和 useCapture 做用同樣 once,布爾值,值爲 true 表示該回調只會調用一次,調用後會移除監聽 passive,布爾值,表示永遠不會調用 preventDefault通常來講,咱們只但願事件只觸發在目標上,這時候可使用 stopPropagation 來阻止事件的進一步傳播。一般咱們認爲 stopPropagation 是用來阻止事件冒泡的,其實該函數也能夠阻止捕獲事件。stopImmediatePropagation 一樣也能實現阻止事件,可是還能阻止該事件目標執行別的註冊事件。

node.addEventListener('click',(event) =>{
	event.stopImmediatePropagation()
	console.log('冒泡')
},false);
// 點擊 node 只會執行上面的函數,該函數不會執行
node.addEventListener('click',(event) => {
	console.log('捕獲 ')
},true)
複製代碼

事件代理 若是一個節點中的子節點是動態生成的,那麼子節點須要註冊事件的話應該註冊在父節點上

<ul id="ul">
	<li>1</li>
    <li>2</li>
	<li>3</li>
	<li>4</li>
	<li>5</li>
</ul>
<script>
	let ul = document.querySelector('##ul')
	ul.addEventListener('click', (event) => {
		console.log(event.target);
	})
</script>z
複製代碼

事件代理的方式相對於直接給目標註冊事件來講,有如下優勢 節省內存 不須要給子節點註銷事件 點擊查看詳解


12.問題以下:

  1. 什麼是重繪(Repaint)和迴流(Reflow)?
  2. 哪些動做可能會致使重繪(Repaint)和迴流(Reflow)的發生?
  3. 重繪(Repaint)和迴流(Reflow)和Event loop的關係?
  4. 如何減小重繪(Repaint)和迴流(Reflow)?

13. 2*8最有效率的計算方法
  2<<3 講一個數左移動n位就至關於乘以2的n次方,一個數要乘以8只須要將他左移動三位就好了,而位運算cpu直接支持,因此運算效率最高,因此2乘以8最有效的是 2<<3
例如11 >> 2,則是將數字11右移2位
右移一位至關於除2,右移n位至關於除以2的n次方。
14.發佈訂閱模式和觀察者模式有什麼區別

其實訂閱模式有一個調度中心,對訂閱事件進行統一管理。而觀察者模式能夠隨意註冊
事件,調用事件,雖然實現原理都雷同,設計模式上有必定的差異,實際代碼運用中差異在
於:訂閱模式中,能夠抽離出調度中心單獨成一個文件,能夠對一系列的訂閱事件進行統一管理。
複製代碼

15.apply和call方法有什麼區別

區別:
   call, apply方法區別是,從第二個參數起,call方法參數將依次傳遞給借用的方法做參數
而apply直接將這些參數放到一個數組中再傳遞, 最後借用方法的參數列表是同樣的.
應用場景:
   當參數明確時可用call, 當參數不明確時可用apply給合arguments
複製代碼

16.js對象和hashMap

數組:也叫線性連續表
怎麼將一組值相差範圍巨大,個數波動範圍很大的下標放入特定的數組空間呢?
用哈希算法、也叫散列算法
哈希算法的目的就是將不定的輸入轉換成特定範圍的輸出,而且要求輸出儘可能均勻分佈
1,除法散列法
最直觀的一種,小茄上文使用的就是這種散列法,公式:
index = key % 16
2,平方散列法
求index是很是頻繁的操做,而乘法的運算要比除法來得省時(對如今的CPU來講,估計我
們感受不出來),因此咱們考慮把除法換成乘法和一個位移操做。公式:
index = (key * key) >> 28
3,斐波那契(Fibonacci)散列法
複製代碼

17.vue組件中data必須是一個函數的緣由

vue組件中data值不能爲對象,由於對象是引用類型,組件可能會被多個實例同時引用。
若是data值爲對象,將致使多個實例共享一個對象,其中一個組件改變data屬性值,其它
實例也會受到影響。

  上面解釋了data不能爲對象的緣由,這裏咱們簡單說下data爲函數的緣由。data爲函數,
經過return 返回對象的拷貝,導致每一個實例都有本身獨立的對象,實例之間能夠互不影
響的改變data屬性值。
複製代碼

18.原型鏈

實例的__protpo__指向的是原型對象。
   實例的構造函數的prototype也是指向的原型對象。 
   原型對象的construor指向的是構造函數。
   對象的__proto__它的是原型,而原型也是一個對象,也有__proto__屬性,原型的
   __proto__又是原型的原型,就這樣能夠一直經過__proto__想上找,這就是原型鏈,當向上
   找找到Object的原型的時候,這條原型鏈就算到頭了
複製代碼

19.閉包

一般,函數的做用域及其全部變量都會在函數執行結束後被銷燬。可是,在建立了一個閉
包之後,這個函數的做用域就會一直保存到閉包不存在爲止
function makeAdder(x) { 
  return function(y) { 
    return x + y; 
  }; 
} 
閉包建立的第二種形式:傳入一個全局變量
建立閉包的常見方式,就是在一個函數內部建立另外一個函數。

//經過閉包能夠得到函數fn的局部變量user
function fn(){
    var user='zhang';
    return function(){
        return user;
    }//經過匿名函數返回局部變量user
}
console.log(fn()());//zhang  經過box()()來直接調用匿名函數返回值

var b=fn();
console.log(b());//zhang 另外一種調用匿名函數返回值
經過閉包能夠實現函數內的局部變量的累加:

function fn(){
    var num=100;
    return function(){
        num++;
        return num;
    }
}
var b=fn();//得到函數
//你會發現局部變量num並無在內存當中消失
console.log(b());//調用匿名函數
console.log(b());//第二次調用匿名函數,實現累加
因爲在閉包所在的做用域返回的局部變量不會被銷燬,因此會佔用內存。過分的使用閉
包會迫使性能降低,所以建議你們在有必要的狀況下再使用閉包。做用域鏈的機
制會致使一個問題,在循環中裏的匿名函數取得的任何變量都是最後一個值

function fn(){
    var arr=[];
    //i爲fn函數中的局部變量。
    for(var i=0;i<3;i++){
        arr.push(function(){
            return i;
        });
    }
    return arr;

}
var b=fn();
for(var i=0;i<b.length;i++){
    console.log(b[i]());//3
}
以上示例輸出的結果均是3,也就是循環結束後i的值。這是由於在for循環的過程中,
數組中的匿名函數並無自我執行。當在調用匿名函數的時候,經過閉包得到的i已是3了
,因此每次輸出的都是3。 若是想要輸出的結果爲0,1,2能夠作以下的調整:

function fn(){
    var arr=[];
    for(var i=0;i<3;i++){
        arr.push((function(num){
            //將當即執行函數返回的匿名函數放到數組中。
            //由於num爲函數的參數,所以有本身獨立的做用域
            return function(){
                return num;
            };
        })(i));
    }
    return arr;
}
var b=fn();
for(var i=0;i<b.length;i++){
    console.log(b[i]());//0,1,2
}
經過匿名函數的當即執行,將當即執行後返回的函數直接賦值給數組arr。每次循環即將
i的值傳遞給num,又由於num在函數中,因此有本身的獨立做用域,所以num獲得的值爲
每次循環傳遞進來的i值,即0,1,2

接下來看一下關於閉包當中的this對象:
this對象指的是什麼,這個要看函數所運行的環境。若是函數在全局範圍內調用
,函數內的this指向的是window對象。對象中的方法,經過閉包若是運行的環境
爲window時,則this爲window。由於閉包並非該對象的方法。

var color="red";
function fn(){
    return this.color;
}
var obj={
    color:"yellow",
    fn:function(){
        return function(){//返回匿名函數
            return this.color;
        }
    }
}
console.log(fn());//red  在外部直接調用this爲window
var b=obj.fn();//b爲window下的變量,得到的值爲obj對象下的fn方法返回的匿名函數
console.log(b());//red  由於是在window環境下運行,因此this指缶的是window

//能夠經過call或apply改變函數內的this指向
console.log(b.call(obj));//yellow
console.log(b.apply(obj));//yellow
console.log(fn.call(obj));//yellow
經過變量能夠得到上一個做用域中的this指向

var color="red";
function fn(){
    return this.color;
}
var obj={
    color:"yellow",
    fn:function(){
        var _this=this;//將this賦值給變量_this
        return function(){
            return _this.color;//經過_this得到上一個做用域中的this指向
        }
    }
}
console.log(fn());//red
var b=obj.fn();
console.log(b());//yellow
能夠經過構造方法傳參來訪問私有變量
function Desk(){
    var str="";//局部變量str,默認值爲""
    this.getStr=function(){
        return str;
    }
    this.setStr=function(value){
        str=value;
    };
}
var desk=new Desk();
//爲構造函數的局部變量寫入值。
desk.setStr("zhangPeiYue");
//獲取構造函數的局部變量
console.log(desk.getStr());//zhangPeiYue
閉包常見的做用
一、模擬塊級做用域(匿名自執行函數)
if(){}for(){}等沒有做用域,因此在其塊內聲明的變量,在外部是可使用的。

//javaScript沒有塊級做用域的概念
function fn(num){
    for(var i=0;i<num;i++){}
    console.log(i);//在for外部i不會失敗
}
fn(2);

if(true){
    var a=13;
}
console.log(a);//在if定義的變量在外部能夠訪問
經過匿名自執行函數能夠模擬塊級做用域

 (function(){
        //i在外部就不認識啦
        for(var i=0;i<count;i++){}
  })();
  console.log(i);//報錯,沒法訪問
因爲外部沒法訪問自執行函數內的變量,所以在函數執行完後會馬上被銷燬,在外部沒法
訪問。從而可有效避免在多人開發時因爲全局變量過多而形成的命名衝突問題。另外因爲
做用域鏈的機制,局部變量要比全局變量的訪問速度更快,能夠提高程序的運行速度!

二、對結果進行緩存
寫一個用於實現全部參數和的函數:

var fn=function(){
    var sum=0;
    for(var i=0;i<arguments.length;i++){
        sum+=arguments[i];
    }
    return sum;
}
console.log(fn(1,2));//3
以上函數接收一些number類型的參數,並返回這些參數之和。因爲每次傳遞的參數相同,
因此返回的結果是同樣的。這樣勢必會形成了一種浪費,在此時我們能夠經過緩存機制來提
高這個函數的性能。

var fn=(function(){
    var cache={}//將結果緩存到該對象中
    return function(){
        var str=JSON.stringify(arguments);
        if(cache[str]){//判斷緩存中是否存在傳遞過來的參數,存在直接返回結果,
        無需計算
            return cache[str];
        }else{//進行計算並返回結果
            var sum=0;
            for(var i=0;i<arguments.length;i++){
                sum+=arguments[i];
            }
            return cache[str]=sum;
        }
    }
})()
上面的示例將計算後的結果緩存到局部變量cache當中,在調用這個函數時,先在緩存中
查找,若是找不到,則進行計算,而後將結果放到緩存中並返回,若是找到了,直接返回
查找到的值。
複製代碼
相關文章
相關標籤/搜索