記錄一次螞蟻金服前端電話面試

座標杭州,18年畢業,算上實習一年半開發經驗。是外派的面試,後面兩面都是阿里的面試官。css

原本是給我發的在線測評,可是那邊服務器出現問題,我一直打不開網頁,最後只好以電話問答的形式。下面我寫的大部分都是測評裏的題目,部分是電話裏新增的題目。。。html

  1. 儘可能使用盡量多的方式實現子元素的垂直水平居中

    <div class="father">
        <div class="child">  
        </div>
    </div>
    
    <style> .father { width: 300px; height: 300px; } .child { } </style>
    複製代碼

child分不少種狀況,大體說一下react

  • 行內元素:text-align + line-height
.father{
  text-align: center;
  line-height: 300px;
}
複製代碼
  • 定寬定高:absolute + margin
.father{
  position: relative;
}
.child{
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -150px 0 0 -150px;
}
/* 或者 */
.child{
  position: absolute;
  left: 0;
  top: 0; 
  right: 0; 
  bottom: 0;
  margin: auto;
}
複製代碼
  • 不定高:absolute + translate
.father{
  position: relative;
}
.child{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
}
複製代碼
  • 不定高:flex
.father{
  display: flex; 
}
.child{
  margin:auto;
}
/* 或者 */
.child{
  justify-content: center;
  align-items: center;
}
複製代碼
  • table方式:
.father{
  display: table; 
}
.child{
  display: table-cell;
  text-align: center;
  vertical-align: middle;
}
複製代碼
  1. 儘量多的方式實現以下三欄佈局,要求 .main 在中間顯示

<div class="container">
  <div class="main"></div>
  <div class="sub"></div>
  <div class="extra"></div>
</div>
複製代碼
  • 浮動
  • flex佈局:利用order屬性(排序,這個沒答上來)
  • gird佈局:grid-template-areas
  1. 執行下面的代碼,輸出結果是什麼?

console.log(+false) // 0, 這裏是一元運算符進行的弱類型轉換,相對應的 +true 則返回 1
console.log('1' + 2 + '3' + 4) // '1234' 遇到字符串就會拼接
console.log(4 + 3 + 2 + '1')  // '91' 先加在一塊兒再拼接
複製代碼
  1. 運行下面的代碼,輸出什麼?

var x = 3;
var foo = {
  x: 2,
  baz: {
    x: 1,
    bar: function() {
      return this.x;
    }
  }
}
var go = foo.baz.bar;

console.log(go());  // 3
console.log(foo.baz.bar()); // 1
複製代碼

這題考的是this的指向:面試

this由調用者提供,由調用函數的方式來決定。若是是一個對象調用的函數,則this指向該對象,好比foo.baz.bar()。若是函數獨立調用好比go(),那麼該函數內部的this,則指向undefined。可是在非嚴格模式中,它會被自動指向全局對象window。算法

  1. 實現如下函數,使得輸入的字符串逆序輸出

function reverse(str) {
  let res = str.split('');
  return res.reverse().join('');
}

reverse('hello world!'); // output: '!dlrow olleh'
複製代碼

進階問題編程

'hello world!'.reverse();  // output: '!dlrow olleh'
複製代碼
  • 這個問題須要給String的原型上添加方法,可是要考慮有一些改造:
String.prototype.reverse = function reverse() {
  let res = this.split('');
  return res.reverse().join('');
}
複製代碼
  1. 實現sleep 函數

要求用法:redux

/** - 使當前運行的異步操做(promise 或者 async)中止等待若干秒 - - @param ms */
(async () => {
  console.log('hello')
  await sleep(2000) // 等待兩秒
  console.log('world')
})()
複製代碼
const sleep = (ms) => {
  new Promise(resolve, reject) {
    setTimeOut(() => {
      resolve(); // 大體這樣?
    }, ms)
  }
}
複製代碼
  1. 實現throttle 節流函數

    用法:api

    const throFun = () => console.log('hello');
    const thro = throttle(throFun, 300);
    document.body.onscroll = () => {
      thro();  // 調用至少間隔 300 毫秒纔會觸發一次
    }
    複製代碼
    /** - 頻率控制,返回函數連續調用時,action 執行頻率限定爲 1次 / delay - @param delay {number} 延遲時間,單位毫秒 - @param action {function} 請求關聯函數,實際應用須要調用的函數 - @return {function} 返回客戶調用函數 */
    function throttle(action, delay) {
      var previous = 0;
      // 使用閉包返回一個函數而且用到閉包函數外面的變量previous
      return function() {
        var _this = this;
        var args = arguments;
        var now = new Date();
        if(now - previous > delay) {
            action.apply(_this, args);
            previous = now;
        }
      }
    }
    複製代碼
  2. 實現debounce 防抖函數

    用法:數組

    const throFun = () => console.log('hello');
    const thro = debounce(throFun, 300);
    document.body.onscroll = () => {
      thro();  // 若一直調用則不會執行,空閒時間大於 300 毫秒纔會執行
    }
    複製代碼
    /** - 空閒控制 返回函數連續調用時,空閒時間必須大於或等於 delay,action 纔會執行 - @param delay {number} 空閒時間,單位毫秒 - @param action {function} 請求關聯函數,實際應用須要調用的函數 - @return {function} 返回客戶調用函數 */
    function debounce(action, delay) {
      var timer; // 維護一個 timer
      return function () {
          var _this = this; // 取debounce執行做用域的this
          var args = arguments;
          if (timer) {
              clearTimeout(timer);
          }
          timer = setTimeout(function () {
              action.apply(_this, args); // 用apply指向調用debounce的對象,至關於_this.action(args);
          }, delay);
      };
    }
    複製代碼
  3. 數組去重有哪些方法?

