最終題目準備

1,vue的列表組件爲何要加key?css

  增長diff算法的同級比較效率,  key是惟一索引,能夠一目瞭然的看到同一級的是否變化,若是沒有key, 那就只能一個個的去進行比較了。html

2, ['1', '2', '3'].map(parseInt)結果是多少?        [1, NaN, NaN];前端

  map函數的默認參數爲 item,index和arr,  parseInt的參數爲 字符串 和 進制數。   因此轉換爲求  parseInt('1', 0) parseInt('2', 1) parseInt('3', 2)的值。
vue

  關於求進制數: parseInt(str, radix)node

    radix的範圍是在 2和36之間, 當進制數爲0的時候,默認爲10進制。  str的值從第一個開始不能大於對應的進制數。若是第一個數大於對應的進制數,則返回NaN。 若是第一個數一旦小於進制數,就開始作運算,直到碰到大於進制數的就停下來。webpack

    exp:  parseInt('43256789', 5);    4*5*5 + 3* 5 + 2 = 117ios

3,節流和防抖, 有什麼區別, 怎麼實現?es6

  節流:  限制一段時間內函數只執行一次。web

  防抖:  函數一段事件執行一次, 若是在這段時間內被觸發,則從新計算時間。ajax

  參考 : http://www.javashuo.com/article/p-fcnnhvlc-dt.html

4, 介紹下 Set  Map  WeakSet   WeakMap的區別

  set 對應的是數組,  相似數組, 容許存儲任何類型的值,但沒有重複的成員。set內部的比較是用全等。 size是數量, 方法有keys, values, entries和forEach。

  weakset:  只能儲存對象引用。 因爲是弱引用, 只要沒被其餘的變量或者屬性引用,就會被回收。 因此沒法被遍歷,沒法拿到全部的元素,也沒有size屬性。

  Map: 對應的是obj對象。 是以key,value的形式存儲的。  key能夠爲任意數據結構, 而對象的key只能爲字符串。

  weakmap: 鍵值對的集合,只接受對象做爲鍵名。弱引用,不能遍歷。

5,深拷貝

     function isObject(obj) {
        return typeof obj === 'object' && obj !== null;
    }

    function deepClone(target, hash = new WeakMap()) {
        if (!isObject(target)) return target;
        if (hash.has(target)) return hash.get(target);

        let clone = Array.isArray(target) ? []: {};
        hash.set(target, clone);

        for (let key in target) {
            if (Object.prototype.hasOwnProperty.call(target, key)) {
                if (isObject(target[key])) {
                    clone[key] = deepClone(target[key], hash);
                } else {
                    clone[key] = target[key];
                }
            }
        }

        return clone;
    }
View Code

6,setTimeout, promise   ,  async  await  有什麼區別

  setTimeout :  定時器的回調函數是 屬於 宏任務, 當前執行棧清空後執行。

  promise:  promise的then函數是微任務, 放在微任務隊列, 當前同步任務執行完以後就立馬執行微任務隊列。

  async / await: async函數返回promise, 正常狀況下await後面也是promise,若是不是promise,則會被變爲promise,而且當即resolve。

7, async / await 使如何經過同步寫法的方式來實現異步的。

  async/await是 generator的語法糖,   在遇到異步的操做時, 會暫停該函數, 交出執行權, 當該異步完成後, 再繼續執行。

8, var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];    扁平化數組而且去重 按順序排列

[...new Set(arr.flat(Infinity))].sort((a,b) => a-b);

9,js異步解決方案的發展歷程 以及優缺點

  1,callback:  回調地獄, 強耦合,不能用try catch捕獲錯誤。不能return

  2, promise: 解決回調地獄, 採用鏈式調用。 不過語義很不清楚,一眼看去都是then的堆積。沒法取消promise

  3,generator:能夠控制函數的執行, 也能夠進行函數內外的數據交換和錯誤的處理。

  4,async: 代碼簡潔,符合語義。由於有自動執行器,因此代碼量少。

10, 如何實現一個new

function _new(fn, ...args) {
    let obj = Object.create(fn.prototype);
    let result = fn.apply(obj, args);
    return Object.prototype.toString.call(result) === '[object Object]' ? result : obj;
}

11, 簡單講解一下http2的多路複用

  多路複用代替了http1的序列和阻塞機制,全部相同域名的請求都經過一個tcp鏈接併發完成。 http1併發多個請求須要多個tcp鏈接,瀏覽器通常會限制爲6個。 http2的多路複用會消除因多個tcp鏈接帶來的延時和內存消耗,並且單個鏈接上能夠進行並行交錯的請求和響應,互相不干擾。

