2020春季1-3年前端面經

css

z-index在什麼狀況下失效

z-index只做用於被定位了的元素上,還有就是子元素的z-index會被父的值覆蓋。css

box-sizing有哪些值

content-boxborder-box 兩個,前者是默認值,指設定的width只包含content的寬,不包含border和padding,後者都包括。
這個問的還挺多的有的是給html+css代碼叫算大小的,有的是口頭表達的。html

flex相關屬性值以及他們的意義

flex是佈局的大方向,問的頻率也挺高的,要麼是問垂直居中的時候引出來,要麼是叫你實現一個簡單佈局而後引出來,不清楚的能夠看一哈阮一峯老師的教程(傳送門)vue

css優化手段

這種優化的手段是說不完的,我也僅表達一下本身現階段的一些理解。
一、提升加載速度:好比最最最基礎的壓縮文件大小,還有能夠經過內聯css來使瀏覽器開始頁面渲染的時間提早,文件大小須要控制在14.6kb(由於初始擁塞窗口存在限制),還有就是chrome自帶的 coverage 標籤,能夠分析js和css文件的使用率,而後咱們去進一步作懶加載或者移除無用代碼。
二、提升選擇器的性能,好比不要嵌套太多複雜的層級,選擇器從右到左匹配。
三、提升渲染速度,這個我也不太懂,只是最近看canvas的時候,mdn裏關於canvas優化提到CSS transforms使用GPU,所以速度更快,找到了一篇文章介紹使用transform與否的對比演示,也解釋了爲何會更快,感受不錯,文章傳送門面試

JS

map和filter的區別

map的回調裏return啥就是啥,filter的回調裏返回的布爾值決定當前項是否會存到新的數組裏。
我其實沒懂這個是想問啥,由於筆試遇到這道題的時候其餘題都還挺有意思的,有點把我整懵了。vue-router

sleep

單獨實現一個sleep很簡單chrome

function sleep(time) {
  return new Promise((res) => {
    setTimeout(res, time)
  })
}

可是面試過程當中,碰到了一道筆試題很是有意思,大概是這樣:canvas

//實現
Person('Jack').eat('lunch').sleep(2).eat('dinner').firstSleep(5)
//輸出

// 等待5s
firstSleep 5s
Hi, my name is Jack
Eat lunch
// 等待2s
sleep 2s
Eat dinner

我一開始的思路是使用setTimeoutPromisemacro/micro特徵,即firstSleep使用Promise,其餘所有使用setTimeout,在這樣的思路下,sleep和eat大概是這樣的數組

sleep(time) {
  this.sleepTime += time
  setTimeout(() => {
    log('balabala')
  }, this.sleepTime)
  return this
}
eat(food) {
  setTimeout(() => {
    log('balabala')
  }, this.sleepTime)
  return this
}

那後面的firstSleep就根本無法寫了,前面時常爲this.sleepTime沒有操做空間了。
產生這樣的錯誤思路的緣由是對上面說的sleep函數或者是瀏覽器的事件循環理解不透徹。
這裏咱們須要的是一個雙向隊列(好像是叫這個 吧),即正常狀況的鏈式調用中往隊列中push,遇到firstSleep就unshift,在Person的構造函數中定義一個setTimeout來開始執行這個雙向隊列中的函數(就像串聯多個異步任務時用於鏈接每一個任務的next() )。
代碼:瀏覽器

const log = console.log
const deque = []
function next() {
  const fn = deque.shift()
  fn && fn()
}
function Person(name) {
  deque.push(() => {
    log(`Hi, my name is ${name}`)
    next()
  })
  setTimeout(() => {
    next()
  }, 0)
  return this
}
Person.prototype = {
  eat(food) {
    deque.push(() => {
      log(`Eat ${food}`)
      next()
    })
    return this
  },
  sleep(time) {
    deque.push(() => {
      setTimeout(() => {
        log(`sleep ${time}s`)
        next()
      }, time * 1000)
    })
    return this
  },
  sleepFirst(time) {
    deque.unshift(() => {
      setTimeout(() => {
        log(`sleepFirst ${time}s`)
        next()
      }, time * 1000)
    })
    return this
  }
}

new Person('Jack').eat('lunch').sleep(2).eat('dinner').sleepFirst(2)

再觀察到題目中沒有new關鍵字,寫個函數包一下就好dom

function _Person(name) {
  return new Person(name)
}

currying