const arr = [1,2,3,4,4,3,2,1];
// 方法一:new Set ES6
return [...new Set(arr)]; // 這裏又問到我...的用法

// 方法二:雙層for循環 (而後說這樣性能很差,讓我只用一層for循環的方法)
function unique(arr){
  var res=[];
  for (var i = 0; i < arr.length; i++) {
    for (var j = i+1; j < arr.length; j++) {
      if (arr[i] === arr[j]) {
        ++ i;
        j = i;
      }
    }
    res.push(arr[i]);
  }
  return res;
}

// 方法三:單層for循環 + indexOf
function unique(array){
    var res = [];
    for(var i = 0; i < array.length; i++) {
        //若是當前數組的第i項在當前數組中第一次出現的位置是i,才存入數組;不然表明是重複的
        if (array.indexOf(array[i]) === i) {
            res.push(array[i])
        }
    }
    return res;
}
// 方法三點三:或者這樣
function unique(array){
    let res = [];
    for(var i = 0; i < array.length; i++) {
        if (res.indexOf(array[i]) === -1) {
            res.push(array[i]);
        }
    }
    return res;
}

// 方法四:面試官說若是能夠容忍改變原有數組的狀況下,怎麼改進性能更好
function unique(array){
    // 注意這裏必定要倒敘for循環,不然會出現問題
    for(var i = array.length - 1; i > 0; i--) { 
        if (array.indexOf(array[i]) !== i) {
            array.splice(i, 1);
        }
    }
    // 由於少聲明一個變量,節省了內存空間(雖然能夠忽略不計,可是面試嘛~)
    return array;
}
複製代碼
  1. 場景題,考察事件代理,事件監聽,DOM自定義屬性等

題目描述:promise

  • 網頁中有一個元素A,它有個data-href屬性,裏面存放一個連接地址🔗
  • 實現一個函數,當任意點擊時,若是點擊的元素就是A或其上層節點中找到A,則進行連接跳轉

實現思路:

  • 首先給window添加點擊事件的監聽,而後先聲明一箇中間變量targetNode記錄節點
  • 而後循環判斷當前節點targetNode是否存在data-href屬性
  • 若是存在則進行跳轉,break。不存在則將該節點的父節點賦值給targetNode
  • 一直循環到判斷targetNode是最外層節點爲止

面試事後整理的代碼:

window.addEventListener('click', (e) => {
    let targetNode = e.target
    while (targetNode !== document) { // 只要當前節點不是最外層document
        console.log(targetNode)
        if (targetNode.getAttribute('data-href')) { // 其實用hasAttribute更合適
            window.open(targetNode.dataset.href)
            break
        } else { // 沒找到就繼續往上找
            targetNode = targetNode.parentNode
        }
    }
})
複製代碼

總結:

  • 感受這道題出的很好,回答過程當中面試官也一直引導個人思路,好比最開始我想到判斷節點是否爲上下級關係的方法用DOM的contains()方法,而後面試官考慮性能,最好用原生api。而後我就說用parentNode。後來我查了一下MDN,發現contains這個方法就是原生的api,IE5以上就支持了:
    contains兼容性
    可是這也不是重點,重點是用contains這個方法不能實現這個場景,由於你須要父節點(上層節點)是已知的。但這個場景是經過已知子節點(點擊事件返回的target)來向上尋找節點。
  • 我說到用dataset獲取自定義屬性的時候,面試官說考慮到兼容性,有沒有別的方法。我回答getAttribute()
  • 在說怎麼一層一層的往上找節點的時候,最開始我想到了用遞歸調用函數,面試官立即打斷我說沒有必要,並且浪費性能。而後提示我說有什麼循環的方法。最後想到了while
  1. 其餘問題

  • ES6數組有哪些方法
  • React使用中用過哪些狀態管理工具,緊接着問了redux和mobx的區別,面試遇到三四次了,故總結一下:

1.Redux 鼓勵一個應用只用一個 Store,Mobx 鼓勵使用多個 Store; 2.Redux 是函數式編程,而Mobx的模式是面向對象的; 3.Redux 使用「拉」的方式使用數據,這一點和 React是一致的,但 Mobx 使用「推」的方式使用數據; 4.Redux 鼓勵數據範式化,減小冗餘,Mobx 允許數據冗餘,但一樣能保持數據一致。 5.Redux更嚴格,必須調用reducer觸發action來改變state, Mobx 最初的一個賣點就是直接修改數據,可是實踐中你們仍是發現這樣無組織無紀律很差,因此後來 Mobx 仍是提供了 action 的概念。和 Redux 的 action 有點不一樣,Mobx 中的 action 其實就是一個函數,不須要作 dispatch。若是想強制要求使用 action,禁止直接修改 observable 數據,使用 Mobx 的 configure,以下:

import {configure} from 'mobx';

configure({enforceActions: true});
複製代碼
  • 讓講了一下react的虛擬DOM,簡單講一下diff算法原理
  • React中key的做用
相關文章
相關標籤/搜索