<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          百度某部門一面原題

          共 18430字,需瀏覽 37分鐘

           ·

          2023-11-09 16:47

          大廠技術  高級前端  Node進階

          點擊上方 程序員成長指北,關注公眾號

          回復1,加入高級Node交流群

          一、前言

          這次的百度面試挺緊張的,在寫算法題的時候腦子都有點空白,還是按照腦海中那點殘存的算法技巧才寫出來,不至于太尷尬,以及第一次面試百度這種級別的公司,難免出現了一些平常不至于出現的問題或沒注意的缺點,在這里分享給大家。

          二、原題

          1. 如何用chatgpt提升前端開發(fā)效率

          1、問題解答和指導:

          ChatGPT可以幫助回答與前端開發(fā)相關的問題。當你在編寫代碼的時候,當一時忘記了某個API怎么用,就可以向ChatGPT提問,并獲得解答和指導,甚至還會給出一些更加深入且性能更好的應用。這可以幫助更快地解決問題和理解前端開發(fā)中的概念。

          2、代碼片段和示例:

          ChatGPT可以幫助你生成常見的前端代碼片段和示例。你可以描述你想要實現的功能或解決的問題,然后向ChatGPT請求相關代碼片段。這樣,您可以更快地獲得一些基礎代碼,從而加快開發(fā)速度。

          3、自動生成文檔:

          ChatGPT可以幫助你生成前端代碼的文檔。你可以描述一個函數、組件或類,并向ChatGPT請求生成相關的文檔注釋。這可以幫助您更輕松地為你的代碼添加文檔,提高代碼的可讀性和可維護性。

          4、問題排查和調試:

          在開發(fā)過程中,您可能會遇到問題或錯誤。您可以向ChatGPT描述您遇到的問題,或者直接把代碼交給它,并請求幫助進行排查和調試。ChatGPT可以提供一些建議和指導,幫助您更快地找到問題的根本原因并解決它們。

          5、學習資源和最新信息:

          ChatGPT可以為你提供關于前端開發(fā)的學習資源和最新信息。你可以向ChatGPT詢問關于前端開發(fā)的最佳實踐、最新的框架或庫、前端設計原則等方面的問題。這可以幫助我們不斷學習和更新自己的前端開發(fā)知識,從而提高效率。

          2. [1, 2, 3, 4, 5, 6, 7, 8, 9] => [[1, 2, 3],[4, 5, 6],[7, 8, 9]],把一個一維數組變成三個三個的二維數組

          在JavaScript中,可以使用數組的slice方法和一個循環(huán)來將一個一維數組轉換為一個二維數組。下面是一個示例代碼:

           function convertTo2DArray(arr, chunkSize{
            var result = [];
            for (var i = 0; i < arr.length; i += chunkSize) {
              result.push(arr.slice(i, i + chunkSize));
            }
            return result;
          }

          var inputArray = [123456789];
          var outputArray = convertTo2DArray(inputArray, 3);

          console.log(outputArray);
          輸出結果將是: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
          slice 不會修改原數組,只會返回一個淺復制了原數組中的元素的一個新數組,不信的話自己可以編譯一下。
          這段代碼中的convertTo2DArray函數接受兩個參數:arr表示輸入的一維數組,chunkSize表示每個子數組的大小。它使用slice方法來從輸入數組中提取每個子數組,并使用循環(huán)來遍歷整個數組并構建輸出二維數組。最后,它返回生成的二維數組。

          3. 輸出結果,為什么?


          const obj3 = {a1};
          const obj4 = {b2};
          console.log(obj3 == obj4);  // false
          console.log(obj3 === obj4); // false


          結果:

          false,false

          原因:

          在這段代碼中,obj3obj4分別是兩個獨立的對象,它們開辟的堆內存地址是完全不一樣。==運算符用于比較兩個操作數是否相等,而===運算符用于比較兩個操作數是否嚴格相等。

          根據對象的比較規(guī)則,當使用==運算符比較兩個對象時,它們將會進行類型轉換后再進行比較。由于obj3obj4是不同的對象,即使它們的屬性值相同,它們的引用也不同,因此在進行類型轉換后,它們會被視為不相等的對象。因此,console.log(obj3 == obj4);的輸出結果將會是false。
          而在使用===運算符比較兩個對象時,不會進行類型轉換,而是直接比較兩個操作數的值和類型是否完全相同。由于obj3obj4是不同的對象,且類型也不同,即使它們的屬性值相同,它們也不會被視為嚴格相等的對象。因此,console.log(obj3 === obj4);的輸出結果同樣會是false

          總結起來,無論是使用==運算符還是===運算符,obj3obj4都不會被視為相等或嚴格相等的對象,因為它們是不同的對象。

          4. this有關 輸出結果,為什么? 


          const obj1 = {
            fn() => {
              return this
            }
          }
          const obj2 = {
            fnfunction(){
              return this
            }
          }

          console.log(obj1.fn());
          console.log(obj2.fn());

          輸出結果:

          1. window || undefined

          2. obj2


          原因是:

          在箭頭函數 fn 中的 this 關鍵字指向的是定義該函數的上下文,而不是調用該函數的對象。因此,當 obj1.fn() 被調用時,由于箭頭函數沒有它自己的this,當你調用fn()函數時,this指向會向上尋找,因此箭頭函數中的 this 指向的是全局對象(在瀏覽器環(huán)境下通常是 window 對象),因此返回的是 undefined。

          而在普通函數 fn 中的 this 關鍵字指向的是調用該函數的對象。在 obj2.fn() 中,函數 fn 是作為 obj2 的方法被調用的,所以其中的 this 指向的是 obj2 對象本身,因此返回的是 obj2。
          需要注意的是:

          objl.fn()的輸出結果是window(不是嚴格模式下)‖undefined(嚴格模式下)

          obj2.fn()的結果是obj2(不管是不是)

          5. Promise有關輸出結果,為什么? 

          console.log('1');
          function promiseFn() {
            return new Promise((resolve, reject) => {
              setTimeout(()=> {
                console.log('2');
              })
              resolve('3');
              console.log('4')
            })
          }

          promiseFn().then(res => {
            console.log(res);
          });

          輸出結果:1 4 3 2

          原因是:

          1. 首先,代碼從上往下執(zhí)行,把console.log('1')放入同步任務

          2. 再調用promiseFn(),因為new Promise是同步任務,所以放入同步任務,繼續(xù)執(zhí)行

          3. 遇到setTimout這個宏任務,放入宏任務隊列中

          4. 遇到resolve('3'),把res返回

          5. 之后再執(zhí)行.then(),因為promise.then是微任務,所以放入微任務隊列

          6. 代碼是先執(zhí)行同步任務,再執(zhí)行微任務,之后再是宏任務

          7. 所以輸出結果為1 4 3 2


          這里涉及到了EventLoop的執(zhí)行機制

          6. 實現斐波那契的第N個值(從0開始),要求時間復雜度為O(n)

          使用動態(tài)規(guī)劃來規(guī)避重復計算問題,算是比較容易想到較優(yōu)的一種解法,并且向面試官展現了你算法能力中有動態(tài)規(guī)劃的思想,對于在面試中的你加分是極大的。
          以下是動態(tài)規(guī)劃思路的算法,狀態(tài)轉移方程為dp[i] = dp[i-1] + dp[i-2]
          function fibonacci(n
              if (n <= 1return n;
              let fib = [01]; // 保存斐波那契數列的結果 
              for (let i = 2; i <= n; i++) { 
                  fib[i] = fib[i - 1] + fib[i - 2]; // 計算第i個斐波那契數 
              } 
              return fib[n]; 
          }
          在面試中,動態(tài)規(guī)劃的常用狀態(tài)轉移方程可以根據問題的具體情況有所不同。以下是幾個常見的動態(tài)規(guī)劃問題和它們對應的狀態(tài)轉移方程示例:

          斐波那契數列(Fibonacci Sequence):

          • dp[i] = dp[i-1] + dp[i-2],其中 dp[i] 表示第 i 個斐波那契數。

          爬樓梯問題(Climbing Stairs):

            • dp[i] = dp[i-1] + dp[i-2],其中 dp[i] 表示爬到第 i 級樓梯的方法數。

          背包問題(Knapsack Problem):

          • dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i]),其中 dp[i][j] 表示在前 i 個物品中選擇總重量不超過 j 的最大價值,

            weight[i] 表示第 i 個物品的重量,value[i] 表示第 i 個物品的價值。

          最長遞增子序列(Longest Increasing Subsequence):

          • dp[i] = max(dp[j] + 1, dp[i]),其中 dp[i] 表示以第 i 個元素結尾的最長遞增子序列的長度,j 為 0 到 i-1 的索引,且 nums[i] > nums[j]。

          最大子數組和(Maximum Subarray Sum):

            • dp[i] = max(nums[i], nums[i] + dp[i-1]),其中 dp[i] 表示以第 i 個元素結尾的最大子數組和。

          最長公共子序列(Longest Common Subsequence):

          • 如果 str1[i] 等于 str2[j],則 dp[i][j] = dp[i-1][j-1] + 1;

          • 否則,dp[i][j] = max(dp[i-1][j], dp[i][j-1]),其中 dp[i][j] 表示 str1 的前 i 個字符和 str2 的前 j 個字符的最長公共子序列的長度。


          編輯距離(Edit Distance):

          • 如果 word1[i] 等于 word2[j],則 dp[i][j] = dp[i-1][j-1];

          • 否則,dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1,其中 dp[i][j] 表示將 word1 的前 i 個字符轉換為 word2 的前 j 個字符所需的最少操作次數。

          打家劫舍(House Robber):

            • dp[i] = max(dp[i-1], dp[i-2] + nums[i]),其中 dp[i] 表示前 i 個房屋能夠獲得的最大金額,nums[i] 表示第 i 個房屋中的金額。

          最大正方形(Maximal Square):

          • 如果 matrix[i][j] 等于 1,則 dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1;

          • 否則,dp[i][j] = 0,其中 dp[i][j] 表示以 matrix[i][j] 為右下角的最大正方形的邊長。

          7. 手寫EventBus 

          當需要手動實現一個簡單的 EventBus 時,你可以創(chuàng)建一個全局的事件總線對象,并在該對象上定義事件的訂閱和發(fā)布方法。
          class EventBus {
            constructor() {
              this.events = {}; // 存儲事件及其對應的回調函數列表
            }

            // 訂閱事件
            subscribe(eventName, callback) {
              this.events[eventName] = this.events[eventName] || []; // 如果事件不存在,創(chuàng)建一個空的回調函數列表
              this.events[eventName].push(callback); // 將回調函數添加到事件的回調函數列表中
            }

            // 發(fā)布事件
            publish(eventName, data) {
              if (this.events[eventName]) {
               this.events[eventName].forEach(callback => {
                  callback(data); // 執(zhí)行回調函數,并傳遞數據作為參數
                });
              }
            }

            // 取消訂閱事件
            unsubscribe(eventName, callback) {
              if (this.events[eventName]) {
                this.events[eventName] = this.events[eventName].filter(cb => cb !== callback); // 過濾掉要取消的回調函數
              }
            }
          }

          使用上述 EventBus 類,你可以執(zhí)行以下操作:
          // 創(chuàng)建全局事件總線對象
          const eventBus = new EventBus();

          const callback1 = data => {
            console.log('Callback 1:', data);
          };

          const callback2 = data => {
            console.log('Callback 2:', data);
          };

          // 訂閱事件
          eventBus.subscribe('event1', callback1);
          eventBus.subscribe('event1', callback2);

          // 發(fā)布事件
          eventBus.publish('event1''Hello, world!');

          // 輸出:
          // Callback 1: Hello, world!
          // Callback 2: Hello, world!

          // 取消訂閱事件
          eventBus.unsubscribe('event1', callback1);

          // 發(fā)布事件
          eventBus.publish('event1''Goodbye!');

          // 輸出:
          // Callback 2: Goodbye!

          在上述示例中,我們創(chuàng)建了一個 EventBus 類,該類具有 subscribepublish 和 unsubscribe 方法。subscribe 方法用于訂閱事件,publish 方法用于發(fā)布事件并觸發(fā)相關的回調函數,unsubscribe 方法用于取消訂閱事件。我們使用全局的 eventBus 對象來執(zhí)行訂閱和發(fā)布操作。
          這個簡單的 EventBus 實現允許你在不同的組件或模塊之間發(fā)布和訂閱事件,以實現跨組件的事件通信和數據傳遞。你可以根據需要對 EventBus 類進行擴展,添加更多的功能,如命名空間、一次訂閱多個事件等。

          當問到EventBus時,得預防面試官問到EvnetEmitter,不過當我在網上查找相關的資料時,發(fā)現很多人似乎都搞混了這兩個概念,雖然我在這里的手寫原理似乎也差不多,但在實際使用中,兩者可能在細節(jié)上有所不同。因此,在具體場景中,你仍然需要根據需求和所選用的實現來查看相關文檔或源碼,以了解它們的具體實現和用法。


          下面是一個簡單的 EventEmitter 類實現的基本示例:

          class EventEmitter {
            constructor() {
              this.events = {}; // 用于存儲事件及其對應的回調函數列表
            }

            // 訂閱事件
            on(eventName, callback) {
              this.events[eventName] = this.events[eventName] || []; // 如果事件不存在,創(chuàng)建一個空的回調函數列表
              this.events[eventName].push(callback); // 將回調函數添加到事件的回調函數列表中
            }

            // 發(fā)布事件
            emit(eventName, data) {
              if (this.events[eventName]) {
                this.events[eventName].forEach(callback => {
                  callback(data); // 執(zhí)行回調函數,并傳遞數據作為參數
                });
              }
            }

            // 取消訂閱事件
            off(eventName, callback) {
              if (this.events[eventName]) {
                this.events[eventName] = this.events[eventName].filter(cb => cb !== callback); // 過濾掉要取消的回調函數
              }
            }
            
            // 添加一次性的事件監(jiān)聽器 
            once(eventName, callback) { 
                const onceCallback = data => { 
                    callback(data); // 執(zhí)行回調函數 
                    this.off(eventName, onceCallback); // 在執(zhí)行后取消訂閱該事件 
                }; 
                this.on(eventName, onceCallback); 
            }
          }

          使用上述 EventEmitter 類,你可以執(zhí)行以下操作:

          const emitter = new EventEmitter();

          const callback1 = data => {
            console.log('Callback 1:', data);
          };

          const callback2 = data => {
            console.log('Callback 2:', data);
          };

          // 添加一次性事件監(jiān)聽器 
          const onceCallback = data => { 
              console.log('Once Callback:', data); 
          };

          // 訂閱事件
          emitter.on('event1', callback1);
          emitter.on('event1', callback2);
          emitter.once('event1', onceCallback);

          // 發(fā)布事件
          emitter.emit('event1''Hello, world!');

          // 輸出:
          // Callback 1: Hello, world!
          // Callback 2: Hello, world!
          // Once Callback: Hello, world!

          // 取消訂閱事件
          emitter.off('event1', callback1);

          // 發(fā)布事件
          emitter.emit('event1''Goodbye!');

          // 輸出:
          // Callback 2: Goodbye!

          在上述示例中,EventEmitter 類具有 on、emit 、 offonce 方法。on 方法用于訂閱事件,emit 方法用于發(fā)布事件并觸發(fā)相關的回調函數,off 方法用于取消訂閱事件,once方法用于添加一次性的事件監(jiān)聽器。你可以根據需求對 EventEmitter 類進行擴展,添加更多的功能,比如一次訂閱多個事件、取消所有事件訂閱等。

          eventBus,eventEmitter的區(qū)別

          EventBus 和 EventEmitter 都是用于實現事件發(fā)布-訂閱模式的工具,但它們在實現和使用上有一些區(qū)別。

          1. 實現方式:

          • EventBusEventBus 是一個全局的事件總線,通常是作為一個單例對象存在,用于在不同組件或模塊之間傳遞事件和數據。在 Vue.js 中,Vue 實例可以充當 EventBus 的角色。

          • EventEmitterEventEmitter 是一個基于類的模塊,通常是作為一個實例對象存在,用于在單個組件或模塊內部實現事件的發(fā)布和訂閱。


          2.使用范圍:

          • EventBusEventBus 的作用范圍更廣泛,可以跨越不同組件、模塊或文件進行事件的發(fā)布和訂閱。它可以實現多個組件之間的通信和數據傳遞。

          • EventEmitterEventEmitter 主要用于單個組件或模塊內部,用于實現內部事件的處理和通信。

          3.依賴關系:

          • EventBusEventBus 通常需要一個中央管理的實例,因此需要在應用程序的某個地方進行創(chuàng)建和管理。在 Vue.js 中,Vue 實例可以用作全局的 EventBus。

          • EventEmitterEventEmitter 可以在需要的地方創(chuàng)建實例對象,并將其用于內部事件的發(fā)布和訂閱。

          4.命名空間:

          • EventBusEventBus 可以使用不同的事件名稱來進行事件的區(qū)分和分類,可以使用命名空間來標識不同類型的事件。

          • EventEmitterEventEmitter 通常使用字符串作為事件的名稱,沒有直接支持命名空間的概念。


          總結起來,EventBus 主要用于實現跨組件或模塊的事件通信和數據傳遞,適用于大型應用程序;而 EventEmitter 主要用于組件或模塊內部的事件處理和通信,適用于小型應用程序或組件級別的事件管理。選擇使用哪種工具取決于你的具體需求和應用場景。

          8. (場景題)在瀏覽器中一天只能彈出一個彈窗,如何實現,說一下你的思路? 

          要在瀏覽器中實現一天只能彈出一個彈窗的功能,可以使用本地存儲(localStorage)來記錄彈窗狀態(tài)。下面是一種實現方案:
          1. 當頁面加載時,檢查本地存儲中是否已存在彈窗狀態(tài)的標記。

          2. 如果標記不存在或者標記表示上一次彈窗是在前一天,則顯示彈窗并更新本地存儲中的標記為當前日期。

          3. 如果標記存在且表示上一次彈窗是在當天,則不顯示彈窗。


          以下是示例代碼:
          // 檢查彈窗狀態(tài)的函數
          function checkPopupStatus() {
            // 獲取當前日期
            const currentDate = new Date().toDateString();

            // 從本地存儲中獲取彈窗狀態(tài)標記
            const popupStatus = localStorage.getItem('popupStatus');

            // 如果標記不存在或者標記表示上一次彈窗是在前一天
            if (!popupStatus || popupStatus !== currentDate) {
              // 顯示彈窗
              displayPopup();

              // 更新本地存儲中的標記為當前日期
              localStorage.setItem('popupStatus', currentDate);
            }
          }

          // 顯示彈窗的函數
          function displayPopup() {
            // 在這里編寫顯示彈窗的邏輯,可以是通過修改 DOM 元素顯示彈窗,或者調用自定義的彈窗組件等
            console.log('彈出彈窗');
          }

          // 在頁面加載時調用檢查彈窗狀態(tài)的函數
          checkPopupStatus();

          在這個實現中,checkPopupStatus 函數會在頁面加載時被調用。它首先獲取當前日期,并從本地存儲中獲取彈窗狀態(tài)的標記。如果標記不存在或者表示上一次彈窗是在前一天,就會調用 displayPopup 函數顯示彈窗,并更新本地存儲中的標記為當前日期。

          通過這種方式,就可以確保在同一天只能彈出一個彈窗,而在后續(xù)的頁面加載中不會重復彈窗。

          9. 項目中的性能優(yōu)化? 

          1、對組件和圖片進行懶加載對暫時未使用的組件和圖片使用懶加載可以顯著地減少頁面加載時間,比如在我的項目中路由配置中除了需要頻繁切換的頁面組件外,其他的組件都使用箭頭函數引入組件進行懶加載,以及一些沒有展現在界面的圖片也進行了一個VueLazy的懶加載。

          2、減少HTTP請求數量由于頻繁的請求會對后端服務器造成極大的負擔,所以應該減少不必要的請求,比如在我的項目中的搜索界面,對于搜索按鈕增加了防抖功能

          3、使用緩存使用瀏覽器緩存可以減少資源請求,從而提高頁面加載速度。項目中我會把用戶的一些需要持久化的信息存入本地存儲。

          4、異步請求使用Promise.all:異步請求可以在后臺加載資源,從而避免阻塞頁面加載。在請求數據時,我會使用Promise.all一次性并行的請求類似的數據,而不需要一個一個的請求,較少了請求時間。

          5、圖片優(yōu)化使用適當的圖片格式和大小可以減少頁面的資源請求和加載時間,項目中我會把圖片轉化成base64的格式和webp格式,這樣可以使圖片大小更小

          6、使用CDN加速:使用CDN可以提高資源的訪問速度,從而加快頁面加載速度。我項目中的一些第三方資源有時需要請求,因此我會使用CDN內容分發(fā)網絡來提高訪問速度。

          7、骨架屏(Skeleton Screen):它可以提升用戶感知的加載速度和用戶體驗。雖然骨架屏本身并不直接影響代碼性能,但它可以改善用戶對應用程序的感知,提供更好的用戶體驗。

          10. 項目中遇到的難點,如何解決

          1. 數據狀態(tài)管理

          前端登錄狀態(tài)管理


          • 我在一個練手的項目中做前端登錄功能的時候, 碰到了購物車需要登錄判斷的功能,比如用isLogin來判斷有沒有登錄,當時由于沒有深入了解vuex,所以我一開始想著把這個isLogin通過組件與組件的傳值方法,把這個值傳給相應的組件,然后在需要登錄組件中進行判斷,但后來發(fā)現這個方法太麻煩了
          • 后來通過學習了解,使用了vuex這個全局狀態(tài)管理的方法, 通過使用createStore這個vuex中的API創(chuàng)建了一個全局的登錄狀態(tài),再通過actions mutations實現登錄判斷和登錄狀態(tài)共享

          組件數據狀態(tài)管理
          • 我項目中一開始首頁、詳情頁等其他頁面越來越多的狀態(tài)放在同一個store上,雖然感覺有點亂,但實現了數據流和組件開發(fā)的分離,使得我更能夠專注于數據的管理

          • 但隨著數據的增多,感覺實在太亂了,然后得知vuex中可以使用 modules 來進行分模塊,相應的頁面放入相應的模塊狀態(tài)中,之后再用actions,mutations,state,getters這四件套, 更好的模塊化管理數據,能夠知道哪些狀態(tài)是全局共享的(登錄), 哪些狀態(tài)是模塊共享的

          • 然后在新的項目中,也就是現在簡歷上的項目里,嘗試使用pinia來管理,因為我發(fā)現它更簡單(沒有mutations),模塊化更好,讓我對組件狀態(tài)管理的更加得心應手,學習起來也更加的方便。

          node的錯誤處理

          • 一開始用node寫后端的時候,一堆錯誤,比如路由沒配置,數據庫報錯。使得后面的代碼都無法運行,寫著寫著就感覺寫不下去,經常一個錯誤就需要反復的在腦海中想最后依靠那一絲的靈光一閃才解決
          • 之后我就在app.js這個后端入口文件的最后,添加一個統(tǒng)一的錯誤處理的中間件,向前端返回狀態(tài)碼和相應的信息后,直接使用next()向后繼續(xù)執(zhí)行,這樣雖然服務器報了錯,但仍然可以執(zhí)行后續(xù)的代碼。

          跨域問題

          • 在我寫完前端項目的時候,想要提升一下自己,就轉去學習了Koa,在搭建了大致的服務器,寫了一個簡單的接口并運行服務器后,我想當然的就在前端直接請求后端的端口,結果報了一個跨域的錯誤,由于當時初學后端,不怎么了解跨域,所以找了很多的解答并逐個在項目中進行嘗試,比如跨域中的script,postMessagehtml本身的Websocket

          • 但發(fā)現最實用的還是在服務器中配置Access-Control-Allow-Origin來控制跨域請求的url地址,以及其他一些Access-Control-Allow頭來控制跨域請求方法等,然后跨域請求url的白名單我放入了.env這個全局環(huán)境變量中。

          axios響應攔截

          • 在后端返回數據的時候,我返回數據有一個狀態(tài)碼以及添加到data這個需要返回的數據(代碼如下),這導致我在獲取接口里的數據時需要多.data(引用一層data),當時我沒意識到,結果一直獲取不到數據。之后輸出獲取的數據才發(fā)現在數據外面包了一層,雖然這個時候解決了服務器那邊數據返回的問題,但后面每次獲取數據時都需要在往里再獲取,非常的麻煩。

          • 最后在學習了并在項目中使用axios進行請求和響應后,就在響應的時候設置一個攔截器,對響應進行一番處理之后就可以直接拿到后端接口返回的值,而不會導致接口返回的值不會有太多的嵌套了。

          11. 如何學習前端的,學了幾年?

          這個就看個人情況了,但其中,你得展現出你的學習積極性和對前端的熱愛,讓面試官能夠欣賞你

          我大致說說我回答的,僅作參考

          我從大二開始就對前端很感興趣,當時正好學校也分了Web前端的方向,于是就跟著學校的課程開始學習基本的html,css,js三劍客,但之后感覺到老師教的很慢,就自己到B站上學習了,之后由于參加過一次藍橋杯,就看到了藍橋云課上有相關的基于html,css,js比較基礎項目,接著我還學習了一些行內大牛寫的一些博客文章,比如阮一峰,張鑫旭,廖雪峰等這些老師。之后又學習了vue并且在GitHub上學習相關的設計理念,根據GitHub上項目中不懂的東西又逐漸學習了各種UI組件庫和數據請求方式,最后又學習了Nodejs中的Koa,用Vue和Koa仿寫了一個全棧型項目,目前正在學習一些typescript的基本用法并嘗試著運用到項目中,并在學習Vue的一些底層源碼。


          關于本文

          作者:吃膩的奶油

          https://juejin.cn/post/7240751116701728805


          三、最后

          這套題目,更加看重的是代碼底層的實現和算法基礎。


          Node 社群

              
              


          我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學習感興趣的話(后續(xù)有計劃也可以),我們可以一起進行Node.js相關的交流、學習、共建。下方加 考拉 好友回復「Node」即可。

             “分享、點贊、在看” 支持一下

          瀏覽 480
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品白浆无码流出视频网站 | 色综合天天综合网天天狠天天 | 免费操逼视频。 | 免费看日逼视频的网站 | 成人自拍网站在线 |