1. 程式人生 > >金三銀四,磨礪鋒芒;劍指大廠,揚帆起航(2020年最全大廠WEB前端面試題精選)上

金三銀四,磨礪鋒芒;劍指大廠,揚帆起航(2020年最全大廠WEB前端面試題精選)上

金三銀四,磨礪鋒芒;劍指大廠,揚帆起航(2020年最全大廠WEB前端面試題精選)上

引言

元旦匆匆而過,2020年的春節又接踵而來,大家除了忙的提著褲子加班、年底沖沖衝外,還有著對於明年的迷茫和期待!2019年有多少苦澀心酸,2020年就有更多幸福美好,加油,奧利給!懷著一顆積極向上的心,來面對未來每一天的挑戰!

所謂“兵馬未動,糧草先行”,我們打響明天的戰役也需要精神食糧來做後勤保障才是。在此我整理了多位從業者和我在2019年底至2020年初的一廠面試精選題,希望對磨礪鋒芒、奮發向上的小夥伴有所幫助,祝你早日劍指大廠,揚帆起航,奧利給!

CSS

1、講講盒模型(螞蟻金服 2019.03 招行信用卡 2019.04 美團 作業幫)

盒子模型就是 元素在網頁中的實際佔位,有兩種:標準盒子模型和IE盒子模型

標準(W3C)盒子模型:內容content+填充padding+邊框border+邊界margin寬高指的是 content 的寬高

低版本IE盒子模型:內容(content+padding+border)+ 邊界margin,寬高指的是content+padding+border 部分的寬高

/* 標準模型 */
box-sizing:content-box;
 /*IE模型*/
box-sizing:border-box;

2、根據盒模型解釋邊距重疊(螞蟻金服 2019.03 圖森未來)

父子元素、兄弟元素,當有外邊距時,會取其中一個邊距的最大值,作為實際的邊距。
空元素的有上下邊距時,也會取其中更大的一個邊距值,作為實際的邊距。
這就是邊距重疊。

BFC:
概念:塊級格式化上下文
原理:

  1. 在BFC這個元素垂直方向的邊距會發生重疊
  2. BFC的區域不會與浮動元素的box重疊
  3. BFC在頁面上是一個獨立的容器,其裡外的元素不會互相影響
  4. 計算BFC高度時,浮動元素也會參與計算

3、 寬高比4:3自適應 (螞蟻金服 2019.03 )

垂直方向的padding: 在css中,padding-top或padding-bottom的百分比值是根據容器的width來計算的。

