感慨歲月如梭==>前端基礎

前言

也不知道是何時我曾經立下一天一遍博文的豪言壯志,現在打開一看,有關技術的文章的建立時間都定格在2017年,豪言壯志當然不可靠,腳踏實地纔是硬道理。這幾個月個人變化很大,曾經懶惰睡懶覺的我天天都堅持6點起牀,如今我還在嘗試學着胖哥(技術胖)10點半睡覺4點半起牀,結果第一天就吃到了失敗的苦果。以上內容交代了文章主人公從一個懶惰it行業從事者慢慢向業界前輩學習的經歷。接下來我會記錄下關於前端面試的一些問題和解答,不能保證徹底是正確的,可是對我自身也算是種技術沉澱了。javascript

主要內容分爲 JS原生部分,vue框架使用部分和優化的部分。由於我最近在面試,因此可能會抽面試題來先寫,其實我也沒有太多思路,秉着沒人看的心態拼命亂寫,我仍是但願有我的在下面大聲說出博主你寫錯啦等等吐槽,我是菜雞我爲本身代鹽。html

因爲是我的總結因此並不會太詳細,也不會舉例去說明,只能按個人表達出來前端

內容

1 JS原生

前端的根基所在,原生JS是限制不少前端向更高方向發展的一個瓶之一,廢話很少說先從簡單的開始吧
複製代碼

1 let/const區別

這題看起很簡單,我會不假思索的答出const通常用來定義常量或者對象(對象類型在js中是保存一個指針地址因此不會有改變),而let咱們就用來定義變量,const是須要初始化的,在定義的時候就須要初始化賦值,而let則不用一開始就初始化,二者都不存在變量提高(暫時性死區),而且會造成一個塊級做用域,並且不能重複定義相同的變量名。如今咱們稍微整理一下他們的異同點,同時給他倆來個參照物var,得出如下結論。vue

相同點:html5

  1. 塊級做用域
  2. 不存在變量提高
  3. 暫時性死區
  4. 不可重複聲明
  5. let、const聲明的全局變量不會掛在頂層對象下面

不一樣點:java

  1. const定義須要初始化
  2. const不可修改,只讀
    補充個暫時性死區的解釋:

當程序的控制流程在新的做用域(module function 或 block 做用域)進行實例化時,在此做用域中用let/const聲明的變量會先在做用域中被建立出來,但所以時還未進行詞法綁定,因此是不能被訪問的,若是訪問就會拋出錯誤。所以,在這運行流程進入做用域建立變量,到變量能夠被訪問之間的這一段時間,就稱之爲暫時死區。git

翻譯一下人話就是,在函數做用域,或者使用let/const時造成的塊級做用域中,在執行到let/const之定義以前,定義的變量都是不可訪問的,在語法上這個暫時性死區(TDZ)。es6

2 數組去重方法

面試超級喜歡問的問題,簡單來講,非要追求逼格的話google一下能夠找找到不少,這裏我只介紹最實用的方法,在處理性能方面方法3>方法1>方法2github

1 普通版

function unique(array) {
  let temp = []
  for (let i = 0, l = array.length; i < l; i++) {
    if (temp.indexOf(arr[i]) === -1) temp.push(arr[i])
  }
  return temp
}
複製代碼

最普通的for循環,時間複雜度O(n^2) 空間複雜度O(n),固然咱們能夠價格hash表讓查找更加快速面試

function unique(array) {
  let temp = []
  let hash = {}
  for (let i = 0, l = array.length; i < l; i++) {
    if (!hash[array[i]]) {
      hash[array[i]] = true //存入hash表
      temp.push(arr[i])
    }
  }
  return temp
}
複製代碼

這樣咱們就能夠把時間複雜度降到了O(n),但因爲新建了一個對象因此消耗內存方面要遠大於indexOf

2 filter版

function unique(array) {
  return array.filter((item, index, array) => {
    return array.indexOf(item) === index
  })
}
複製代碼

這個性能應該是最差的了,從空間複雜度和時間複雜度上推論的

3 es6版(set)

//Set 版本
function unique(array) {
  return [...new Set(array))]
}
複製代碼

經測試這個最好

4 強行ts版

function unique(array: Array<number>): Array<number> {
  let temp: Array<number> = []
  for (let i: number = 0, l: number = array.length; i < l; i++) {
    if (temp.indexOf(array[i]) === -1) temp.push(array[i])
  }
  return temp
}

複製代碼

ts用的很是少,隨手寫的,不夠健壯性,只能去掉重複的數字類型數組,二維數據,和其它類型的數據都沒有考慮到,由於比較隨意啊,因此我也不考慮那麼多了,總結下就行了

3 如何控制冒泡/捕獲事件

首先,事件冒泡和事件捕獲的提出都是爲了解決事件執行順序,咱們在使用中能夠經過addEventListener()的第三個參數來決定咱們註冊的事件是捕獲時觸發仍是冒泡時觸發,false的時候是冒泡觸發,true則爲捕獲。下面我就簡單舉個例子,請看如下代碼

<div id="el_1">
    <p class="el_2">有本事點我</p>
<div>
//假設咱們給p添加一個點擊事件
複製代碼

事件冒泡:是微軟的方案,冒泡就像一塊石頭扔進水裏,氣泡會從底下往上冒,因此以上的事件執行順序是p>div>body>html>document

事件捕獲:網景公司提出,事件捕獲和事件冒泡相反,這時候p元素的點擊事件執行順序是 document>html>body>div>p

細心的小夥伴必定會發現咱們如今用的w3c標準實際上是存在事件冒泡和事件捕獲的,其實這就是w3c作的折中方案,這個方案就是先捕獲後冒泡,到事件target上時,則是誰先註冊誰就先執行,好比你在target上註冊了一個事件捕獲事件和事件冒泡事件,那決定他們執行順序的其實就是註冊的順序。