12,tcp的三次握手和四次揮手

  三次握手: 客戶端發送一個帶SYN標誌的數據包給服務器,服務器收到後返回一個帶有SYN/ACK標誌的數據包表示確認,客戶端再回傳一個帶ACK標誌的數據包表示握手結束。

  四次揮手: 客戶端進程發出連續釋放報文,並中止發送數據。 服務器收到連續釋放報文,發出確認報文。 服務器將最後的數據發送完畢,向客戶端發送連續釋放報文。 客戶端收到後,發出確認。 服務器收到客戶端的確認, 進入closed狀態。

13, cookie和token都放在header中, 爲何不劫持token呢

  token是爲了防止csrf跨站請求攻擊的。  瀏覽器在發送http時會自動帶上cookie, 可是不會自動帶上token。

14,  var a = ? ,  if (a == 1 && a == 2 && a== 3) { console.log(1)}    a在什麼狀況下 會打印1;

  由於用 == 號比較的時候,會進行隱式轉換, 對於對象來講,隱式轉換會調用自身的toString或者valueof方法。

var a = {
    n: 1,
    toString() {
        return this.n++
    }
}
a==1 && a==2 && a==3 ; true
toString 改成valueof也能夠

若是a爲數組 有一種方法更簡單
var a = [1,2,3];
a.toString = a.shift;
a == 1 && a==2 && a==3 ; true

 15,bfc及其應用

  bfc爲塊級格式化上下文,bfc內部的元素不管怎樣都不會影響外部元素。

  觸發條件: html元素, display爲inline-block table-cell和table-caption,position不爲relative或static  overflow爲 auto scroll或hidden   float的值不爲none

  基本用途: 去除margin重疊, 清除浮動 , 流體佈局。

16,在vue中,爲什麼子組件不能修改父組件傳遞的prop,若是修改了,vue是如何監控到屬性的修改並給出警告的?

  若是傳遞的prop爲引用類型,子組件修改的話不會報錯,若是是基本類型,子組件修改的時候會失敗,而且vue會給出警告。

  由於在修改prop的時候,觸發set會判斷是否在根組件或者是更新子組件。 若是不是那就說明更新的是props, 會給出警告。

17,雙向綁定和vuex是否衝突

  在嚴格模式下,的確衝突, 由於在數值改變時,v-model會直接修改屬性值,可是這個修改不是在mutaition中操做的,因此會報錯。 解決方法:

    1,在input中綁定vuex的state, 監聽input或change事件,在回調中操做mutation

    2,使用帶有setter的雙向綁定計算屬性。

18,爲何一般在發送數據埋點請求的時候使用的是1×1像素的透明gif圖片

  此方法主要應用於只需向服務器發送數據,無需服務器回覆。

    避免跨域, 不會阻塞頁面, gif在全部格式中體積最小。

19,vue的響應式原理 Object.defineProperty有什麼缺陷, 爲何vue3改用了proxy?

  Object.defineProperty沒法監控到數組下標的變化,因此vue內部重寫了數組的一些操做方法,但也只是針對了這幾種方法作了hack,經過下標操做數據的話,vue就監聽不到。

  Object.defineProperty只能劫持對象的屬性,所以須要對對象的每一個屬性進行遍從來進行數據的監聽,若是屬性也是對象,還須要進行深度遍歷。

  es6的proxy有如下兩個優勢: 1,能夠劫持整個對象,提升性能, 那麼固然數組新加的屬性就能夠監聽到了。

20,div垂直水平居中

  參考  http://www.javashuo.com/article/p-eiwnvhgj-ea.html

21,如何實現冒泡排序,時間複雜度是多少, 如何改進

    function bubble(arr) {
       const len = arr.length - 1;
       for (let i = 0; i < len; i++) {
           let isOk = true;
           for (let j = 0; j < len - i; j++) {
               if (arr[j] > arr[j+1]) {
                   [arr[j], arr[j+1]] = [arr[j+1], arr[j]];
                   isOk = false;
               }
           }
           if (isOk) break;
       }
       return arr;
   }
View Code

22, 某公司1到12月份的銷售額存在一個對象中 {1:222, 2:123, 5:888},請把數據處理爲以下結構:[222, 123, null, null, 888, null, null, null, null, null, null, null]。