.wrap{
       position: relative;
       height: 0;  //容器的height設定為0
       width: 100%;
       padding-top: 75%;  //100%*3/4
}
.wrap > *{
       position: absolute;//容器的內容的所有元素absolute,然子元素內容都將被padding擠出容器
       left: 0;
       top: 0;
       width: 100%;
       height: 100%;
}
+ **padding & calc()**: 跟第一種方法原理相同
​```css
padding-top: calc(100%*9/16);
  • padding & 偽元素
  • 視窗單位: 瀏覽器100vw表示瀏覽器的視窗寬度
width:100vw;
height:calc(100vw*3/4)

4、css選擇器的優先順序( 百度前端 搜狐 美團 拼多多 VIVO)

優先順序就近原則,同權重情況下樣式定義最近者為準

!important>id >class>tag

important比內聯優先順序高

元素選擇符的權值:元素標籤(派生選擇器):1,class選擇符:10,id選擇符:100,內聯樣式權值最大,為1000

  1. !important宣告的樣式優先順序最高,如果衝突再進行計算。
  2. 如果優先順序相同,則選擇最後出現的樣式。
  3. 繼承得到的樣式的優先順序最低。

5、css水平居中 (螞蟻金服、百度前端、位元組跳動)

一、對於行內元素:

text-align:center;

二、對於確定寬度的塊級元素:

(1)margin和width實現水平居中

常用(前提:已設定width值):margin-left:auto; margin-right:auto;

(2)絕對定位和margin-left: -(寬度值/2)實現水平居中

固定寬度塊級元素水平居中,通過使用絕對定位,以及設定元素margin-left為其寬度的一半

.content{

width: 200px;

position: absolute;

left: 50%;

margin-left: -100px; // 該元素寬度的一半,即100px

background-color: aqua;

}

(3)position:absolute + (left=0+top=0+right=0+bottom=0) + margin:auto

.content{

position: absolute;

width: 200px;

top: 0;

right: 0;

bottom: 0;

left: 0;

margin: auto;

}

三、對於未知寬度的塊級元素:

(1)table標籤配合margin左右auto實現水平居中

使用table標籤(或直接將塊級元素設值為display:table),再通過給該標籤新增左右margin為auto

(2)inline-block實現水平居中方法

display:inline-block;(或display:inline)和text-align:center;實現水平居中

存在問題:需額外處理inline-block的瀏覽器相容性(解決inline-block元素的空白間距)

(3)絕對定位實現水平居中

絕對定位+transform,translateX可以移動本省元素的50%

.content{

position: absolute;

left: 50%;

transform: translateX(-50%); /* 移動元素本身50% */

background: aqua;

}

(4)相對定位實現水平居中

用float或者display把父元素變成行內塊狀元素

.contentParent{

display: inline-block; /* 把父元素轉化為行內塊狀元素 */

/*float: left; 把父元素轉化為行內塊狀元素 */

position: relative;

left: 50%;

}

/*目標元素*/

.content{

position: relative;

right: 50%;

background-color:aqua;

}

(5)CSS3的flex實現水平居中方法,法一

.contentParent{

display: flex;

flex-direction: column;

}

.content{

align-self:center;

}

(6)CSS3的flex實現水平居中方法,法二

.contentParent{

display: flex;

}

.content{

margin: auto;

}

(7)CSS3的fit-content配合左右margin為auto實現水平居中方法

.content{

width: fit-content;

margin-left: auto;

margin-right: auto;

}

參考連結 https://blog.csdn.net/dengdongxia/article/details/80297116

6、CSS3 的 flexbox(彈性盒佈局模型)以及適用場景 (猿輔導)

該佈局模型的目的是提供一種更加高效的方式來對容器中的條目進行佈局、對齊和分配空間。在傳統的佈局方式中,block 佈局是把塊在垂直方向從上到下依次排列的;而 inline 佈局則是在水平方向來排列。彈性盒佈局並沒有這樣內在的方向限制,可以由開發人員自由操作。flexbox設定父元素的display屬性為flex,則子元素都變成flex item,由此可以控制子元素的排列方式、尺寸、間距等;
試用場景:彈性佈局適合於移動前端開發,在Android和ios上也完美支援。

7、如何畫一個三角形 (星環科技)

左右邊框設定為透明,長度為底部邊框的一半。左右邊框長度必須設定,不設定則只有底部一條邊框,是不能展示的。

{width: 0; height: 0; border-top: 40px solid transparent; border-left: 40px solid transparent; border-right: 40px solid transparent; border-bottom: 40px solid #ff0000;}

8、讓一個圖片無限旋轉(螞蟻金服 2019.03)

 <img class="circle" src="001.jpg" width="400" height="400"/>

 //infinite 表示動畫無限次播放 linear表示動畫從頭到尾的速度是相同的
 .circle{
         animation: myRotation 5s linear infinite;
     }
@keyframes myRotation {
         from {transform: rotate(0deg);}
         to {transform: rotate(360deg);}
}

9、display 有哪些值?說明他們的作用?

inline預設。此元素會被顯示為內聯元素,元素前後沒有換行符。

block此元素將顯示為塊級元素,此元素前後會帶有換行符。

none此元素不會被顯示(隱藏)。

inline-block行內塊元素。(CSS2.1 新增的值)

list-item此元素會作為列表顯示。

table此元素會作為塊級表格來顯示(類似table),表格前後帶有換行符

10、position 的值?

absolute

生成絕對定位的元素,相對於 static 定位以外的第一個父元素進行定位。

元素的位置通過 "left", "top", "right" 以及 "bottom" 屬性進行規定。

fixed

生成固定定位的元素,相對於瀏覽器視窗進行定位。(老IE不支援)

元素的位置通過 "left", "top", "right" 以及 "bottom" 屬性進行規定。

relative

生成相對定位的元素,相對於其正常位置進行定位,不脫離文件流。

因此,"left:20" 會向元素的 LEFT 位置新增 20 畫素。

static預設值。

沒有定位,元素出現在正常的文件流中(忽略 top, bottom, left, right 或者 z-index 宣告)。inherit規定應該從父元素繼承 position 屬性的值。

11、為什麼要初始化 CSS 樣式

因為瀏覽器的相容問題,不同瀏覽器對有些標籤的預設值是不同的,如果沒對CSS初始化往往會出現瀏覽器之間的頁面顯示差異。

12、簡要介紹一下CSS3的新特性

  1. 在佈局方面新增了flex佈局;

  2. 在選擇器方面新增了例如:first-of-type,nth-child等選擇器;

  3. 在盒模型方面添加了box-sizing來改變盒模型,

  4. 在動畫方面增加了animation、2d變換、3d變換等。在顏色方面新增透明、rgba等,

  5. 在字型方面允許嵌入字型和設定字型陰影,同時當然也有盒子的陰影,

  6. 媒體查詢。為不同裝置基於它們的能力定義不同的樣式。

    @media screen and (min-width:960px) and (max-width:1200px){
     body{
         background:yellow;
     }
    }

13、元素的顯示與隱藏

元素的顯示隱藏方法很多,不同方法的在不同的場景下頁面效果不一,對頁面的效能也有不同的影響。

元素隱藏方法總結:

  1. 如果希望元素不可見、不佔據空間、資源會載入、DOM 可訪問: display: none

  2. 如果希望元素不可見、不能點選、但佔據空間、資源會載入,可以使用: visibility: hidden

  3. 如果希望元素不可見、不佔據空間、顯隱時可以又transition淡入淡出效果

    div{ 
    
         position: absolute;
    
         visibility: hidden;
    
         opacity: 0;
    
         transition: opacity .5s linear;
    
         background: cyan;
    }
    
    
    div.active{
         visibility: visible;
         opacity: 1;
    }

這裡使用visibility: hidden而不是display: none,是因為display: none會影響css3的transition過渡效果。 但是display: none並不會影響cssanimation動畫的效果。

  1. 如果希望元素不可見、可以點選、佔據空間,可以使用: opacity: 0

  2. 如果希望元素不可見、可以點選、不佔據空間,可以使用: opacity: 0; position: absolute;

  3. 如果希望元素不可見、不能點選、佔據空間,可以使用: position: relative; z-index: -1;

  4. 如果希望元素不可見、不能點選、不佔據空間,可以使用: position: absolute ; z-index: -1;

14、display: nonevisibility: hidden的區別

  1. display: none的元素不佔據任何空間,visibility: hidden的元素空間保留;
  2. display: none會影響css3的transition過渡效果,visibility: hidden不會;
  3. display: none隱藏產生重繪 ( repaint ) 和迴流 ( relfow ),visibility: hidden只會觸發重繪;
  4. 株連性:display: none的節點和子孫節點元素全都不可見,visibility: hidden的節點的子孫節點元素可以設定 visibility: visible顯示。visibility: hidden屬性值具有繼承性,所以子孫元素預設繼承了hidden而隱藏,但是當子孫元素重置為visibility: visible就不會被隱藏。

JavaScript部分

1. 談談對閉包的理解,閉包的用途,閉包的缺點 (阿里巴巴一面 2019.8)

  • 閉包是指有權訪問另外一個函式作用域中的變數的函式
  • 閉包的用途:
  1. 設計私有的方法和變數。
  2. 匿名函式最大的用途是建立閉包,並且還可以構建名稱空間,以減少全域性變數的使用。從而使用閉包模組化程式碼,減少全域性變數的汙染。
  • 閉包的缺點:
  1. 閉包會使得函式中的變數都被儲存在記憶體中,濫用閉包可能導致記憶體洩漏。解決方法是在函式退出之前,將不使用的區域性變數全刪了。
  2. 閉包會在父函式外部,改變父函式內部變數的值。

2. 談談js的垃圾回收機制

  • JavaScript擁有自動的垃圾回收機制,當一個值,在記憶體中失去引用時,垃圾回收機制會根據特殊的演算法找到它,並將其回收,釋放記憶體。
  • 標記清除演算法:
  1. 標記階段,垃圾回收器會從根物件開始遍歷。每一個可以從根物件訪問到的物件都會被新增一個標識,於是這個物件就被標識為可到達物件。
  2. 清除階段,垃圾回收器會對堆記憶體從頭到尾進行線性遍歷,如果發現有物件沒有被標識為可到達物件,那麼就將此物件佔用的記憶體回收,並且將原來標記為可到達物件的標識清除,以便進行下一次垃圾回收操作。
  3. 缺點:垃圾收集後有可能會造成大量的 記憶體碎片。
  • 引用計數演算法:
  1. 引用計數的含義是跟蹤記錄每個值被引用的次數,如果沒有引用指向該物件(零引用),物件將被垃圾回收機制回收。
  2. 缺點: 迴圈引用沒法回收。

3. 引起JavaScript記憶體洩漏的操作有哪些,如何防止記憶體洩漏?(搜狐一面 2019.12 )

  • 記憶體洩漏(Memory Leak)是指程式中己動態分配的堆記憶體由於某種原因程式未釋放或無法釋放,造成系統記憶體的浪費,導致程式執行速度減慢甚至系統崩潰等嚴重後果。
  • 雖然JavaScript 會自動垃圾收集,但是如果我們的程式碼寫法不當,會讓變數一直處於“進入環境”的狀態,無法被回收。
  1. 意外的全域性變數引起的記憶體洩漏

  2. 閉包引起的記憶體洩漏

  3. 未清除 dom 元素的引用的記憶體洩漏

  4. 迴圈引用引起的記憶體洩漏

  5. 被遺忘的計時器或回撥引起的記憶體洩漏

  • 防止記憶體洩漏的方法:
  1. 及時清除引用。
  2. 使用WeakSet和WeakMap,它們對於值的引用都是不計入垃圾回收機制的,所以名字裡面才會有一個"Weak",表示這是弱引用。
const wm = new WeakMap();
const element = document.getElementById('example');
wm.set(element, 'some information');
wm.get(element) // "some information"

先新建一個 Weakmap 例項。然後,將一個 DOM 節點作為鍵名存入該例項,並將一些附加資訊作為鍵值,一起存放在 WeakMap 裡面。這時,WeakMap 裡面對element的引用就是弱引用,不會被計入垃圾回收機制。

也就是說,DOM 節點物件的引用計數是1,而不是2。這時,一旦消除對該節點的引用,它佔用的記憶體就會被垃圾回收機制釋放。Weakmap 儲存的這個鍵值對,也會自動消失。

4. ajax的用途,ajax請求的五種狀態(搜狐一面 2019.10 )

  • AJAX是“Asynchronous JavaScript And XML”的縮寫,是一種實現無頁面重新整理獲取伺服器資料的混合技術。
  • XMLHttpRequest 物件是瀏覽器提供的一個API,用來順暢地向伺服器傳送請求並解析伺服器響應,當然整個過程中,瀏覽器頁面不會被重新整理。
  • .open()方法接收三個引數:請求方式(get or post),請求URL地址和是否為非同步請求的布林值。“同步”意味著一旦請求發出,任何後續的JavaScript程式碼不會再執行,“非同步”則是當請求發出後,後續的JavaScript程式碼會繼續執行,當請求成功後,會呼叫相應的回撥函式。
// 該段程式碼會啟動一個針對“example.php”的GET同步請求。
xhr.open("get", "example.php", false)
  • xhr例項的readystatechange事件會監聽xhr.readyState屬性的變化,有以下五種變化:
readyState 對應常量 描述
0(未初始化) xhr.UNSENT 請求已建立, 但未初始化(此時未呼叫open方法)
1(初始化) xhr.OPENED 請求已建立, 但未傳送 (已呼叫open方法, 但未呼叫send方法)
2(傳送資料) xhr.HEADERS_RECEIVED 請求已傳送 (send方法已呼叫, 已收到響應頭)
3(資料傳送中) xhr.LOADING 請求處理中, 因響應內容不全, 這時通過responseBody和responseText獲取可能會出現錯誤
4(完成) xhr.DONE 資料接收完畢, 此時可以通過responseBody和responseText獲取完整的響應資料
//promise 實現ajax
function ajax(method, url, data) {
    var request = new XMLHttpRequest();
    return new Promise(function (resolve, reject) {
        request.onreadystatechange = function () {
            if (request.readyState === 4) {
                if (request.status === 200) {
                    resolve(request.responseText);
                } else {
                    reject(request.status);
                }
            }
        };
        request.open(method, url);
        request.send(data);
    });
}
ajax('GET', '/api/categories').then(function (text) {   // 如果AJAX成功,獲得響應內容
    log.innerText = text;
}).catch(function (status) { // 如果AJAX失敗,獲得響應程式碼
    log.innerText = 'ERROR: ' + status;
});

5.講一講js裡面的非同步操作有哪些?( 螞蟻金服一面 2019.03)

  1. 回撥函式。 ajax典型的非同步操作,利用XMLHttpRequest,回撥函式獲取伺服器的資料傳給前端。
  2. 事件監聽。 當監聽事件發生時,先執行回撥函式,再對監聽事件進行改寫
  3. 觀察者模式,也叫訂閱釋出模式。 多個觀察者可以訂閱同一個主題,主題物件改變時,主題物件就會通知這個觀察者。
  4. promise.
  5. es7語法糖async/await
  6. co庫的generator函式

6. javascript做型別判斷的方法有哪些?

  1. typeof,可以判斷原始資料型別:undefined、boolean、string、number、symbol,但是typeof null的型別判斷為object。對於引用型別,會判斷為function、object兩種型別。
  2. instanceof ,instanceof 檢測的是原型,判斷一個例項是否屬於某種型別。
function instanceOf(left,right) {
    let proto = left.__proto__;
    let prototype = right.prototype
    while(true) {
        if(proto === null) return false;
        if(proto === prototype) return true;
        proto = proto.__proto__;
    }
}
  1. Object.prototype.toString
  • toString() 是 Object 的原型方法,呼叫該方法,預設返回當前物件的型別。
Object.prototype.toString.call('') ;   // [object String]
Object.prototype.toString.call(1) ;    // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window 是全域性物件 global 的引用

7. 如何阻止事件冒泡和預設事件?

  • 標準的DOM物件中可以使用事件物件的stopPropagation()方法來阻止事件冒泡,但在IE8以下中IE的事件物件通過設定事件物件的cancelBubble屬性為true來阻止冒泡;
  • 預設事件的話通過事件物件的preventDefault()方法來阻止,而IE通過設定事件物件的returnValue屬性為false來阻止預設事件。

使用 IntersectionObserver

  • IntersectionObserver API為開發者提供了一種可以非同步監聽目標元素與其祖先或視窗(viewport)處於交叉狀態的方式。祖先元素與視窗(viewport)被稱為根(root)。
const config = {
    root: null,    // 預設指向瀏覽器的視口,但可以是任意DOM元素
    rootMargin: '0px',  // 計算交叉時,root邊界盒的偏移量
    threshold: 0.5   // 監聽物件的交叉區域與邊界區域的比率
}
let observer = new IntersectionObserver(fucntion(entries){
    // ...
}, config)

new IntersectionObserver(function(entries, self))
  • 在entries我們得到我們的回撥函式作為Array是特殊型別的:IntersectionObserverEntry 首先IntersectionObserverEntry含有三個不同的矩形的資訊
  • 此外,IntersectionObserverEntry還提供了isIntersecting,這是一個方便的屬性,返回觀察元素是否與捕獲框架相交,
  • 另外,IntersectionObserverEntry提供了利於計算的遍歷屬性intersctionRatio:返回intersectionRect 與 boundingClientRect 的比例值.

圖片懶載入實現程式碼

  • 以載入圖片為例子,我們需要將img標籤中設定一個data-src屬性,它指向的是實際上我們需要載入的影象,而img的src指向一張預設的圖片,如果為空的話也會向伺服器傳送請求。
    <img src="default.jpg" data-src="www.example.com/1.jpg">
const images = document.querySelectorAll('[data-src]')
const config = {
    rootMargin: '0px',
    threshold: 0
};
let observer = new IntersectionObserver((entries, self)=>{
    entries.forEach(entry => {
        if(entry.isIntersecting){
         // 載入影象
         preloadImage(entry.target);
         // 解除觀察
           self.unobserve(entry.target)
        }
    })
}, config)

images.forEach(image => {
  observer.observe(image);
});

function preloadImage(img) {
  const src = img.dataset.src
  if (!src) { return; }
  img.src = src;
}

參考: 實現圖片懶載入

8. 什麼是函式節流和函式去抖?( 螞蟻金服一面 2019.03)

  • 函式去抖 debounce: 當呼叫函式n秒後,才會執行該動作,若在這n秒內又呼叫該函式則將取消前一次並重新計算執行時間。
var debounce = function(delay, cb) {
    var timer;
    return function() {
        if (timer) clearTimeout(timer);
        timer = setTimeout(function() {
            cb();
        }, delay);
    }
}
  • 函式節流 throttle: 函式節流的基本思想是函式預先設定一個執行週期,當呼叫動作的時刻大於等於執行週期則執行該動作,然後進入下一個新週期
var throttle = function(delay, cb) {
    var startTime = Date.now();
    return function() {
        var currTime = Date.now();
        if (currTime - startTime > delay) {
            cb();
            startTime = currTime;
        }
    }
}

9.如何實現對一個DOM元素的深拷貝,包括元素的繫結事件?

//使用cloneNode,但是在元素上繫結的事件不會拷貝
function clone(origin) {
    return Object.assign({},origin);
}
//實現了對原始物件的克隆,但是隻能克隆原始物件自身的值,不能克隆她繼承的值,如果想要保持繼承鏈,可以採用如下方法:
function clone(origin) {
    let originProto=Object.getPrototypeOf(origin);
    return Object.assign(Object.create(originProto),origin);
}

10. script標籤如何非同步載入?

  • 預設情況下,瀏覽器是同步載入 JavaScript 指令碼,即渲染引擎遇到 script 標籤就會停下來,等到執行完指令碼,再繼續向下渲染。如果是外部指令碼,還必須加入指令碼下載的時間。如果指令碼體積很大,下載和執行的時間就會很長,因此造成瀏覽器堵塞,使用者會感覺到瀏覽器“卡死”了,沒有任何響應。
<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>
  • defer與async的區別是:
  1. defer要等到整個頁面在記憶體中正常渲染結束(DOM 結構完全生成,以及其他指令碼執行完成),才會執行;async一旦下載完,渲染引擎就會中斷渲染,執行這個指令碼以後,再繼續渲染。一句話,defer是“渲染完再執行”,async是“下載完就執行”。
  2. 另外,如果有多個defer指令碼,會按照它們在頁面出現的順序載入,而多個async指令碼是不能保證載入順序的。

11. 講一下let、var、const的區別,談談如何凍結變數

  • var 沒有塊級作用域,支援變數提升。
  • let 有塊級作用域,不支援變數提升。不允許重複宣告,暫存性死區。
  • const 有塊級作用域,不支援變數提升,不允許重複宣告,暫存性死區。宣告一個變數一旦宣告就不能改變,改變報錯。const保證的變數的記憶體地址不得改動。如果想要將物件凍結的話,使用Object.freeze()方法
const foo=Object.freeze({});
foo.prop=123;
console.log(foo.prop);//混雜模式undefined,不起作用

12. 談談js事件迴圈機制 ( 螞蟻金服一面 2019.03)

  • 程式開始執行之後,主程式則開始執行 同步任務,碰到 非同步任務 就把它放到任務佇列中,等到同步任務全部執行完畢之後,js引擎便去檢視任務佇列有沒有可以執行的非同步任務,將非同步任務轉為同步任務,開始執行,執行完同步任務之後繼續檢視任務佇列,這個過程是一直 迴圈 的,因此這個過程就是所謂的 事件迴圈,其中任務佇列也被稱為事件佇列。通過一個任務佇列,單執行緒的js實現了非同步任務的執行,給人感覺js好像是多執行緒的。

13.如何攔截變數屬性

  • 使用proxy。new Proxy() 表示生成一個 Proxy 例項,target 引數表示所要攔截的目標物件,handler 引數也是一個物件,用來定製攔截行為。
var proxy = new Proxy({}, {
  get: function(target, property) {
    return 35;
  }
});
let obj = Object.create(proxy);
obj.time // 35

14.箭頭函式和普通函式的區別是什麼?(阿里巴巴 2019.8.5)

  • 普通函式this:
  1. this總是代表它的直接呼叫者。
  2. 在預設情況下,沒找到直接呼叫者,this指的是window。
  3. 在嚴格模式下,沒有直接呼叫者的函式中的this是undefined。
  4. 使用call,apply,bind繫結,this指的是繫結的物件。
  • 箭頭函式this:
  1. 在使用=>定義函式的時候,this的指向是 定義時所在的物件,而不是使用時所在的物件;
  2. 不能夠用作建構函式,這就是說,不能夠使用new命令,否則就會丟擲一個錯誤;
  3. 不能夠使用 arguments 物件;
  4. 不能使用 yield 命令;

15.函式柯里化理解 ( 螞蟻金服一面 2019.03)

  • 只傳遞給函式一部分引數來呼叫它,讓它返回一個函式去處理剩下的引數。
  • 用途:1.延遲計算;2.引數複用;3.動態生成函式
const curry = (fn, currArgs=[]) => {
    return function() {
        let args = Array.from(arguments);
        [].push.apply(args,currArgs);
        if (args.length < fn.length) {
            return curry.call(this,fn,...args);
        }
        return fn.apply(this,args);
    }
}

16.講講對d3的理解,講講d3與echarts的區別 (騰訊二面 2019.06)

  • d3正如其名 Data Driven Documents,其本質是將資料與 DOM 繫結,並將資料對映至 DOM 屬性上;
  • d3與echarts的區別:
  1. d3通過svg繪製圖形,可以自定義事件。svg不依賴解析度,繼續xml繪製圖形,可以操作dom。支援事件處理器,複雜度高,會減慢頁面的渲染速度。

  2. echarts通過canvas來繪製圖形,使用者通過配置 options 引數,就可很容易繪製指定圖表。canvas依賴解析度,基於js繪製圖形,不支援事件處理,能以png或者jpg的格式儲存圖片。

框架( react anglar vue等)

Vue

1、vuex原理 (百度前端 位元組跳動 騰訊 網易)

Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。每一個 Vuex 應用的核心就是 store(倉庫)。“store” 基本上就是一個容器,它包含著你的應用中大部分的狀態 ( state )。

(1)Vuex 的狀態儲存是響應式的。當 Vue 元件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的元件也會相應地得到高效更新。

(2)改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化。

vuex的store有State、 Getter、Mutation 、Action、 Module五種屬性;

  • state 為單一狀態樹,在state中需要定義我們所需要管理的陣列、物件、字串等等
  • getters 類似vue的計算屬性,主要用來過濾一些資料。
  • mutation 更改store中state狀態的唯一方法就是提交mutation,store.commit。
  • action actions可以理解為通過將mutations裡面處裡資料的方法變成可非同步的處理資料的方法,簡單的說就是非同步操作資料。view 層通過 store.dispath 來分發 action。
  • module module其實只是解決了當state中很複雜臃腫的時候,module可以將store分割成模組,每個模組中擁有自己的state、mutation、action和getter。

2. vue資料雙向繫結(騰訊 2019.04)

<body>
    <div id="app">
    <input type="text" id="txt">
    <p id="show"></p>
</div>
</body>
<script type="text/javascript">
    var obj = {}
    Object.defineProperty(obj, 'txt', {
        get: function () {
            return obj
        },
        set: function (newValue) {
            document.getElementById('txt').value = newValue
            document.getElementById('show').innerHTML = newValue
        }
    })
    document.addEventListener('keyup', function (e) {
        obj.txt = e.target.value
    })
</script>

3. 父子元件如何通訊,兄弟元件如何通訊(騰訊 2019.04 依圖 貓眼電影 bilibili)

父元件通過props屬性與子元件通訊

父元件:

<parent>
    <single-voice  ref="singleVoiceRef" :parent-to-child="singleVoiceData"/>
</parent>

data(){
    return {
        singleVoiceData:'來自父元件的資料'
    }
}

// 父元件呼叫子元件中的方法,將值傳遞給子元件

CSSmethods:{`
`this.$refs.singleVoiceRef.openSingleVoice(this.singleVoiceData)`
`}`

