不知名本科菜雞の春招前端心路歷程(阿里,騰訊,美團) | 掘金技術徵文

BB小天使發表於2020-04-04

囉嗦的話

本人現在大三,就讀於北京師範大學珠海分校的前端小菜雞。受人蠱惑,1月份開始尋找暑期實習,經歷十分坎坷。因為也拿到自己心愛的offer啦,有的公司也已經穩了,等HR面或者等offer啦,所以特來分享一下俺的經歷哈哈哈,希望對大家有所幫助!!

心裡準備

沒有名校光環,沒有大廠實習經歷,沒有ACM金牌,一無所有,唯有堅持、努力、思考可以幫助我們

常見QA

這些俺就沒有研究太多了哈哈哈,就簡單扯一點點噗噗

前端技術學習路徑

我個人的話,是這樣子學的噗噗

graph LR
css-->js
js-->dom

React-->Webpack
Webpack-->Taro
複製程式碼

其實說實話,對於技術棧這些東東我倒也沒有太仔細的去研究過噗噗,大概就是以下這些吧:

  • React/Vue
  • Webpack
  • Babel
  • Html5
  • Css3
  • Typescript
  • Sass/Less
  • Git

基本都是平時可能做專案會碰到,比較常見的東東

前端框架學習

因為我是大一時候接觸React的,所以也是情有獨鍾,Vue也只是瞭解一些基本的原理還有使用方法,沒有深入研究。俺覺得如果要研究研究框架的話。就這樣子吧!

  1. 瞭解框架出現的原因
  2. 瞭解框架解決了那些問題/難點
  3. 瞭解框架基本語法、使用方式
  4. 瞭解框架的編碼規範
  5. 瞭解框架的坑、以及出現的原因
  6. 瞭解框架實現的原理
  7. 瞭解框架的原始碼
  8. 自己寫一個框架(劃掉

大廠演算法/筆試

這個東東其實我倒也沒有感受的太深,就是我的感受就是,位元組跳動的演算法要求會比別的大廠會高(來自一面掛的小菜雞)

筆試題

因為今年阿里內推沒有筆試,TX也還沒到常規批的筆試,就只經歷過美團、快手的筆試。大家可以去看一下他們的筆試題,反正俺自閉了~

基本就幾個方向吧,大家可以去leetcode瘋狂刷題打卡!

  1. 動態規劃
  2. 圖論
  3. DFS/BFS
  4. 貪心演算法
  5. 排序
  6. 陣列/字串

程式碼評測題/面試中的筆試

大家可以看看阿里跟TX的程式碼評測題,其實他們出題的感覺挺像的。基本流程都差不多

一般分為3 - 4題吧

  1. 第一題一般是一道leetcode難度easy/medium難度的演算法題,都是比較常見的吧,一般是連結串列/陣列/字串
  2. 第二、三題一般是結合實際情況的演算法題,今年常見的是DFS的題型,例如模擬css選擇器來找節點,或者求載入依賴的順序。
  3. 最後一題一般是一個程式碼綜合題,一般做不出來的,時間太短了,像什麼模擬貪吃蛇啊,或者寫一個React元件啊之類的

或者說可能是純實踐的操作題,這些基本都是我面試中遇到過的東東,例如:

  • 實現深拷貝
  • 實現觀察者模式/訂閱釋出
  • 實現下劃線形式轉換大駝峰(a_bb_ccc -> ABbCcc)
  • 實現排序
  • 實現函式柯里化
  • 實現函式扁平化

大廠前端的要求

這個的話,其實我感受不是很明顯,就我而言吧,我覺得他們想要的是,對原理的東西一定要了解/熟悉,有做一定的實踐。例如`:

面試官:webpack,babel有使用過嗎?
面試官:那你自己寫過嗎?

類似這種,不僅要我們瞭解,會使用,還需要知道一些原理,並且自己會加以改進。

無論什麼都是這樣的,再比如像是React。他們或許不會問你怎麼使用,他們喜歡問:

面試官:keys的作用,如果列表元素重新排序,是否會重新渲染
面試官:setState非同步or同步,平時有遇到過嗎
面試官:React的阻止冒泡怎麼樣的,跟原生有什麼區別

等等之類的東東,就是一些我們平時可能不會在意的小坑,或者需要注意的東西。需要我們不僅會用也要知道為什麼這樣用。

前端複習重點

當然還是基礎優先啦~

  • 網路
  • 瀏覽器
  • css
  • js
  • 效能
  • 框架

等等這些,就我而言,其實我也不知道什麼是重點,但是我覺得前端效能優化方面很多面試官都喜歡問

  • 常見的效能優化方式
  • 你如何發現效能不好
  • 如何發現記憶體洩漏
  • 怎麼提高首屏渲染速度
  • 如何優化介面訪問
  • 如何實現高幀率動畫
  • 效能優化的指標

等等這些,關於效能方面的東西,感覺會比較常問

個人建議

前期準備

  • 面試最重要還是得基礎紮實hhhh,例如前端相關的知識點,我們可以面經或者書籍來惡補!,基礎一定要紮實,做不到脫口而出也要思考一下吧大致的東東講出來。
  • 最重要還是得有自己專案,因為大廠更看重你的實踐能力,以及在實踐中的思考,難點的解決,所以我覺得有一個自己的專案,無論是在簡歷篩選或者是面試之中都很有用
  • 做好平時的積累、沉澱。例如可以自己總結一些難點,或者易錯的東東,發表一些部落格文章,在社群中與大家分享一下,這都是不錯的!
  • 一定要堅持,萬事開頭難,可能覺得知識點基礎都那麼多了,面試怎麼過嘛?但是付出的努力與回報是成正比的,你現在多努力,以後就會有多感謝自己當初的那份執著
  • 梳好頭髮,換好衣服(一位被leader吐槽粉色睡衣的小菜雞路過~)

不要緊張

面試大家都會緊張,這是肯定的,但是千萬別過於緊張。我這人本來就是容易緊張的,所以導致面試的時候,經常緊張得說不出話哈哈哈,特別是剛剛開始,前幾次的面試,哇,還是視訊面試,緊張的說不出話hhh直抖腿

所以俺建議吼~可以起來走一走,喝口水,面試前10分鐘可以看看B站,冷靜冷靜,就當做聊天一樣就可以啦!

體現思考

我們很多人面試的時候,我們或許都會選擇去看一些面經,很多基礎的知識點,的確看面經會更加方便、快捷。但是這也有一個弊端...

那就是不能體現我們的 ”思考過程與能力

舉個例子

image

TCP三次握手

面試官:你知道TCP三次握手嗎,你講一下吧~
小菜雞:客戶端傳送syn,服務端接收然後傳送syn + ack包給客戶端,客戶端接收後發一個ack,連線成功

emmm,很好,但是這個簡單的答案,但是會不會有所死板,更像是照著書本,標準答案念出來的

面試官:你知道TCP三次握手嗎,你講一下吧~

小菜雞:客戶端傳送syn,跟伺服器說“我要連線啦”,進入syn_send狀態。
服務端接收然後傳送syn + ack包給客戶端,跟客戶端說“我知道了,我這邊ok了”,進入syn_recv狀態。
客戶端接收後發一個ack,跟服務端說”我要連線咯!“,進入establish狀態,連線成功。

emmm,⑧錯⑧錯,帶有了一點點自己的理解在裡面,但是其實還可以加一點東東,可以再詳細解釋一下為什麼是三次握手,而不是兩次。

面試官:(給你個眼神)

小菜雞:因為三次是為了確定雙方的收發能力:第一次,確定了客戶端的傳送能力。第二次,服務端確定了自己的接受能力。第三次,確定了客戶端的接受能力與服務端的傳送能力。
再比如說,如果我們第一次握手,因為卡住了或者別的原因,導致連線請求沒有傳送出去,那麼客戶端會發起第二次連線請求,然後連線成功,之後斷開。這時候!!這時候!!如果第一次握手的請求不卡了,現在發起了連線,而如果只需要兩次握手,那麼現在客戶端與服務端就連線起來了,但是這時候客戶端並沒有東西要傳送,所以就導致服務端資源被佔用啦。

俺就是舉個例子,hhhh說的對不對俺也不知道噗噗。就大概是這種思路嘛,面試官往往只是為了推敲出候選人是否有足夠的思考能力,與技術潛力來承擔起工作的重任。這樣子可以很好的體現出我們的思考能力哈啊哈。

XSS和CSRF攻防

俺們再舉個例子哈哈哈,比如說現在問xss跟csrf,大噶會怎麼回答呢?

面試官:(開始你的表演)

小菜雞:csrf就是跨站頁面請求來進行攻擊,一般我們新增token來防禦,xss就是跨站指令碼攻擊,一般我們過濾一下script標籤啊這些就ok

我們不妨說多一點,發揮口才!!!

面試官:(開始你的表演)

小菜雞:csrf就是跨站頁面請求來進行攻擊,就比如我們現在登入了一個銀行的網頁,然後我們開啟新的標籤頁,點選了一些攻擊的網頁,這時候因為我們剛剛登入,cookie還沒有過期,我們剛剛點選的網頁就會進行csrf攻擊,利用cookie進行csrf攻擊,錢就沒了啦......

css就是跨站指令碼攻擊,分為XXX類,常見的比如現在有一個評論的元件,使用者輸入評論儲存進資料庫,然後別的使用者訪問的時候可以看到。如果這時候使用者植入惡意的js程式碼評論,我們儲存到資料庫中,那樣別的使用者訪問就會被攻擊啦!我們可以通過過濾尖角號,或者把他轉換成html實體來防禦......

舉舉例子~更加生動!面試官更能理解你的意思!

所以俺建議吼~我們看面經之後,或許可以總結一些例子,或者一些深入的東東,例如“為什麼”,“怎麼來的”這些東東,面試的時候可以發揮口才瘋狂吹!

適當引導

面試過幾輪之後,有了一定的經驗,你就會發現,面試官一般會跟著你說的東西,或者根據你的簡歷來進行提問。所以,其實我們可以適當的引導一下面試官問你熟悉的東東。比如......

面試官:優化效能?

小菜雞:balabala ... 重繪、迴流 ... balbala

面試官:那你說一下重回迴流吧~

小菜雞:(舒服了)

嘿嘿,可以通過一些關鍵詞來引導hhhh

面試官:記憶體洩漏?

小菜雞:記憶體洩漏有xxxx情況,我之前用React做一個專案,裡面有一個監聽滾動條,結果發現切換了頁面還在監聽,結果發現是沒有取消時間監聽,發生了記憶體洩漏,之後我通過xxx方法解決了

其實我們這裡可以引導面試官往幾個方面問

  1. 你的專案,難點等
  2. 使用hook的useEffect的return方法來取消事件監聽
  3. 還有哪些記憶體洩漏的情況,如何解決
  4. 如何發現記憶體洩漏

所以俺的建議吼,這裡只是舉一個簡單的例子,我們其實可以通過很多種方法,來引導面試官來問我們熟悉的東西,而不是被面試官帶進他自己的節奏,把你問倒hhhh

專案難點

如果有自己的專案,那麼有一個特殊的難點會顯得尤為重要(俺因為沒有,被懟的好慘hhhh)最好呢,是一個網上不能輕易找到的功能或者設計。這樣會凸顯自己~嗯!很強!就決定是你了。

或者是一個系統整體的架構之類的,體現出自己對於產品的理解很深哈哈哈。

再或者,可以針對自己現在的專案,總結出一個功能點計劃,現在沒有不代表未來沒有,也可以表現的出自己也瞭解過相關的知識,知道大體的方向,只不過現在還沒有實施,還在計劃之中,體現自己很有熱情!!

熱情熱情

熱情很重要嗷,這個部分科班非科班,本科還是研究生。無論是誰,熱情總能讓面試官對你有好的印象。無關時間長短,只是自己的心態熱情。對一個功能難點深入探究,對技術原理反覆推敲,為自己的專案作出多大多大的努力。俺覺得都是十分好的東東!

稍加思索

面試的時候,問到不會的東東很正常,但是我個人覺得不要立刻說不會,其實可以稍加思索,然後想一想問題前後的聯絡,然後說一下自己的理解。向面試官請求引導,看看能不能答出來。如果實在不行,也可以跟面試官說,這方面還需要加強,面試結束之後自己再查查資料補一補。學習的精神很重要。

虛心請教

很多人覺得面試官很凶,很有壓力,但其實我們應該是抱著學習的心態去面試的。面試只是查漏補缺的過程。我們面試結束之後,其實可以詢問面試官可否加一下好友之類的。然後可以詢問他一些人生的建議、技術的指導等等。厚著臉皮問,不要擔心被嫌棄就好啦哈哈哈。我就是這樣問一個面試官,才學到了很多東西,專案的難點,或者技術的思考之類的東東。

部分面經

阿里の盒馬X數字農業事業部

初面

初面是聊得最久的一次了,一個多小時了吧,不過初面的面試官真的很讓人感動一直在鼓勵我,“好啊好啊”,“沒關係沒關係”,啊太棒了,給俺這個小菜雞很多信心hhhh

  1. 輸入url到頁面展示
  2. 瀏覽器儲存
  3. 如何實現繼承
  4. 跨域,常用哪個,解釋一下
  5. 快取
  6. 重繪迴流
  7. 效能優化
  8. React優勢
  9. React生命週期
  10. React最佳實踐
  11. React新特性
  12. 如果列表元件要新增一些內容,例如標題,簡介等,你會怎麼對程式碼進行修改(容器元件 -> 展示元件)
  13. csrf 和 xss
  14. flex
  15. 判斷是否為陣列
  16. typeof arr === 'object'
  17. 瀏覽器事件迴圈,node事件迴圈
  18. 事件委託
  19. webpack流程,外掛
  20. koa原始碼
  21. koa洋蔥模型
  22. mobx原理
  23. 首屏優化
  24. async/await Promise
  25. 盒模型
  26. babel原理
  27. Taro原理

一面

一面俺就放放筆試題還有俺自己做的情況吧哈哈哈哈,一面的面試官跟俺說拓撲排序,俺才知道原來還有這種東西(流淚...

筆試題目

  1. 給定一個連結串列,判斷連結串列中是否有環,比如下圖這種即為有環連結串列。
    image
    加分項:使用空間複雜度 O(1) 實現

  1. 分析一個專案的依賴結構,並按依賴優先順序排序。 已知一個專案的依賴結構,期望在前端通過 loader 的方式非同步載入相關的元件,而我們期望依賴在載入的過程中:
  • 每一個依賴被載入後都會被立刻執行,那麼如果要爭取載入一個依賴,則其子依賴都應該優先被載入
  • 每一個依賴不希望在錢多出現冗餘的情況,若依賴出現多版本的情況,則預設使用更新的版本,比如已知專案依賴結構為(其中 @ 後面的為依賴版本號):
ProjectA
- a@0.1.0
    - d@0.2.0
    - c@0.1.0
- b@0.1.1
    - e@0.1.2
    - c@0.1.2
- c@0.2.0
複製程式碼

則其中一種輸出的依賴優先順序排序為:
['d@0.2.0', 'c@0.2.0', 'a@0.1.0', 'e@0.1.2', 'b@0.1.1']

輸出分析: 為了讓 a 載入後可以爭取執行,則必須先載入 d 和 c,b 的載入同理,又因為在整個依賴關係下,c 的最新版本為 0.2.0 於是有了如上的輸出結果。


  1. 請用 React 實現一個搜尋框元件,功能包括:
  • 輸入文字字數限制
  • 可配置輸入文字約束,比如僅限輸入數字
  • 使用者輸入時可支援關鍵字搜尋,並出現下拉框展示相關項
    image

俺的答案

  1. 第一題leetcode原題來的,環形連結串列好像是,可以用快慢指標或者簡單的集合
const cycle1 = function (node) {
  let set = new Set()
  while (node) {
    if (set.has(node))
      return true
    else
      set.add(node)
    node = node.next
  }
  return false
};



const cycle2 = function (node) {
  let start = node
  let end = node.next
  while (start !== end) {
    // 沒有環就null
    if (end === null || end.next === null) return false
    start = start.next
    end = end.next.next
  }
  return true
}
複製程式碼
  1. 第二題的話我拿到題目第一個想到的就是DFS來尋找那些依賴,然後最後再對依賴這些進行版本比較(其實應該用集合、還有拓撲排序來優化)

這題有大佬在評論區指出錯誤啦!之前那個版本是比較字串,但是忽略了多位數字版本的情況,例如b@0.2.22b@0.2.3,結果應該是前者,但之前版本是輸出後者,現在修改了一下!好嘞!

function update(npmList) {
  let versions = {}
  let res = []

  // 比較版本號
  function cmp(a, b) {
    const versionListA = getVersion(a).split('.')
    const versionListB = getVersion(b).split('.')
    for (let index = 0; index < 3; index++) {
      const versionA = parseInt(versionListA[index])
      const versionB = parseInt(versionListB[index])
      if (versionA > versionB) return a
      else if (versionA === versionB) continue
      else return b
    }
    return a
  }

  // 獲得版本號
  function getVersion(str) {
    return str.substr(str.indexOf('@') + 1)
  }

  function dfs(npmList) {
    if (npmList.length === 0) return

    npmList.forEach((npm) => {
      const { name, deps = [] } = npm
      // 先遍歷他們的依賴
      dfs(deps)
      let key = name.substr(0, name.indexOf('@'))
      // 如果依賴不存在則新增,若已存在,則取最新版
      if (!versions[key]) {
        versions[key] = name
      } else {
        versions[key] = cmp(versions[key], name)
      }
      // 新增進最後的載入列表
      res.push(key)
    })
    return
  }
  dfs(npmList)
  // 去除重複項,然後將包名轉換為依賴名,eg: a -> a@0.1.0
  return [...new Set(res)].map(key => versions[key])
}
複製程式碼
  1. 第三題的話,我粗略寫了一下噗,寫的也不是很好,用React整的

不知名本科菜雞の春招前端心路歷程(阿里,騰訊,美團) | 掘金技術徵文

// 第三題React部分第三題React部分第三題React部分第三題React部分第三題React部分

import React, { Component } from 'react';
import './input.css'

function debounce(fn, delay = 500) {
  let timeout = null
  return function (e, ...args) {
    e.persist && e.persist()
    timeout && clearTimeout(timeout)
    timeout = setTimeout(() => {
      fn.call(this, e, ...args)
    }, delay)
  }
}

class Tips extends Component {
  render() {
    const { tipsList } = this.props
    return tipsList && tipsList.length !== 0 ? (
      <div className="tips__container">
        {tipsList.map((item, index) => {
          return (
            <a href="#" key={index} className="link">{item}</a>
          )
        })}
      </div>
    ) : <div></div>
  }
}

export default class Input extends Component {
  constructor(props) {
    super(props);
    this.state = {
      keyWords: [
        '前端工程師1', '前端高階開發1', '後端工程師1', '測試開發1', '專案主管1', 'dress', 'Recent', '123456', 'awdad1'
      ],
      inputValue: '',
      inputType: 'text',
      inputMaxLen: 20,
      wordsList: []
    }
    this.handleInput = debounce(this.handleInput, 200)
    this.handleMaxLenChange = debounce(this.handleMaxLenChange, 400)
  }

  handleInput = (e) => {
    const { target: { value } } = e
    const { keyWords } = this.state
    const tipsList = !value
      ? []
      : keyWords.filter(item => {
        const res = item.search(new RegExp(value, 'i'))
        return res !== -1
      })
    this.setState({
      inputValue: value,
      tipsList
    })
  }

  handleTypeClick = (e) => {
    const { target: { name } } = e
    this.setState({ inputType: name })
  }

  handleMaxLenChange = (e) => {
    const { target: { value } } = e
    const { inputValue } = this.state
    const newInputValue = inputValue.substr(0, +value)
    // 如果設定最大長度小於現在關鍵詞的長度,則擷取一下
    this.input.value = newInputValue
    this.setState({ inputMaxLen: value, inputValue: newInputValue })
  }

  render() {
    const { tipsList, inputType, inputMaxLen } = this.state
    return (
      <div className="container">
        <div className="control__container" onClick={this.handleTypeClick}>
          <button name="text">文字</button>
          <button name="number">數字</button>
          <span>最大長度: </span>
          <input type="number" placeholder="預設: 20" onInput={this.handleMaxLenChange} />
        </div>
        <div className="input__container">
          <div className="input__wrap">
            <input
              ref={input => this.input = input}
              placeholder="請輸入關鍵詞"
              type={inputType}
              maxLength={inputMaxLen}
              onInput={this.handleInput} />
            <button>搜尋</button>
          </div>
          <Tips tipsList={tipsList} />
        </div>
      </div>
    )
  }
}
複製程式碼
// 第三題CSS部分第三題CSS部分第三題CSS部分第三題CSS部分第三題CSS部分第三題CSS部分


.container {
  width: 600px;
  height: 400px;
  margin: 0 auto;
  padding: 30px;
  background: #fff;
}

.input__container {
  margin-top: 30px;
}

.input__wrap {
  display: flex;
  align-items: center;
}

.input__wrap input {
  box-sizing: border-box;
  width: 85%;
  height: 50px;
  padding: 0 10px;
  border: #666 1px solid;
  border-right: 0;
  outline: none;
}

.input__wrap button {
  cursor: pointer;
  box-sizing: border-box;
  width: 15%;
  height: 50px;
  color: #fff;
  font-size: 20px;
  border: none;
  border: #666 1px solid;
  outline: none;
  background: #1890ff;
}

.control__container {
  display: flex;
  align-items: center;
}

.control__container button {
  cursor: pointer;
  width: 50px;
  height: 30px;
  margin-right: 10px;
  color: #fff;
  outline: none;
  border: #333 1px solid;
  border-radius: 8px;
  background: #1890ff;
}

.control__container span {
  margin-left: auto;
  margin-right: 10px;
  color: #666;
  font-size: 14px;
}

.tips__container {
  overflow-y: scroll;
  max-height: 200px;
  border: #333 1px solid;
  border-top: 0;
}

.tips__container .link {
  display: block;
  height: 30px;
  padding: 5px 10px;
  color: #666;
  line-height: 30px;
  text-decoration: none;
}

.tips__container .link:hover {
  color: #fff;
  background: #666;
}

input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
  display: none;
}
複製程式碼

二面

二面主要是結合專案來問的,抓住一個功能發散開來,例如我專案的聊天室的功能,嚇得我好慌好慌hhh,不過面試官人很好一直引導我,特別是那些場景題,引導我去思考,啊,太感動了!!!

  1. 專案の各種東東
  2. 聊天私聊怎麼做
  3. 聊天記錄未讀訊息怎麼做
  4. 聊天離線資訊處理
  5. session會話管理如何實現(使用者登入後,開啟新標籤頁輸入url訪問資源)
  6. 訪問資源許可權控制
  7. 事件佇列題
  8. websocket如何連線
  9. 做題系統元件的設計與擴充(擴充更多型別的題目,如何設計元件)
  10. 使用者鑑權系統設計
  11. 為什麼密碼錶跟使用者資訊表分開放
  12. 資料庫表的設計

三面

這一面也是結合專案來問的。啊,三面的面試官真的太好了,期初我的小專案沒什麼難點(我都以為涼透透了嗚嗚嗚),然後面試官給了提了幾個建議,讓我多去深入思考思考,面試完之後去找他請教問題,也一直很有耐心給我指導指導,啊,太棒了吧?

  1. 專案の各種東東
  2. 飛豬為什麼掛了
  3. 專案難點
  4. 小程式登入怎麼做的
  5. 封裝了什麼元件
  6. 建議:線上閱卷、批註、修改錯別字等(canvas繪製)
  7. 建議:實時監控每個同學的進度(選擇答案後之後教師端更新/攝像頭監控)
  8. a與b聊天,將他們的記錄,多選,然後合併發給c,如何設計
  9. 除了編譯成小程式,有試過app嗎

四面

四面應該是總監面,還是得感謝三面的面試官給我提的建議,之後做出來之後,發現這個東東可以作為專案的一個難點來吹哈哈哈!四面主要還是圍繞專案來問,我個人覺得關注的更是自己的思維、對技術的認識、對自己未來的發展規劃等巨集觀的內容

就是這個小功能,canvas實現作業批註等功能

  1. 專案難點(canvas繪製公式
  2. websocket實現,聊天功能的實現(心跳檢測,斷線重連
  3. 專案の細節
  4. 聊天資訊的一致性,時序性
  5. 目標、具體想通過實習學到什麼
  6. 技術規劃,之後學些什麼

五面

五面是交叉面,心驚膽跳嗚嗚嗚,希望不要掛我...五面問的大多是基礎方面的內容,不過也是結合專案來問的,這一面面試官主要關注的是效能方面的內容,例如資料埋點啊、頁面載入時間、介面響應時間等一系列關於效能方面的問題,他希望的是資料量化的一個東東,具體的實現,達成了什麼目標等

  1. 專案做了那些事情
  2. 小程式執行池
  3. 小程式和H5的區別
  4. 快取存在哪(強快取、協商快取分別通過什麼欄位儲存
  5. React與Vue的區別
  6. React的優勢
  7. Taro編譯的機制
  8. Taro支援的端有哪些
  9. node的機制、優勢
  10. 專案的難點,如何解決,遇到的問題
  11. 如何監控效能
  12. 嘗試做了哪些效能上的優化
  13. 收集使用者資訊?資料埋點?效能指標?量化指標?
  14. 資源大小,載入速度,頁面渲染時間,介面訪問時間
  15. 如何優化node後臺的介面(sql優化,表結構重寫
  16. 使用什麼伺服器,部署在什麼作業系統上
  17. 多人同時訪問介面測試過嗎?最高承載多少
  18. webpack如何減小資源打包大小
  19. 擅長什麼
  20. 你的優勢是什麼
  21. 目標?規劃?

騰訊のWXG開放平臺小程式基礎部

一面

一面是筆試 + 面試,俺也放放題目跟俺的答案吧!

筆試題目

  1. 實現⼀個函式 reverse(a, n) ,反轉⼀個含有 n 個整數的陣列 a(直接在陣列a上操作,元素交換次數 儘可能少,不能使⽤js Array 類內建屬性和⽅法)。

  1. 實現⼀個函式 countLongest(tree) ,輸⼊⼀棵⼆叉樹,返回⼆叉樹中距離最⻓的兩個葉⼦節點之間 的距離。
var x = [0, 1, 2, 3]
reverse(x, 4) // x = [3, 2, 1, 0]
var y = [1, 2, 3, 4, 1]
reverse(y, 5) // y = [1, 4, 3, 2, 1]
var tree1 = {
  value: 1,
  left: {
    value: 2
  },
  right: {
    value: 3
  }
}
countLongest(tree1) // 2
var tree2 = {
  value: 1,
  left: {
    value: 2,
    left: {
      value: 3,
      left: {
        value: 6
      }
    },
    right: {
      value: 4
    }
  },
  right: {
    value: 5
  }
}
countLongest(tree2) // 4
複製程式碼

  1. 在前端開發中,通常會把多個js⽂件合併成⼀個⽂件,以減少⽹絡請求次數,達到優化載入速度的⽬ 的,但是當⽂件之間存在依賴關係時,對js合併的順序,會有⼀定的要求,⽐如 A.js 依賴了 B.js,那打 包後的⽂件,B.js 需要排在 A.js 的前⾯。 實現⼀個函式 resolve(tree) ,根據js的依賴關係樹 tree,輸出合理的打包順序的陣列(結果可能不 唯⼀,輸出其中⼀種即可)。

樣例

var tree1 = {
  name: 'main.js',
  require: [{
    name: 'A.js'
  }, {
    name: 'B.js'
  }]
}
resolve(tree1) // ['A.js', 'B.js', 'main.js']
var tree2 = {
  name: 'page.js',
  require: [{
    name: 'A.js',
    require: [{
      name: 'B.js',
      require: [{
        name: 'C.js'
      }]
    }]
  }, {
    name: 'D.js',
    require: [{
      name: 'C.js'
    }, {
      name: 'E.js'
    }]
  }]
}
resolve(tree2) // ['C.js', 'E.js', 'D.js', 'B.js', 'A.js', 'page.js']
複製程式碼

  1. 給定⼀個整數陣列 a,實現⼀個函式 countMax(a) ,計算出從 a 中選擇出多個不相鄰元素組成最⼤的 和是多少。

樣例

var x = [1, 4, 5, 3]
countMax(x) // 7
var y = [3, 12, 6, 2, 4]
countMax(y) // 16
複製程式碼

俺的答案

  1. 就是簡單的倒置hhh
function reverse(arr) {
  let len = arr.length
  for (let start = 0; start < Math.floor(len / 2); start++) {
    let end = len - start - 1;
    [arr[start], arr[end]] = [arr[end], arr[start]]
  }
  return arr
}
複製程式碼
  1. 這題是leetcode原題好像,就算算深度
function countLongest(tree) {
  if (!tree) return 0
  let res = 0

  function dfs(node) {
    if (!node) return 0
    const leftMax = dfs(node.left)
    const rightMax = dfs(node.right)
    res = Math.max(leftMax + rightMax, res)
    return Math.max(leftMax, rightMax) + 1
  }
  dfs(tree)
  return res
}

console.log(countLongest({
  value: 1,
  left: {
    value: 2
  },
  right: {
    value: 3
  }
}))
console.log(countLongest({
  value: 1,
  left: {
    value: 2,
    left: {
      value: 3,
      left: {
        value: 6
      }
    },
    right: {
      value: 4
    }
  },
  right: {
    value: 5
  }
}))
複製程式碼
  1. 第三題是不是很眼熟哈哈哈,跟盒馬一面的筆試題好像(其實我發現很多面試筆試題都有這相關的影子)還是DFS來找
function resolve(npmList) {
  const res = []

  function dfs(npmList) {
    if (npmList.length === 0) return

    npmList.forEach((npm) => {
      const { name, require = [] } = npm
      dfs(require)
      !res.includes(name) && res.push(name)
    })
    return
  }
  dfs(npmList)
  return res
}


console.log(resolve([{
  name: 'page.js',
  require: [{
    name: 'A.js',
    require: [{
      name: 'B.js',
      require: [{
        name: 'C.js'
      }]
    }]
  }, {
    name: 'D.js',
    require: [{
      name: 'C.js'
    }, {
      name: 'E.js'
    }]
  }]
}]))
複製程式碼
  1. 用動態規劃來找
function countMax(arr) {
  const len = arr.length
  const dp = new Array(len).fill(0);
  dp[0] = arr[0]
  dp[1] = arr[1]
  dp[2] = arr[0] + arr[2]
  for (let i = 3; i < len; i++) {
    dp[i] = arr[i] + Math.max(dp[i - 2], dp[i - 3])
  }
  return Math.max(dp[len - 1], dp[len - 2])
}

console.log(countMax2([1, 4, 5, 3]))
console.log(countMax2([3, 12, 6, 2, 4]))
複製程式碼

面試內容

  1. 專案
  2. 為什麼用token不用cookie
  3. 跨域(前端跟前端的跨域,iframe之間)
  4. xss
  5. React與Vue的對比
  6. Taro與其他多端框架
  7. 主要還是專案發散
  8. 如何實現輪播圖

二面

二面基本都是一些基礎吧,但是就有些地方會深入去挖這樣子

  1. https原理,握手過程(何時對稱/非對稱,誰先誰後,為什麼這樣)
  2. 常見的優化
  3. webp格式優化了多少
  4. 快取以鍵值形式存在瀏覽器,鍵是什麼,值是什麼
  5. 設計一個快取策略,(hash值)
  6. React的key
  7. React與Vue的區別
  8. Taro與小程式官方框架的區別
  9. 小程式執行池
  10. React列表key固定,順序調換會渲染嗎(不會)
  11. 如何判斷效能瓶頸
  12. 專案の各種東東

三面

三面感覺還不夠二面難,問的比較常見吧應該說,然後也是問問專案這樣子

  1. 演算法:判斷陣列中是否存在兩個數相加等於目標值,給出多種思路與時間空間複雜度(暴力迴圈,排序後迴圈剪枝,動態規劃)
  2. es6的class如何實現私有變數(symbol + 閉包)
  3. 如何進行效能監控
  4. 常見的效能優化方法
  5. 記憶體洩露如何發現,如何解決
  6. 垃圾回收機制
  7. 跨域(cors + jsonp + 其他不常見的跨域方法)
  8. 瀏覽器快取
  9. 實現深拷貝,深拷貝的用途
  10. xss、csrf
  11. cookie與token的工作原理,區別,如何設計
  12. http1.1、http2.0
  13. http無狀態
  14. websocket是什麼協議,如何連線
  15. websocket有什麼優勢,對比輪訓呢
  16. 事件迴圈
  17. setTimeout是否準時,如果不是則應該提前還是延遲
  18. webpack流程
  19. 常見的http狀態碼
  20. babel原理、taro原理
  21. map中的鍵值會不會被回收(weakMap,weakSet等)
  22. 專案....難點、設計、收穫
  23. 平時如何學習

美團到店事業部

一面

  1. 專案
  2. 原型鏈
  3. 繼承
  4. instanceof
  5. 事件迴圈
  6. 非同步任務有哪些,底層如何實現(不會
  7. websocket
  8. 輪詢的弊端
  9. websocket的弊端與優勢
  10. TCP三次握手
  11. 為什麼需要三次握手
  12. 如果兩次握手會發生什麼,保持不必要的連結主要是瀏覽器端還是服務端收到影響大
  13. TCP的擁塞問題(不會
  14. xss和crsf
  15. 跨域(種類,如何使用
  16. 同源策略
  17. 跨域為了解決什麼問題
  18. cookie和token
  19. 如何使用token,設計
  20. 意向城市
  21. 為什麼選擇前端
  22. 前端學習的規劃
  23. koa中介軟體模型,洋蔥模型
  24. 三道演算法
1. 合併兩個有序連結串列
2. 找出陣列第K大的數
3. 晨晨是個愛跑步的孩子,這一天,他準備跑正好k米。
他所在的城市的道路可以看做n個點,m條無向邊組成的圖,
每條邊有一個固定的長度。  晨晨有強迫症,

他跑步前往一個目的地一定要走最短路(當然有多條最短路就可以隨意選擇了)。  
晨晨希望知道,他正好跑k米能走到的目的地的個數。


注意,目的地可能在圖中的點和邊上,且該目的地距離晨晨的起點的最短路正好k米。 
若k大於所有路徑之和自然不存在這樣的目的地,輸出結果自然為0。

複製程式碼

二面

  1. function和箭頭函式
  2. 箭頭函式有什麼特殊的地方
  3. React的生命週期哪些是不安全的,為什麼
  4. 為什麼會出現React Hooks
  5. Memo跟useCallback的區別與聯絡
  6. hooks模擬生命週期
  7. 記憶體洩漏
  8. 如何監控記憶體洩漏,如何發現(全域性變數,閉包,監聽事件,定時器
  9. SPA的優缺點
  10. 首屏載入如何優化
  11. webpack的plugin跟loader的區別
  12. css垂直居中
  13. margin相對於誰
  14. 移動端用什麼佈局
  15. 如何還原設計稿
  16. em、rem
  17. margin-top百分比相對於什麼
  18. 圖片格式之間的區別
  19. 如何檢測瀏覽器不支援webp(img onerror
  20. Promise的reject跟catch,場景,你如何使用
  21. class 與 function的區別
  22. class實現靜態變數
  23. for in 和 Object.keys的區別
  24. 類繼承的特點
  25. ES6的Map與物件有什麼區別
  26. git rebase/stash/commit
  27. 不用div如何包裹多個元素(Fragment,<><>).
  28. 原型鏈,作用,如何實現,原理
  29. 盒模型
  30. 筆試題:陣列扁平化排序去重
  31. 筆試題:實現柯里化函式

三面

  1. 專案成就,經歷,心得(瘋狂追問
  2. css移動方塊(css3,setInterval,requestAnimationFrame)
  3. 為什麼requestAnimationFrame能夠做到60幀
  4. javascript引擎,v8引擎,垃圾回收
  5. v8引擎跟別的有什麼區別
  6. 程式碼編譯大致流程
  7. babel
  8. http跟https區別,具體
  9. 如果https發來證照,但是我沒有CA的公鑰怎麼辦(用久的請求CA新的
  10. 堆跟棧的區別
  11. 還有別的什麼記憶體塊
  12. 垃圾回收
  13. 如何手動垃圾回收(定時器,監聽事件,物件等
  14. 兩個this指向的問題
  15. 筆試部分
實現自定義陣列下的排序方法(掛載到陣列原型)
實現下劃線字串轉換大駝峰(asf_ad_ada_adwa -> AsfAdAdaAdawa)
實現釋出訂閱(on,off,emit,once)
複製程式碼

相關文章