// 實現三數相加的add函數
add(1,2,3) // 6
add(1,2)(3) // 6
add(1)(2)(3) // 6

實現一個函數柯里化不難,主要經過判斷當前參數數量與目標函數參數數量,不夠的話返回函數,夠了的話返回結果,兩種實現手段以下:

const sum3 = (x, y, z) => x + y + z
const add = currying(sum3)

// 方法1
function currying1(fn) {
  /*
  *@param{ Number } n 目標函數指望剩餘參數數量
  *@param{ Array } args 已有參數數組
  */
  function next(n, args) {
    return (...xs) => {
      if(n <= xs.length) {
        return fn(...args, ...xs)
      }
      return next(n - xs.length, [...args, ...xs])
    }
  }
  return next(fn.length, [])
}
// 方法2
function currying2(fn) {
  return (...a) => {
    if(a.length >= fn.length) {
      return fn(...a)
    }
    return currying2(fn.bind(null, ...a))
  }
}

思路都同樣的,方法1中合併參數的[...args, ...xs]操做其實就是bind函數最後return裏的合併arguments。

柯里化的部分就完了,可是若是仍是這個add,想實現的是不知道多少個參數相加呢。
與柯里化相同的是在函數內部保存已經收集的參數,不一樣的是柯里化能夠經過判斷參數數量來決定返回值,新需求須要重寫返回函數的toString來輸出最後執行的返回值。

JavaScript calls the toString method automatically when a Function is to be represented as a text value, e.g. when a function is concatenated with a string.

代碼:

function add() {
  var args = Array.prototype.slice.call(arguments)
  
  var adder = function() {
    args.push(...arguments)
    return adder
  }
  
  adder.toString = function() {
    return args.reduce((a, b) => a + b)
  }
  return adder
}

add(1, 2, 3)(4)(5) // f 15
add(1, 2, 3)(4)(5) + 0 // 15

看起來是成了,可是若是不轉換類型的話,輸出的結果前有個 f ,這讓我很疑惑,找了不少資料也沒有結果,若是你知道的話,還請不吝賜教。

Vue

父子組件鉤子順序

父beforeCreate 父created 父beforeMount
子beforeCreate 子created 子beforeMount 子mounted
父mounted
子組件是先於父組件mounted的。

數據變更以後會當即更新dom嗎

這個題也挺有意思的,是在vue雙向綁定原理以後問的,有意思不是在於多難或者多偏,而是能感到面試管真的在考驗你的能力,不是看你會背多少面試題。題目是這樣的

// ...
data() {
  return {
    title: 'abc'
  }
}
methods: {
  change: function() {
    this.title = '1'
    this.title = '2'
    this.title = '3'
    // 調用change以後dom更新幾回
  }
}
// ...

猜也能猜到確定是更新一次。可是我想到別的地方緣由說錯了淦。具體緣由是Vue把更新都借用本身的 nextTick 去異步更新。
下面這段若是不熟的話建議配和Vue(2.6.10)源碼一塊兒食用。
調用 change 以後,順序同步執行三次 defineProperty 裏的 set, 也就是順序同步三次 Watcherupdate 方法,update的核心是 queueWatcher,

export function queueWatcher (watcher: Watcher) {
  const id = watcher.id
  if (has[id] == null) {
    has[id] = true
    if (!flushing) {
      queue.push(watcher)
    } else {
      // ...
    }
    // queue the flush
    if (!waiting) {
      waiting = true
      // ...
      nextTick(flushSchedulerQueue)
    }
  }
}

代碼裏的 has 就是用來過濾相同 watcher ,雖而後面的被無情拋棄了,可是隻要有這個watcher的id,異步更新的時候使用的也是同步修改的數據。

vue-router兩種模式 hash 和 history 的區別

最直觀的區別是hash模式帶 '#'
history模式使用h5新增的 pushStatereplaceState,他們用來修改瀏覽器的歷史記錄棧,修改時不會當即發送請求。

一些感想

能看到這篇文章大機率說明你在準備面試,若是你是萌新沒怎麼面過,那我能夠告訴你不論是大廠仍是小做坊,面試過程有很大比重是介紹你簡歷中寫的能力和項目,與其盲目的在面試題海里不知所措,不如好好準備簡歷拿下那些送分題。若是你是久經沙場的禿頭碼農 ,那也但願這篇文章能幫助到你。

相關文章
相關標籤/搜索