子元件通過props來接受資料

props: {parentToChild: {type: String,required: true}},methods:{openSingleVoice(SingleVoice) {console.log(SingleVoice)}}

子元件向父元件傳值

vue2.0只允許單向資料傳遞,我們通過出發事件來改變元件的資料

子元件程式碼:

<template>
    <div @click="open"></div>
</template>

methods: {
   open() {
        this.$emit('showbox','the msg'); //觸發showbox方法,'the msg'為向父元件傳遞的資料
    }
}

父元件程式碼:

<child @showbox="toshow" :msg="msg"></child> //監聽子元件觸發的showbox事件,然後呼叫toshow方法

methods: {
    toshow(msg) {
        this.msg = msg;
    }
}

兄弟元件之間的通訊

我們可以例項化一個vue例項,相當於一個第三方

eventVue.$emit(‘function1’,value)
eventVue.$on(‘function1’, (message) => { // 箭頭函式接收
})

建立一個公共橋樑 eventVue.js

import Vue from 'vue'
export default new Vue()

兄弟元件內引入 eventVue.js

兄弟元件一

import eventVue from './eventVue.js'
export default {
  methods: {
 // 點選通訊錄與員工進行語音聊天
    handleChatStaff(staffInfo) {
      console.log(staffInfo)
      this.staffInfo = staffInfo
      eventVue.$emit('updateChatList', this.staffInfo)
    },
  }
}