Array.from({length: 12}).map((_,index) => obj[index + 1] || null);

23,要求設計LazyMan類, 知足如下的功能

LazyMan('Tony');
// Hi I am Tony

LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch

LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food
View Code

 

      class LazyClass {
            constructor(name) {
                this.eventQueen = [];
                this.name = name;
                this.init();
            }
            init() {
                console.log('Hi I am ' + this.name);
                setTimeout(() => {
                    this.next();
                });
                return this;
            }
            eat(things) {
                let that = this;
                this.eventQueen.push(function () {
                    console.log('I am eating '+ things);
                    that.next();
                });
                return this;
            }
            sleep(time) {
                let that = this;
                this.eventQueen.push(function () {
                    setTimeout(() => {
                        console.log('等待了' + time + 's');
                        that.next();
                    }, time*1000);
                })
                return this;
            }

            sleepFirst(time) {
                let that = this;
                this.eventQueen.unshift(function () {
                    setTimeout(() => {
                        console.log('等待了' + time + 's');
                        that.next();
                    }, time *1000)
                });
                return this;
            }
            next() {
                let fn = this.eventQueen.shift();
                fn && fn();
            }

        }



        function LazyMan(name) {
            return new LazyClass(name);
        }

24,比較opacity:0, visibility:hidden, display:none的優劣和適用場景

  均可以讓元素不可見,

  display:none:  不渲染dom,不佔據空間,沒法監聽事件,屬性改變時會引發頁面迴流, transition不支持。

  visibility:hidden : 佔據空間,渲染dom, 沒法監聽事件, 屬性改變引發頁面重繪。

  opacity:0  : 佔據空間,渲染dom, 能夠監聽事件, 配合transition進行顯示和隱藏, 屬性改變引發頁面重繪

25,箭頭函數和普通函數的區別是什麼? 構造函數可使用new生成實例,箭頭函數能夠嗎?

  箭頭函數和普通函數的區別:   箭頭函數沒有this, 箭頭函數使用的是箭頭函數所在函數的this,由於也沒法使用call apply和bind來綁定和改變this。

                箭頭函數沒有arguments屬性,若是要使用能夠用rest參數, 不可使用yield命令,所以不能用做Generator函數。

  箭頭函數不能當作構造函數,由於不能使用new命令,不然會報錯。

26,給定兩個數組,計算他們的交集;  例如:給定 nums1 = [1, 2, 2, 1],nums2 = [2, 2],返回 [2, 2]。

    function getSame(arr1, arr2) {
            let result = [];
            let newArr2 = [...arr2];
            arr1.forEach(item => {
                let index = newArr2.indexOf(item);
                if (index > -1) {
                    newArr2.splice(index, 1);
                    result.push(item);
                }
            });
            return result;
        }

27,已知代碼:  <img src="1.jpg" style="width:480px!important;」>  如何修改才能讓圖片寬度爲300px?  下面的代碼不能修改... 

  max-width: 300px;

28, token加密的步驟

  後端經過隨機數加簽名來生成一個token, 前端拿到token後在接口調用的時候添加token,後端判斷請求中攜帶的token進行驗證。

29,模擬實現一個promise.finally

Promise.prototype.finally = function (callback) {
    let P = this.constructor;
    return this.then( value => P.resolve(callback()).then(() => value), error => P.resolve(callback()).then(()=> { throw error}) )
}

30,隨機生成一個長度爲 10 的整數類型的數組,例如 [2, 10, 3, 4, 5, 11, 10, 11, 20],將其排列成一個新數組,要求新數組形式以下,例如 [[2, 3, 4, 5], [10, 11], [20]]

     function getNewArray(arr) {
            let newArr = [...new Set(arr)];
            let hash = {length: 0};
            newArr.forEach(item => {
                let index = Math.floor(item / 10);
                if (!hash[index]) {
                    hash[index] = [];
                    hash.length++;
                }
                hash[index].push(item);
            });
            return Array.from(hash);
        }

31,實現一個字符串匹配算法,從長度爲n的字符串s中,查找是否存在字符串t,t的長度是n,若存在則返回位置

      function findStr(str, part) {
           if (part.length > str.length) return -1;
           for (let i = 0; i < str.length - part.length; i++) {
               if (str.slice(i, i+part.length) === part) {
                   return i;
               }
           }
           return -1;
       }

32,數組裏面有10萬個數據,取第一個元素和第十萬個元素時間相差多少

  數組本質上也是對象,其索引是字符串,查找數組的元素就是經過索引查找哈希表的過程,因此消耗的時間大體同樣。

