前端JS面試題

前端面試題精選

1.memorize函數實現應用

首先什麼是memorize函數,memorize直譯:記憶,緩存等意思,到了計算機層面就翻譯爲緩存函數,緩存函數就是把計算的結果,存在函數中,當再次調用的時候就能夠直接調用。這種方法就是用空間來換取時間javascript

const memorize = function(fn) {
        const cache = {}
        return function(...args) { // 參數值,是一個數組,數組的值是須要計算的值
            const _args = JSON.stringify(args)
            return cache[_args] || (cache[_args] = fn.apply(fn, args)) 
            // 緩存函數的核心判斷依據,傳入的鍵名對應的鍵值爲null 則調用add方法 反之從cache中拿取
        }
    }
    const add = function(a) {
        return a + 1
    }
    const adder = memorize(add) // memorize只調用一次 後面adder調用的都是return的函數
    adder(1) // 2    cache: { '[1]': 2 }
    adder(1) // 2    cache: { '[1]': 2 }
    adder(2) // 3    cache: { '[1]': 2, '[2]': 3 }

2. bind,apply,call的區別和實現

javascript 權威指南上的解釋是: call()、apply()能夠看作是某個對象的方法,經過調用方法的形式來間接調用函數。bind()就是將某個函數綁定到某個對象上。前端

var obj = {
        x:1
    }
    function foo() {
        console.log(this.x)
    }
    foo.call(obj)  //1

call()和apply()的第一個參數相同,就是指定對象,他們的根本區別就在於傳入的參數。
call傳入參數形式爲call(obj, 1, 2, 3)
apply傳入參數形式爲apply(obj, [1,2,3])vue

bind()方法和前二者不一樣在於:bind()方法會返回執行上下文被改變的函數,而不會當即執行,而前二者是直接執行該函數。他的參數和call()相同.java

3.數組去重

去重方法有不少種,經常使用必需會寫的幾種去重方法有

1. 遍歷去重
2. json鍵名不惟一去重
3. new Set()去重

3.1 遍歷去重

let arr = [1, 2, 3, 4, 5, 6, 7, 7, 7, 3, 111, 1, 3]

    for (let i = 0; i < arr.length; i++) {
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[i] == arr[j]) {
                arr.splice(j, 1)
                i = i - 1
            }
        }
    }

3.2 json鍵名去重

let arr = [1, 2, 3, 4, 5, 6, 7, 7, 7, 3, 111, 1, 3]
    let obj = {}
    let result = []
    
    for(let i = 0 ; i < arr.length; i++) {
        obj[arr[i]] = null
    }
    
    for(let key in obj) {
        result.push(key)
    }

3.3 new Set()去重

let arr = [1, 2, 3, 4, 5, 6, 7, 7, 7, 3, 111, 1, 3]
    let newArr = new Set(arr) // 返回一個set對象
    let result = []
    
    newArr.forEach(val => {
        result.push(val)
    })

4.數組扁平化

數組扁平化簡單來講就是把一個多維數組變爲一維數組,核心思想:面試

1.遞歸
2.數值toString() + split()
3.Array.prototype.flat(depth) // Infinity表明無限扁平

遞歸json

function flatten(arr) {
    var res = [];
    arr.map(item => {
        if(Array.isArray(item)) {
            res = res.concat(flatten(item));
        } else {
            res.push(item);
        }
    });
    return res;
}

數值的扁平化toString() + split()數組

let arr = [1,2,3,[2,3,4],45,7,[24,[2,3]]]
    function flatten(arr) {
        return arr.toString().split(',').map(val => {
            return Number(val)
        })
    }

flat()緩存

let arr = [1,2,3,[2,3,4],45,7,[24,[2,3]]]
    arr.flat(infinity)

5.debounce和throttle的實現和使用場景

去抖動和節流,兩者都是隨着時間推移控制執行函數的次數來達到較少資源消耗,特別在事件觸發上,尤其重要。閉包

debounce的做用是,當調用動做觸發一段時間後,纔會執行該動做,若在這段時間間隔內又調用此動做則將從新計算時間間隔。app

簡單來講就是:調用會一直刷新動做,動做是被延遲執行,直到中止調用等待了一段時間後再執行動做。看下面簡單debounce實現節流例子:

function easyDebounce(method, scope) {
        clearTimeout(method.tId); // onresize會一直被觸發,只要在100毫秒內被連續觸發計時器都會刷新直到時間大於100毫秒
        method.tId= setTimeout(function(){
            method.call(scope);
        }, 100);
    }
    
    function resizeDiv(){
        var div = document.getElementById("myDiv");
        div.style.height = div.offsetWidth + "px";
    }
    
    // 節流在resize事件中最經常使用
    window.onresize = function(){
        easyDebounce(resizeDiv);
    };

throttle預先設定一個執行週期,當調用動做的時刻大於等於執行週期則執行該動做,而後進入下一個新的時間週期。throttle能夠基於debounce實現,只須要加上一個閥值(最小值)若是時間小於定義的閥值 則不觸發動做,大於則觸發並刷新週期,並且第一次一定觸發。節流不實用定時器,debounce使用定時器

var throttleV2 = function(action, delay){
        var statTime = 0;
    
        return function() { // 每次resize執行的函數 閉包保證statTime能夠一直使用
            var currTime = +new Date();
    
            if (currTime - statTime > delay) {
                action.apply(this, arguments);
                statTime = currTime ; // 每次調用完以後刷新時間
            }
        }
    }    
    
    // example
    function resizeHandler() {
        console.log("resize");
    }
    
    window.onresize = throttleV2(resizeHandler, 300);

6.vue數據雙向綁定

vue實現數據的雙向綁定根本API是Object.defineProperty(),經過這個方法重寫get,和set屬性來達到數據雙向綁定

詳細解讀一下Object.defineProperty()這個東西到底幹了啥

var Book = {}
    var name = '';
    Object.defineProperty(Book, 'name', {
      set: function (value) {
        name = value;
        console.log('書名:' + value);
      },
      get: function () {
        return '《' + name + '》'
      }
    })
     
    Book.name = '前端學習';
    console.log(Book.name);

雙向綁定是用發佈訂閱模式實現,因此涉及到監聽器Observer、訂閱者Watcher、解析器Compile,以及消息訂閱器dep收集watcher。

圖片來自互聯網:
clipboard.png

7.vue scoped實現原理

vue scoped的實現是經過在對應的dom節點添加data-v-哈希值,並在style每一個屬性後面加上這串data-v-hash來實現樣式的惟一性,起到一個樣式做用域的效果。
可是實際應用中添加scoped也會帶來一些麻煩,好比設置完scoped屬性以後沒法修改子組件的樣式。再次有兩點供你們參考:

  1. 不用scoped屬性,每一個組件使用良好的命名規範,每一個組件的根節點取惟一的類名。
  2. 使用scoped屬性,在須要操做子組件樣式的時候使用‘>>>’來修改子組件的節點樣式。

持續更新中~~~

相關文章
相關標籤/搜索