4 什麼是閉包

關於閉包,我想你們都很熟悉,此次我打算用變量對象的角度來解析閉包的原理。 閉包提供了函數外部訪問函數內部變量的能力,同時因爲沒法被回收會致使內存泄露等問題。

個人描述創建在有必定基礎的狀況下的,默認你明白函數執行上下文的建立,js垃圾回收機制,做用域鏈等基礎知識。

首先咱們講一下做用域的概念,做用域鏈其實由當前環境和上層環境一些類變量對象組成,它保證了當前環境對符合訪問權限的變量和函數的有序訪問。 這時候咱們舉例有一個執行上下文A和一個在執行上下文A下建立的函數也就是執行上下文B,當執行上下文A被激活的時候,這時候執行上下文就會被建立,在建立階段分別會建立變量對象,肯定this的指向,肯定做用域鏈, 以後就是執行階段,也就是執行咱們寫在函數體內的代碼,分別是變量賦值,函數引用和其它代碼,執行完畢後變執行上下文就會出棧,等待垃圾回收。 那麼閉包是什麼,上面提到了執行上下文B執行時若是訪問了執行上下文A的變量對象,那麼閉包就產生了,這時候函數B就是個閉包(這裏是有不一樣解釋的,各類大神書稱內層函數爲閉包,而chrome中則之外層函數爲閉包),變量對象中包含了argument,聲明的變量和聲明的函數,而咱們知道,函數的執行上下文,在執行完畢以後,生命週期結束,那麼該函數的執行上下文就會失去引用。其佔用的內存空間很快就會被垃圾回收器釋放。但是閉包的存在,會阻止這一過程。閉包的運用就很少說了,有柯里化等

5 hash和histroy模式的區別

這一個我以前寫過一篇總結,我就直接放進來了

history給咱們保存狀態的能力,經過pushState()添加激活歷史條目,經過replaceState()修改當前激活的歷史條目history接收三個參數

history.pushState({page:1},'title1','?page=1')
複製代碼
  • stateObj(狀態對象) : 是一個JavaScript對象類型,咱們能夠經過這個這個對象保存數據,能夠在新的歷史條目裏(新的頁面)獲取到這個對象

  • title(標題) :目前瀏覽器大多不支持,保險起見能夠傳一個空字符串

  • url(地址): 新的頁面地址,可選,傳入的地址必須是同源,不然pushState()會拋出異常l 不傳或傳空字符串新歷史條目默認爲當前文檔url

經過onpopstate事件的event對象會拷貝一份改歷史記錄條目的state,下面咱們來實現一個小案例。

history.pushState({
      color: 'red',
    },
    '',
    '?color=red') //添加並激活一個歷史條目,histroy.html?color=red
  history.back() //返回上一條歷史條目 histroy.html
  setTimeout(() => {
    history.forward() //設置定時器後前進到下一條歷史條目 ,histroy.html?color=red
  }, 1000)
  // 狀態的歷史記錄條目發生變化時, popstate事件就會在對應window對象上觸發.
  window.onpopstate = function (e) {
    console.log(e.state)
    if (e.state && e.state.color === 'red') {
      document.body.style.color = 'red'
    }
  }
複製代碼

經過pushstate把頁面的狀態保存在state對象中,當頁面的url再變回這個url時,能夠經過event.state取到這個state對象,從而能夠對頁面狀態進行還原,這裏的頁面狀態就是頁面字體顏色,其實滾動條的位置,閱讀進度,組件的開關的這些頁面狀態均可以存儲到state的裏面。

補充資料

window.onpopstate = function (event) {
    alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
  };
  //綁定事件處理函數.
  history.pushState({
    page: 1
  }, "title 1", "?page=1"); //添加並激活一個歷史記錄條目 http://example.com/example.html?page=1,條目索引爲1
  history.pushState({
    page: 2
  }, "title 2", "?page=2"); //添加並激活一個歷史記錄條目 http://example.com/example.html?page=2,條目索引爲2
  history.replaceState({
    page: 3
  }, "title 3", "?page=3"); //修改當前激活的歷史記錄條目 http://ex..?page=2 變爲 http://ex..?page=3,條目索引爲3
  history.back(); // 彈出 "location: http://example.com/example.html?page=1, state: {"page":1}"
  history.back(); // 彈出 "location: http://example.com/example.html, state: null
  history.go(2); // 彈出 "location: http://example.com/example.html?page=3, state: {"page":3}
複製代碼

補充關於hash的一些知識點,咱們histroy是html5 的 api,在此以前還有個hash,瀏覽器經過記錄hash值讓頁面不刷新跳轉,背後的原理其實onhashchange 事件,該事件是在window上的,下面經過一個小demo來理解

<body>
  <div>這是一段測試hash的小文字,改變hash值將觸發hashchange事件,這段文字的顏色取自hash值</div>
</body>
複製代碼
window.onhashchange = function (e) {
    console.log('form:', e.newURL, 'from:', e.oldURL)
    document.body.style.color = location.hash.slice(1)
    console.log(location.hash)
  }
複製代碼

Snip20190820_2
Snip20190820_3
Snip20190820_4
Snip20190820_5

這樣咱們就實現了對頁面狀態的保持,在chrome中前進後退咱們的頁面,但咱們只能經過修改#後面的值來達到咱們須要的效果,這樣自由性會很是低,因此有了咱們的history模式

2 vue框架的使用

預告:先佔個坑位,預告是單向數據流,mixin,低耦合可拓展路由配置

3 網頁的優化

預告:組件分割,緩存,tree shaking,圖片優化

相關文章
相關標籤/搜索