33,vue的父組件和子組件生命週期鉤子執行順序是什麼

  渲染: 父 beforeCreate --> 父created --> 父beforeMount --> 子beforeCreate --> 子created --> 子beforeMount --> 子mounted --> 父mounted

  更新: 父 beforeUpdate --> 子beforeUpdate --> 子updated --> 父updated

  銷燬: 父beforeDestroy --> 子beforeDestroy --> 子 destroyed --> 父 destroyed

34,promise.all的使用、原理和錯誤處理

  promise.all的參數必須有Iterator接口,參數的全部子元素都必須是promise示例,若是不是則自動調用promise.resolve轉爲promise示例。

  promise.all的狀態由子元素的狀態決定,只有子元素的狀態都變成fulfilled,promise.all的狀態才變爲fulfilled,此時子元素的返回值組成一個數組,傳給promise.all的回調函數。只要子元素有一個變爲rejected,promise.all就變成rejected,返回第一個被rejected的子元素的返回值。

35,axios、fetch和ajax有什麼區別

  ajax: XMLHttpRequest對象,最先出現的發送請求的技術。

  axios: 使用promise對ajax的封裝。 

  fetch:fetch是es6的用來代替ajax的異步請求技術。是原生的js,基於promise,爲了擴展其餘應用。

36,vue組件的通訊方式

  1,props、$emit

  2,$emit 、$on 

  3,$attrs和$listeners

  4,provide、inject

  5,vuex

37,vuex工做原理

  vuex是專門使用於vue的狀態管理工具,它集中管理全部組件的狀態,並提供一系列方法來獲取和操做狀態。

  讀取的數據和狀態存放在state裏面, getter爲state的計算屬性,state的值發生變化它也會被從新計算,改變狀態就是提交mutations,若是是異步的任務則須要封裝在action裏面。 module是將store分割成模塊,每一個模塊都具備上面的各個屬性。

38,什麼是虛擬dom, 爲何虛擬dom會提升性能

  虛擬dom其實就是js的一個對象,經過對象來描述真實的dom。 

  頻繁的操做真實dom,效率是很低的。 virtual dom經過使用數據對象來描述dom樹,在每次視圖更新的時候,比較與真實dom的差別, 只須要一次性更新有變化的dom,減小不少沒必要要的dom操做。 因此說 virtual是用來減小大範圍頻繁的重繪。

39,vue計算屬性和方法的區別

  計算屬性是基於響應式依賴來進行緩存的,只有在相關的依賴發生變化的時候才進行求值。 而方法的話就不會進行緩存,老是會執行該函數。

40,vue事件總線

var bus = new Vue();

定義事件 : bus.$on('事件名稱', fn);
觸發事件: bus.$emit('事件名稱', fn);
View Code

41,spa單頁面的理解,優缺點是什麼

  在頁面初始化時加載相應的html、css和js,一旦頁面加載完成,spa不會由於用戶的操做而進行頁面的從新加載或者跳轉,而是使用路由機制實現內容的切換。

  優勢: 用戶體驗好,內容的改變不須要加載整個頁面,避免了重複的渲染。 對服務器壓力小。 先後端分工明確。

  缺點: 初次加載耗時多, 前進後退路由管理, seo難度較大

42,npm run dev以後的執行過程

  首先會在項目的根目錄下尋找 package.json文件, 找到scripts對象對應的dev,執行對應的命令, webpack-dev-server 爲一個node服務器,而後就會把當前的頁面展現在node服務器的對應端口上。

43,爲何組件中的data是一個函數

  由於組件是用來複用的,若是組件中的data是一個對象,那麼每個組件都是公用的一個data對象,data的值會相互影響,而當data爲一個函數,那麼每一個示例能夠維護一份被返回的對象,互相獨立,互不影響。

44,vue是如何實現雙向數據綁定的

   http://www.javashuo.com/article/p-pdmiibct-ek.html

45,var、let和const的區別

  let和const不存在變量提高, 而且只在當前的代碼塊中有效。  並且還存在暫時性死區, 不容許重複的聲明。 const 聲明的常量不能改變值,不過當值 爲對象時能夠改變內容。

46,vue-router的router-link和a標籤有什麼區別

  router-link渲染出來的也是a標籤,看vue-router的源碼,router-link接管了渲染的a標籤的行爲, click的時候阻止了a標籤默認的跳轉,取得to的屬性,經過history或者hash來進行頁面的切換,並不會刷新頁面。