兄弟元件二

import eventVue from './eventVue.js'
export default {
 created() {
    this.updateList()
  },
  methods: {
    updateList() {
      eventVue.$on('updateChatList', (message) => { // 與phoneBook元件通訊
        console.log(message)
        this.updateChatListEvent()
      })
    },
    // 更新聊天列表
    updateChatListEvent() {},
    }

其他參考地址 :

​ https://www.imooc.com/article/68394?block_id=tuijian_wz

​ https://www.cnblogs.com/zhangruiqi/p/9386437.html

4、vue如何將一個元件打包上傳 (騰訊 2019.04)

參考地址:

​ https://www.cnblogs.com/yalong/p/10388384.html

​ https://www.jianshu.com/p/2d47396c775c

5、談談你對 Vue 生命週期的理解?(網易)

​ Vue 例項有一個完整的生命週期,也就是從開始建立、初始化資料、編譯模版、掛載 Dom -> 渲染、更新 -> 渲染、解除安裝等一系列過程,我們稱這是 Vue 的生命週期。

beforeCreate 元件例項被建立之初,元件的屬性生效之前

created 元件例項已經完全建立,屬性也繫結,但真實 dom 還沒有生成,$el 還不可用

beforeMount 在掛載開始之前被呼叫:相關的 render 函式首次被呼叫 mounted el 被新建立的 vm.$el 替換,並掛載到例項上去之後呼叫該鉤子

beforeUpdate 元件資料更新之前呼叫,發生在虛擬 DOM 打補丁之前

update 元件資料更新之後

activited keep-alive 專屬,元件被啟用時呼叫

deactivated keep-alive 專屬,元件被銷燬時呼叫

beforeDestory 元件銷燬前呼叫

destoryed 元件銷燬後呼叫

6、父元件可以監聽到子元件的生命週期嗎?

比如有父元件 Parent 和子元件 Child,如果父元件監聽到子元件掛載 mounted 就做一些邏輯處理,可以通過以下寫法實現:

// Parent.vue
<Child @mounted="doSomething"/>
    
// Child.vue
mounted() {
  this.$emit("mounted");
}
複製程式碼

以上需要手動通過 $emit 觸發父元件的事件,更簡單的方式可以在父元件引用子元件時通過 @hook 來監聽即可,如下所示:

//  Parent.vue
<Child @hook:mounted="doSomething" ></Child>

doSomething() {
   console.log('父元件監聽到 mounted 鉤子函式 ...');
},
    
//  Child.vue
mounted(){
   console.log('子元件觸發 mounted 鉤子函式 ...');
},    
    
// 以上輸出順序為:
// 子元件觸發 mounted 鉤子函式 ...
// 父元件監聽到 mounted 鉤子函式 ...     
複製程式碼

當然 @hook 方法不僅僅是可以監聽 mounted,其它的生命週期事件,例如:created,updated 等都可以監聽。

7、Vue 元件間通訊有哪幾種方式?

Vue 元件間通訊是面試常考的知識點之一,這題有點類似於開放題,你回答出越多方法當然越加分,表明你對 Vue 掌握的越熟練。Vue 元件間通訊只要指以下 3 類通訊:父子元件通訊、隔代元件通訊、兄弟元件通訊,下面我們分別介紹每種通訊方式且會說明此種方法可適用於哪類元件間通訊。

(1)props / $emit 適用 父子元件通訊

這種方法是 Vue 元件的基礎,相信大部分同學耳聞能詳,所以此處就不舉例展開介紹。

(2)ref$parent / $children 適用 父子元件通訊

  • ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子元件上,引用就指向元件例項
  • $parent / $children:訪問父 / 子例項

(3)EventBus ($emit / $on) 適用於 父子、隔代、兄弟元件通訊

這種方法通過一個空的 Vue 例項作為中央事件匯流排(事件中心),用它來觸發事件和監聽事件,從而實現任何元件間的通訊,包括父子、隔代、兄弟元件。

(4)$attrs/$listeners 適用於 隔代元件通訊

  • $attrs:包含了父作用域中不被 prop 所識別 (且獲取) 的特性繫結 ( class 和 style 除外 )。當一個元件沒有宣告任何 prop 時,這裡會包含所有父作用域的繫結 ( class 和 style 除外 ),並且可以通過 v-bind="$attrs" 傳入內部元件。通常配合 inheritAttrs 選項一起使用。
  • $listeners:包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監聽器。它可以通過 v-on="$listeners" 傳入內部元件

(5)provide / inject 適用於 隔代元件通訊

祖先元件中通過 provider 來提供變數,然後在子孫元件中通過 inject 來注入變數。 provide / inject API 主要解決了跨級元件間的通訊問題,不過它的使用場景,主要是子元件獲取上級元件的狀態,跨級元件間建立了一種主動提供與依賴注入的關係。

(6)Vuex 適用於 父子、隔代、兄弟元件通訊

Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。每一個 Vuex 應用的核心就是 store(倉庫)。“store” 基本上就是一個容器,它包含著你的應用中大部分的狀態 ( state )。

  • Vuex 的狀態儲存是響應式的。當 Vue 元件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的元件也會相應地得到高效更新。
  • 改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化。

8、你有對 Vue 專案進行哪些優化?

(1)程式碼層面的優化**

  • v-if 和 v-show 區分使用場景
  • computed 和 watch 區分使用場景
  • v-for 遍歷必須為 item 新增 key,且避免同時使用 v-if
  • 長列表效能優化
  • 事件的銷燬
  • 圖片資源懶載入
  • 路由懶載入
  • 第三方外掛的按需引入
  • 優化無限列表效能
  • 服務端渲染 SSR or 預渲染

(2)Webpack 層面的優化

  • Webpack 對圖片進行壓縮
  • 減少 ES6 轉為 ES5 的冗餘程式碼
  • 提取公共程式碼
  • 模板預編譯
  • 提取元件的 CSS
  • 優化 SourceMap
  • 構建結果輸出分析
  • Vue 專案的編譯優化

(3)基礎的 Web 技術的優化

  • 開啟 gzip 壓縮
  • 瀏覽器快取
  • CDN 的使用
  • 使用 Chrome Performance 查詢效能瓶頸

9、vuejs與angularjs以及react的區別?(天壤智慧)

與angularjs的區別:

1、Angular.js的學習成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比較簡單、直觀。

2、在效能上,Angular.js依賴對資料做髒檢查,所以watcher越多越慢。

3、Vue.js使用基於依賴追蹤的觀察並且使用非同步佇列更新。所有的資料都是獨立出發的。

對於龐大的應用來說,這個優化差異還是比較明顯的。

與reactjs的區別:

React 依賴Virtual DOM,而Vue.js使用的是DOM模板。React採用的Virtual DOM會對渲染出來的結果做髒檢查。
Vue.js在模板中提供了指令,過濾器等,可以非常方便,快捷地操作Virtual DOM

10、的作用是什麼,如何使用?

包裹動態元件時,會快取不活動的元件例項,主要用於保留元件狀態或避免重新渲染;

使用:簡單頁面時

快取:

不快取:

使用:複雜專案時

路由字典中定義{path:’/detail’,meta:{keepAlive:false/true}} 是否快取

根目錄中:

11 、scss是什麼?在vue.cli中的安裝使用步驟是?有哪幾大特性?

css的預編譯。

使用步驟:

​ 第一步:用npm 下三個loader(sass-loader、css-loader、node-sass)

​ 第二步:在build目錄找到webpack.base.config.js,在那個extends屬性中加一個拓展.scss

​ 第三步:還是在同一個檔案,配置一個module屬性

​ 第四步:然後在元件的style標籤加上lang屬性 ,例如:lang=”scss”

有哪幾大特性:

​ 1、可以用變數,例如($變數名稱=值);

​ 2、可以用混合器,例如:定義了字型的混合器

@mixin font-dpr($font-size){
    $font:$font-size/2;
    font-size: $font;
    [data-dpr="2"] & { font-size: $font+2px;}
    [data-dpr="3"] & { font-size: $font+4px;}
}

使用方法如下

.div{

  @include font-dpr(24px);

}

​ 3、可以巢狀

12、vuex原理

  • vuex的store有State、 Getter、Mutation 、Action、 Module五種屬性;
  • state 為單一狀態樹,在state中需要定義我們所需要管理的陣列、物件、字串等等
  • getters 類似vue的計算屬性,主要用來過濾一些資料。
  • mutation 更改store中state狀態的唯一方法就是提交mutation,store.commit。
  • action actions可以理解為通過將mutations裡面處裡資料的方法變成可非同步的處理資料的方法,簡單的說就是非同步操作資料。view 層通過 store.dispath 來分發 action。
  • module module其實只是解決了當state中很複雜臃腫的時候,module可以將store分割成模組,每個模組中擁有自己的state、mutation、action和getter。

13、 vue資料雙向繫結

<body>
    <div id="app">
    <input type="text" id="txt">
    <p id="show"></p>
</div>
</body>
<script type="text/javascript">
    var obj = {}
    Object.defineProperty(obj, 'txt', {
        get: function () {
            return obj
        },
        set: function (newValue) {
            document.getElementById('txt').value = newValue
            document.getElementById('show').innerHTML = newValue
        }
    })
    document.addEventListener('keyup', function (e) {
        obj.txt = e.target.value
    })
</script>

react

1、為什麼選擇使用框架而不是原生

框架的好處:

​ 元件化: 其中以 React 的元件化最為徹底,甚至可以到函式級別的原子元件,高度的元件化可以是我們的工程易於維護、易於組合拓展。
​ 天然分層: JQuery 時代的程式碼大部分情況下是麵條程式碼,耦合嚴重,現代框架不管是 MVC、MVP還是MVVM 模式都能幫助我們進行分層,程式碼解耦更易於讀寫。
​ 生態: 現在主流前端框架都自帶生態,不管是資料流管理架構還是 UI 庫都有成熟的解決方案。
​ 開發效率: 現代前端框架都預設自動更新DOM,而非我們手動操作,解放了開發者的手動DOM成本,提高開發效率,從根本上解決了UI 與狀態同步問題.

虛擬DOM的優劣如何?
優點:

​ 保證效能下限: 虛擬DOM可以經過diff找出最小差異,然後批量進行patch,這種操作雖然比不上手動優化,但是比起粗暴的DOM操作效能要好很多,因此虛擬DOM可以保證效能下限
無需手動操作DOM: 虛擬DOM的diff和patch都是在一次更新中自動進行的,我們無需手動操作DOM,極大提高開發效率
​ 跨平臺: 虛擬DOM本質上是JavaScript物件,而DOM與平臺強相關,相比之下虛擬DOM可以進行更方便地跨平臺操作,例如伺服器渲染、移動端開發等等

​ 缺點:

​ 無法進行極致優化: 在一些效能要求極高的應用中虛擬DOM無法進行鍼對性的極致優化,比如VScode採用直接手動操作DOM的方式進行極端的效能優化

2、為什麼虛擬dom會提高效能? (美團 )

虛擬dom相當於在js和真實dom中間加了一個快取,利用dom diff演算法避免了沒有必要的dom操作,從而提高效能。虛擬DOM本質上是JavaScript物件,是對真實DOM的抽象,狀態變更時,記錄新樹和舊樹的差異,最後把差異更新到真正的dom中

具體實現步驟如下:

1.用 JavaScript 物件結構表示 DOM 樹的結構;然後用這個樹構建一個真正的 DOM 樹,插到文件當中;

2.當狀態變更的時候,重新構造一棵新的物件樹。然後用新的樹和舊的樹進行比較,記錄兩棵樹差異;

把2所記錄的差異應用到步驟1所構建的真正的DOM樹上,檢視就更新了

3、react生命週期函式 (曠世面試 2019.06 拍拍貸 天壤智慧)

​ 元件載入之前,元件載入完成,以及元件更新資料,元件銷燬。觸發的一系列的方法 ,這就是元件的生命週期函式

​ 1、初始化階段:

​ getDefaultProps:獲取例項的預設屬性

​ getInitialState:獲取每個例項的初始化狀態

​ componentWillMount:元件即將被裝載、渲染到頁面上

​ render:元件在這裡生成虛擬的DOM節點

​ componentDidMount:元件真正在被裝載之後

​ 2、執行中狀態:

​ componentWillReceiveProps:元件將要接收到屬性的時候呼叫

​ shouldComponentUpdate:元件接受到新屬性或者新狀態的時候(可以返回false,接收資料後不更新,阻止render呼叫,後面的函式不會被繼續執行了)

​ componentWillUpdate:元件即將更新不能修改屬性和狀態

​ render:元件重新描繪

​ componentDidUpdate:元件已經更新

​ 3、銷燬階段:

​ componentWillUnmount:元件即將銷燬

必須記住的生命週期函式:

*載入的時候:componentWillMount、 render 、componentDidMount(dom操作)

更新的時候:componentWillUpdate、render、componentDidUpdate

*銷燬的時候: componentWillUnmount

4、什麼是Diff演算法? (美團 )

diff演算法作為Virtual DOM的加速器,其演算法的改進優化是React整個介面渲染的基礎和效能的保障,同時也是React原始碼中最神祕的,最不可思議的部分

傳統diff演算法通過迴圈遞迴對比差異,演算法複雜度為O(n3)。react diff算法制定了三條策略,將演算法複雜度從 O(n3)降低到O(n)。

  • WebUI中DOM節點跨節點的操作特別少,可以忽略不計。
  • 擁有相同類的元件會擁有相似的DOM結構。擁有不同類的元件會生成不同的DOM結構。
  • 同一層級的子節點,可以根據唯一的ID來區分。

針對這三個策略,react diff實施的具體策略是:

  1. diff對樹進行分層比較,只對比兩棵樹同級別的節點。跨層級移動節點,將會導致節點刪除,重新插入,無法複用。
  2. diff對元件進行類比較,類相同的遞迴diff子節點,不同的直接銷燬重建。diff對同一層級的子節點進行處理時,會根據key進行簡要的複用。兩棵樹中存在相同key的節點時,只會移動節點。

5、React效能優化方式

由於react中效能主要耗費在於update階段的diff演算法,因此效能優化也主要針對diff演算法。

1.減少diff演算法觸發次數

​ A、 setState機制在正常執行時,由於批更新策略,已經降低了update過程的觸發次數。
因此,setState優化主要在於非批更新階段中(timeout/Promise回撥),減少setState的觸發次數。
常見的業務場景即處理介面回撥時,無論資料處理多麼複雜,保證最後只調用一次setState。

​ B、父元件的render必然會觸發子元件進入update階段(無論props是否更新)。此時最常用的優化方案即為shouldComponentUpdate方法。最常見的方式為進行this.props和this.state的淺比較來判斷元件是否需要更新。或者直接使用PureComponent,原理一致。需要注意的是,父元件的render函式如果寫的不規範,將會導致上述的策略失效。

​ C、使用shouldComponentUpdate鉤子,根據具體的業務狀態,減少不必要的props變化導致的渲染。如一個不用於渲染的props導致的update。
另外, 也要儘量避免在shouldComponentUpdate 中做一些比較複雜的操作, 比如超大資料的pick操作等。

合理設計state,不需要渲染的state,儘量使用例項成員變數。

2、正確使用diff演算法

​ 不使用跨層級移動節點的操作。

​ 對於條件渲染多個節點時,儘量採用隱藏等方式切換節點,而不是替換節點。

​ 儘量避免將後面的子節點移動到前面的操作,當節點數量較多時,會產生一定的效能問題。

效能檢測工具
React官方提供的:React.addons.Perf

6、你瞭解React嗎?

React是facebook搞出來的一個輕量級的元件庫,用於解決前端檢視層的一些問題,就是MVC中V層的問題,它內部的Instagram網站就是用React搭建的。

解決了三個問題: 1.元件複用問題, 2.效能問題,3.相容性問題:

React 會建立一個虛擬 DOM(virtual DOM)。當一個元件中的狀態改變時,React 首先會通過 "diffing" 演算法來標記虛擬 DOM 中的改變,第二步是調節(reconciliation),會用 diff 的結果來更新 DOM。

優點:

​ 1.只需檢視 render 函式就會很容易知道一個元件是如何被渲染的

​ 2.JSX 的引入,使得元件的程式碼更加可讀,也更容易看懂元件的佈局,或者元件之間是如何互相引用的

​ 3.支援服務端渲染,這可以改進 SEO 和效能

​ 4.易於測試

​ 5.React 只關注 View 層,所以可以和其它任何框架(如Backbone.js, Angular.js)一起使用

angular

1、React 與 Angular 有何不同

Angular是一個成熟的MVC框架,帶有很多特定的特性,比如服務、指令、模板、模組、解析器等等。React是一個非常輕量級的庫,它只關注MVC的檢視部分。

Angular遵循兩個方向的資料流,而React遵循從上到下的單向資料流。React在開發特性時給了開發人員很大的自由,例如,呼叫API的方式、路由等等。我們不需要包括路由器庫,除非我們需要它在我們的專案。

2、angular 核心?

AngularJS是為了克服HTML在構建應用上的不足而設計的。 AngularJS有著諸多特性,最為核心的是:

  • MVC
  • 模組化
  • 自動化雙向資料繫結
  • 語義化標籤、依賴注入等等

3、簡述angular的資料繫結

  Angular 在 scope 模型上設定了一個監聽佇列,用來監聽資料變化並更新 view 。每次繫結一個東西到 view 上時 AngularJS 就會往 $watch 佇列裡插入一條 $watch ,用來檢測它監視的 model 裡是否有變化的東西。當瀏覽器接收到可以被 angular context 處理的事件時, $digest 迴圈就會觸發,遍歷所有的 $watch ,最後更新 dom。

4、AngularJS的資料雙向繫結是怎麼實現的?

  1、每個雙向繫結的元素都有一個watcher
  2、在某些事件發生的時候,呼叫digest髒資料檢測。
    這些事件有:表單元素內容變化、Ajax請求響應、點選按鈕執行的函式等。
  3、髒資料檢測會檢測rootscope下所有被watcher的元素。
    $digest函式就是髒資料監測

5、單頁應用有哪些優缺點?(網易雷火)

單頁 Web 應用 (single-page application 簡稱為 SPA) 是一種特殊的 Web 應用。它將所有的活動侷限於一個Web頁面中,僅在該Web頁面初始化時載入相應的HTML、JavaScript 和 CSS。一旦頁面載入完成了,SPA不會因為使用者的操作而進行頁面的重新載入或跳轉。取而代之的是利用 JavaScript 動態的變換HTML的內容,從而實現UI與使用者的互動。由於避免了頁面的重新載入,SPA 可以提供較為流暢的使用者體驗。

1、優點:

1).良好的互動體驗

