前端基礎面試題@JS篇

說說Js的數據類型都有哪些

基本類型

  • String
  • Number
  • Boolean
  • null
  • undefined
  • symbol

引用類型

  • object

說說Http狀態碼

1** 信息,服務器收到請求,須要請求者繼續執行操做(101,升級爲websocket協議)
2** 成功,操做被成功接收並處理(206,部份內容,分段傳輸)
3** 重定向,須要進一步操做以完成請求(301,302重定向;304命中緩存)
4** 客戶端錯誤,請求包含語法錯誤或沒法完成請求(401,要求身份驗證;403,服務器理解客服端需求,可是禁止訪問)
5** 服務器錯誤,服務器在處理請求的過程當中發生了錯誤javascript

說說ajax狀態碼,ajax必定是異步的嗎?

ajax不必定是異步的,能夠經過open方法的第三個參數來配置(默認爲true,異步)
css

狀態碼:html

0 - (未初始化)尚未調用send()方法
1 - (載入)已調用send()方法,正在發送請求
2 - (載入完成)send()方法執行完成
3 - (交互)正在解析響應內容
4 - (完成)響應內容解析完成,能夠在客戶端調用了
前端

說說ajax是什麼?優點?劣勢?應該注意的問題?

ajax是一種和後臺通訊的標準。全稱是Asynchronous Javascript And XML(異步javascript和XML)。java

優點:react

  • 無需刷新頁面請求數據,可使產品更快、更小、更友好
  • 能夠把之前服務端的任務轉嫁到客戶端來處理,減輕服務器負擔,節省帶寬
  • 瀏覽器支持好,無需插件

劣勢:webpack

  • 不支持瀏覽器的回退按鈕
  • 安全性存在問題,可以在用戶不知情的狀況下發送請求
  • 暴露了http交互細節
  • 對搜索引擎(網絡爬蟲)的支持比較弱
  • 程序不容易調試

注意的問題:es6

  • 瀏覽器兼容性問題,這個問題jQuery等庫已經幫咱們封裝好了
  • 跨域問題,不一樣域之間不容許經過ajax進行訪問,能夠參考阮一峯老師的跨域資源共享 CORS 詳解
  • 爲了更快的速度和對搜索引擎友好,首頁儘可能不要用ajax而是服務端渲染(固然這看分場景)
  • ajax適合增刪改查操做

你把下面的表達式的打印結果寫出來

1.toString()  //Uncaught SyntaxError: Invalid or unexpected token
true.toString()  //"true"
[].toString()  //""
{}.toString()  //Uncaught SyntaxError: Unexpected token .
null.toString()  //Uncaught TypeError: Cannot read property 'toString' of null
undefined.toString()  //Uncaught TypeError: Cannot read property 'toString' of undefined
NaN.toString()   //"NaN"
複製代碼

這些須要刻意背一下,其中1和{}是語法錯誤。null和undefined是由於沒有toString方法,可使用call來借用(想詳細瞭解,能夠到評論區看我如何被罵的):web

1..toString()   //"1"
(1).toString()  //"1"
Number(1).toString()  //"1"
({}).toString()  //[object Object]
Object.prototype.toString.call(null)   //[object Null]
Object.prototype.toString.call(undefined)   //[object Undefined]
複製代碼

前端性能優化你瞭解哪些

內容層面

  • 使用CDN
  • 單域名、多域名,單域名能夠減小DNS查找次數,多域名能夠增長瀏覽器並行下載數量,這須要權衡,通常同一個域下不要超過四個資源。
  • 避免重定向(分場景)
  • 避免404

網絡層面

  • 利用緩存,能夠參考另外一篇文章手寫文件服務器,說說先後端交互
  • 文件壓縮(經過響應頭Accept-Encoding: gzip, deflate, br告訴服務器你支持的壓縮類型)
  • 按需加載,提取公共代碼,tree-shaking等(均可以經過webpack來實現)
  • 減小cookie大小
  • 文件合併,經過css雪碧圖合併圖片
  • 文件預加載、圖片懶加載

渲染層間

  • js放底部,css放頂部
  • 減小reflow(迴流)和repaint(重繪)
  • 減小dom節點

代碼層面

  • 緩存dom節點,減小節點查找,css選擇器層級優化
  • 減小dom節點操做
  • 合理使用break、continue、return等,優化循環
  • 像react用到的事件委託、對象池等手段

說說瀏覽器的reflow和repaint

瀏覽器解析過程

  1. 解析html生成dom樹
  2. 解析css
  3. 把css應用於dom樹,生成render樹(這裏記錄這每個節點和它的樣式和所在的位置)
  4. 把render樹渲染到頁面

reflow(迴流)

reflow翻譯爲迴流,指的是頁面再次構建render樹。每一個頁面至少發生一次迴流,就是第一次加載頁面的時候面試

此外,當頁面中有任何改變可能形成文檔結構發生改變(即元素間的相對或絕對位置改變),都會發生reflow,常見的有:

  • 添加或刪除元素(opacity:0除外,它不是刪除)
  • 改變某個元素的尺寸或位置
  • 瀏覽器窗口改變(resize事件觸發)

repaint(重繪)