47,實現convert方法,將數組的list轉換爲tree結構

var list = [
            {id:1,name:'部門A',parentId:0},
            {id:2,name:'部門B',parentId:0},
            {id:3,name:'部門C',parentId:1},
            {id:4,name:'部門D',parentId:1},
            {id:5,name:'部門E',parentId:2},
            {id:6,name:'部門F',parentId:3},
            {id:7,name:'部門G',parentId:2},
            {id:8,name:'部門H',parentId:4}
        ];
// 轉換後的結果以下
let result = [
    {
      id: 1,
      name: '部門A',
      parentId: 0,
      children: [
        {
          id: 3,
          name: '部門C',
          parentId: 1,
          children: [
            {
              id: 6,
              name: '部門F',
              parentId: 3
            }, {
              id: 16,
              name: '部門L',
              parentId: 3
            }
          ]
        },
        {
          id: 4,
          name: '部門D',
          parentId: 1,
          children: [
            {
              id: 8,
              name: '部門H',
              parentId: 4
            }
          ]
        }
      ]
    },
  ···
];
View Code
參考了一個大佬對對象引用的操做:

    function convert(list) {
            let result = [];
            let map = list.reduce((prev, next) => {
                prev[next.id] = next;
                return prev;
            }, {});

            //這時候 list 和 map裏面的元素是相互引用的,
            for (let item of list) {
                if (item.parentId === 0) {
                    result.push(item);
                    continue;
                }
                if (item.parentId in map) {
                    let parent = map[item.parentId];
                    parent.children = parent.children || [];
                    parent.children.push(item); // 後面的新增children 都會影響到根元素的內容
                }
            }
            return result;
        }
View Code

48,實現Promise.race

        Promise._race = function (promises) {
            return new Promise((resolve, reject) => {
                promises.forEach(promise => {
                    promise.then(resolve, reject);
                })
            })
        }    

49,實現模糊查詢結果的關鍵詞高亮

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .red{
            color:red;
        }
    </style>
</head>
<body>
<input type="text" id="input">
<ul id="list"></ul>

    <script>
        let list = ['ab', 'abc', 'abd', 'abcdef', 'abcef','abcdefghij'];  // 模擬查詢的數據
        let container = document.getElementById('list');
        let input = document.getElementById('input');

        function debounce(fn) {   // 防抖, 用戶輸入完成後300ms觸發
            let timeout;
            return function (...args) {
                if (timeout) {
                    clearTimeout(timeout);
                    timeout = null;
                }
                timeout = setTimeout(() => {
                    fn.apply(this, args);
                },300)
            }
        }

        function handleInput(name) {
            let reg = new RegExp(`(${name})`);
            const result = list.reduce((prev, next) => {
                if (reg.test(next)) {
                    let match = RegExp.$1;
                    let str = `<li>${next.replace(match, '<b class="red">'+match+'</b>')}</li>`;
                    prev.push(str);
                }
                return prev;
            }, []);
            if (name === '') {
                container.innerHTML = '';
                return;
            }
            if (result.length === 0) {
                container.innerHTML = '暫無結果';
            } else {
                container.innerHTML = result.join('');
            }
        }
        input.addEventListener('input', debounce(e => {
            handleInput(e.target.value);
        }))
    </script>
</body>
</html>
View Code

 50,已知數據格式,實現函數fn找到對應id的全部父級id

const data = [{
    id: '1',
    name: 'test1',
    children: [
        {
            id: '11',
            name: 'test11',
            children: [
                {
                    id: '111',
                    name: 'test111'
                },
                {
                    id: '112',
                    name: 'test112'
                }
            ]

        },
        {
            id: '12',
            name: 'test12',
            children: [
                {
                    id: '121',
                    name: 'test121'
                },
                {
                    id: '122',
                    name: 'test122'
                }
            ]
        }
    ]
}];

fn(data, '121');  //  [1, 12, 121]
View Code

  

        function find(data, id) {
            if (Array.isArray(data)) {
                while(data.length) {
                    let item = data.shift();
                    if (item.id == id) {
                        return item.hash.split('-');
                    }
                    if (item.children && item.children.length) {
                        item.children.map( one => {
                            one.hash = (item.hash || item.id) + '-' + one.id;
                            data.push(one);
                        })

                    }
                }
            }
            return [];
        }    
相關文章
相關標籤/搜索