使用者不需要重新重新整理頁面,獲取資料也是通過Ajax非同步獲取,頁面顯示流暢。

2).良好的前後端工作分離模式

單頁Web應用可以和RESTful規約一起使用,通過REST API提供介面資料,並使用Ajax非同步獲取,這樣有助於分離客戶端和伺服器端工作。更進一步,可以在客戶端也可以分解為靜態頁面和頁面互動兩個部分。

3).減輕伺服器壓力

伺服器只用出資料就可以,不用管展示邏輯和頁面合成,吞吐能力會提高几倍;

4).共用一套後端程式程式碼
不用修改後端程式程式碼就可以同時用於Web介面、手機、平板等多種客戶端;
2、缺點:

1).SEO難度較高

由於所有的內容都在一個頁面中動態替換顯示,所以在SEO上其有著天然的弱勢,所以如果你的站點對SEO很看重,且要用單頁應用,那麼就做些靜態頁面給搜尋引擎用吧。

2).前進、後退管理

由於單頁Web應用在一個頁面中顯示所有的內容,所以不能使用瀏覽器的前進後退功能,所有的頁面切換需要自己建立堆疊管理,當然此問題也有解決方案,比如利用URI中的雜湊+iframe實現。

3).初次載入耗時多

為實現單頁Web應用功能及顯示效果,需要在載入頁面的時候將JavaScript、CSS統一載入,部分頁面可以在需要的時候載入。所以必須對JavaScript及CSS程式碼進行合併壓縮處理,如果使用第三方庫,建議使用一些大公司的CDN,因此頻寬的消耗是必然的。

結語

還有2件事拜託大家
一:求贊 求收藏 求分享 求留言,讓更多的人看到這篇內容
二:歡迎新增我的個人微信
備註“資料”, 300多篇原創技術文章,海量的視訊資料即可獲得
備註“加群”,我會拉你進技術交流群,群裡大牛學霸具在,哪怕您做個潛水魚也會學到很多東西

相關連結

參考資料

11道瀏覽器原理面試題

這兒有20道大廠面試題等你查收

2020 前端面試 | “HTML + CSS + JS”專題

圖解瀏覽器的工作原理(史上最全)

BAT前端經典面試問題:史上最最最詳細的手寫Promise教程

webpack 中文