repaint翻譯爲重繪,它能夠類比爲上面的第四步,根據render樹繪製頁面,它的性能損耗比迴流要小。每次迴流必定會發生重繪。此外,如下操做(不影響文檔結構的操做,影響結構的會發生迴流)也會發生重繪:

  1. 元素的顏色、透明度改變
  2. text-align等

瀏覽器優化

咱們不太容易精確知道哪些操做具體會形成哪些元素迴流,不一樣的瀏覽器都有不一樣的實現。可是肯定是他們的的耗時是比較長的,由於涉及到大量的計算。

瀏覽器爲了提高性能也對這個問題進行了優化。方案就是維護一個隊列,把全部須要迴流和重繪的操做都緩存起來,一段時間以後再統一執行。可是,有的時候咱們須要獲取一些位置屬性,當咱們一旦調用這些api的時候,瀏覽器不得不當即計算隊列以保證提供的數據是準確的。例如如下操做:

  • offsetTop, offsetLeft, offsetWidth, offsetHeight
  • scrollTop/Left/Width/Height
  • clientTop/Left/Width/Height
  • width,height
  • getComputedStyle或者IE的currentStyle

注意問題

  1. 批量處理
  • 使用DocumentFragment進行緩存,這樣只引起一次迴流
  • 把頻繁操做的元素先display:null,只引起兩次迴流
  • cloneNode和replaceChild,只引起兩次迴流
  1. 不要頻繁更改style,而是更改class
  2. 避免頻繁調用offsetTop等屬性,在循環前把它緩存起來
  3. 絕對定位具備複雜動畫的元素,不然會引發父元素和後續大量元素的頻繁迴流

如何去除字符串首位空格?

//es6
' ab '.trim()      //"ab" 
//正則
' ab '.replace(/^\s*|\s*$/g,'')  //"ab"
複製代碼

如何獲取url中的查詢字符串

function queryUrlParameter(str) {
    let obj = {}
    let reg = /([^?=&#]+)=([^?=&#]+)/g;
    str.replace(reg, function () {
        obj[arguments[1]] = arguments[2]
    })
    //若是加上hash
    // reg = /#([^?&=#]+)/g
    // if (reg.test(str)) {
    //     str.replace(reg, function () {
    //         obj.hash = arguments[1]
    //     })
    // }
    return obj
}
console.log(queryUrlParameter('http://www.baidu.com?a=1&b=2#12222'))  //{ a: '1', b: '2'}
複製代碼

如何實現一個深拷貝、深比較

深拷貝

function clone(obj) {
  if (obj == null || typeof obj !== 'object') return obj

  let newObj = null

  // 時間對象有特殊性
  if (obj.constructor === Date) {
    newObj = new obj.constructor(obj)
  } else {
    newObj = obj.constructor()
  }


  for (let key in Object.getOwnPropertyDescriptors(obj)) {
    newObj[key] = clone(obj[key])
  }
  return newObj
}
複製代碼

深比較

function deepCompare(a, b){
  if(a === null
    || typeof a !== 'object'
    || b === null
    || typeof b !== 'object'){
    return a === b
  }

  const propsA = Object.getOwnPropertyDescriptors(a)
  const propsB = Object.getOwnPropertyDescriptors(b)
  if(Object.keys(propsA).length !== Object.keys(propsB).length){
    return false
  }

  return Object.keys(propsA).every( key => deepCompare(a[key], b[key]))

}

複製代碼

如何實現函數節流和防抖

節流

function throttle(fn, delay) {
  delay = delay || 50
  let statTime = 0
  return function () {
    statTime === 0 && fn.apply(this, arguments)
    let currentTime = new Date()
    if (currentTime - statTime > delay) {
      fn.apply(this, arguments)
      statTime = currentTime
    }
  }
}

let throttleFn = throttle(fn)

throttleFn()//只會執行一次
throttleFn()
throttleFn()
throttleFn()
複製代碼

防抖

function debounce(fn, delay) {
  delay = delay || 50
  let timer = null
  return function () {
    let self = this
    clearTimeout(timer)
    timer = setTimeout(fn.bind(self, arguments), delay);
  }
}
複製代碼

你給我寫一個原生bind方法

Function.prototype._bind = function (context) {
  let self = this
  let args_1 = [].prototype.slice.call(arguments, 1)
  return function () {
    let args_2 = [].prototype.slice.call(arguments)
    let args = args_1.concat(args_2)
    return self.apply(context, args)
  }
}
複製代碼

這只是對bind的一種簡單實現,若是有興趣瞭解更多能夠參考Javascript中bind()方法的使用與實現

如何實現一個數組的展平

function (ary) {
    return ary.toString().split(',')
}
複製代碼

這是一個投機取巧的方法(面試寫個這個也湊合吧),若是有興趣能夠搜索一下其餘實現方法

如何添加、刪除、移動、複製DOM節點

建立

  • createTextNode() //建立文本節點
  • createElement() //建立元素節點
  • createDocumentFragment() //建立文檔碎片

操做

  • appendChild() //增長
  • removeChild() //刪除
  • replaceChild() //替換
  • insertBefore() //插入

查找

  • getElementById()
  • getElementByTagName()
  • getElementByName()
相關文章
相關標籤/搜索