前端面試題分享

前端基礎:

1.講講對web標準以及w3c的理解與認識

web能夠簡單分爲:結構、表現、行爲。三部分獨立開來使其模塊化
w3c是對web作出規範,使代碼更嚴謹,作出來的網頁更易使用,維護。

w3c作出的規範可分爲以下:
結構上:(標籤規範對頁面的搜索權重有很大關係,寫的越規範網站在搜索排名越靠前)javascript

  •   標籤閉合、標籤小寫、不亂嵌套

表現、行爲上:php

  •  使用外鏈的css和js腳本,提升頁面渲染效率。
  •   少使用行內樣式,類名要作到見名知意

2.說明ajax請求的時候post和get的區別

發送機制css

一、get請求會將參數跟在URL後面進行參數傳遞,而post請求則是做爲http消息的實體內容發送給web服務器;
二、get提交的數據限制是1024字節,這種顯示是來自特定瀏覽器和服務器對它的限制。如ie的URL長度限制是2083字節,火狐理論上沒有長度限制。注意這個限制是URL 的整個長度,而不是參數的長度。
三、get方式請求的數據會被瀏覽器緩存起來。由於其餘人能夠從瀏覽器的歷史記錄中讀取到這些數據,好比:帳號或者密碼等。在某種狀況下,get方式會帶來嚴重的安全問題,而post相對來講能夠避免這些問題。html

在服務端的區別前端

一、客戶端請求使用get時,服務端使用Request.QueryString來獲取,而客戶端使用post請求時,服務端使用Request.Form來獲取。
二、post用於建立資源,資源的內容會被編入http請示的內容中,例如,處理定貨表單等。
三、當請求無反作用時(如進行搜索),使用get方法,當請求有反作用時(如添加數據),則用post方法。vue

3.如何對網站的文件和資源進行優化,主流的解決方案包括哪些?

1. 文件合併
2. 文件最小化/文件壓縮
3. 使用 CDN 託管
4. 緩存的使用(多個域名來提供緩存)
5. 其餘java

4.閉包是什麼?有什麼特性?對頁面有什麼影響?

「官方」的解釋是:所謂「閉包」,指的是一個擁有許多變量和綁定了這些變量的環境的表達式(一般是一個函數),於是這些變量也是該表達式的一部分。webpack

通俗的講:就是函數a的內部函數b,被函數a外部的一個變量引用的時候,就建立了一個閉包。web

閉包的特性:面試

①.封閉性:外界沒法訪問閉包內部的數據,若是在閉包內聲明變量,外界是沒法訪問的,除非閉包主動向外界提供訪問接口;
②.持久性:通常的函數,調用完畢以後,系統自動註銷函數,而對於閉包來講,在外部函數被調用以後,閉包結構依然保存在
系統中,閉包中的數據依然存在,從而實現對數據的持久使用。

優勢:

① 減小全局變量。

② 減小傳遞函數的參數量

③ 封裝;

   缺點:
 使用閉包會佔有內存資源,過多的使用閉包會致使內存溢出等.

5.https頁面下直接請求http會遇到什麼問題?

在https頁面下的帶有相對路徑的請求都會與頁面的協議保持一致。若是想在https頁面下發送http的請求,若是隻把連接寫死成爲http的絕對路徑是不夠的,這樣會致使http的請求與總頁面https的請求的session不一致。

爲何呢?緣由是https的請求中服務器發回的cookie是標記爲"secure"的,而http的請求時非"secure","因爲在服務器端secure"的cookie不會兼容非"secure"的,因此當http的請求攜帶着同一jsessionid的cookie到達服務器時,服務器拒絕非"secure",進而返回的結果是一個新的非"secure"的cookie,因而兩個session就不一樣了。

 怎麼解決呢?由緣由分析可知,兩個session不一樣,更具體說是cookie的狀態不一樣。那麼辦法是,在接收到第一個https請求的響應後 到 發送下面的http請求以前,將cookie去"secure"狀態,可是又要保證jsessionid不變。具體操做能夠新建一個cookie(新建的是非"secure"狀態),而後賦予同一個jessionid,而後加入response中。

6.js繼承的方式及其優缺點

推薦文章:傳送門

人家講得已經很清楚了,案例跟優缺點都整理出來了,推薦閱讀

7.解釋ajax的工做原理

一、建立ajax對象(XMLHttpRequest/ActiveXObject(Microsoft.XMLHttp))

二、打開連接 open(請求方式,'請求路徑',同步/異步)

三、發送 send()

四、當ajax對象完成第四步(onreadystatechange)數據接收完成,判斷對象狀態碼(readystate) 4  HTTP響應徹底接收  在判斷http響應狀態(status)200-300之間或者304(緩存)執行回調函數 獲取的數據轉成字符串格式(responseText)

具體代碼參考網上...

JS部分:

1.打印如下執行結果

console.log('script start');
setTimeout(() => {
    console.log('setTimeout');
},0)
Promise.resolve().then(function() {
    console.log('promise1');
}).then(function() {
    console.log('promise2');
});
console.log('script end')

考察的是代碼執行順序問題,定時器和主程序屬於宏任務,Promise中then的回調屬於微任務,在每一個宏任務裏面都會先執行完微任務再去執行下一個宏任務。
本題執行邏輯應該是主線程中console.log('script start');碰到定時器,把這個宏任務扔事件隊列裏面,繼續向下,碰到Promise.then異步任務,繼續扔隊列裏面,執行console.log('script end');再去執行當前宏任務裏面的微任務,即Promise.then回調函數,最後執行第二個宏任務定時器.

執行結果:
script start
script end
promise1
promise2
setTimeout

2.打印如下執行結果

const promise = new Promise((resolve,reject) => {
    console.log(1);
    resolve();
    console.log(2);
});
promise.then(()=>{
    console.log(3);
});
console.log(4);

Promise 構造函數是同步執行的,promise.then 中的函數是異步執行的。因此

執行結果:
1
2
4
3

3.打印如下執行結果

var funcs = [];
for(var i=0;i<10;i++) {
    funcs.push(function() {
        console.log(i);
    });
}
funcs.forEach(function(func) {
    func();
});

基礎題,匿名函數中的 i 值只有在函數調用執行的時候纔會去尋找對應變量的,for循環結束後執行func()時,此時i變量已經變爲10(最後有個i++),因此循環打印了十次10,想依次打印0-9的話可使用當即執行函數解決或者使用ES6的塊級做用域let聲明變量i.
image.png

4.解釋0.1 + 0.2 !== 0.3

js中number類型的數字都是採用64位的雙精度浮點數進行存儲的,其中1個符號位(0正1負),11個指數位,52個尾數位。0.1用二進制表示以下:
0.000110011001100110011001100110011001100110011001100110011...
如上能夠看出0.1二進制表示時尾數是超過52位的, 因此52位以後的會被捨去,這就有了浮點數存儲的精度丟失問題。
image.png

5.寫出下列執行結果:

setTimeout(()=>{
    console.log('b')
    new Promise((resolve,reject)=>{
        console.log('c');
        resolve()
    }).then(res => {
        console.log('f')
    })
},0);
new Promise((resolve,reject) => {
    console.log('d')
    resolve()
}).then(res => {
    console.log('a')
    setTimeout(()=>{
        console.log('e')
    },0)
})

原理同第一題,答案爲:dabcfe

6.寫出如下程序運行結果:

let test1 = () => {
    console.log(this);
};
function test2() {
    console.log(this);
};
class t {
    test() {
        console.log(this);
    }
}
let test3 = t.prototype.test;

test1.call(null);
test2.call(null);
test3.call(null);

先給出正確答案:

/// window  ; window ; null  (非嚴格模式),
/// window  ; null   ; null   (嚴格模式)

當call或apply的第一個參數爲null || undefined時 this指向window ||global

call方法的參數,應該是一個對象。若是參數爲空、null和undefined,則默認傳入全局對象

類和模塊的內部,默認就是嚴格模式,因此不須要使用use strict指定運行模式。只要你的代碼寫在類或模塊之中,就只有嚴格模式可用。考慮到將來全部的代碼,其實都是運行在模塊之中,因此 ES6 實際上把整個語言升級到了嚴格模式。

順便解釋一下call的用法,apply相似,參數不一樣而已:

call方法

語法:call(thisobj,[argq,arg2])

定義:調用一個對象的一個方法,以另外一個對象替換當前對象

說明:

call方法能夠用來代替一個對象調用一個方法,call方法能夠將一個函數的對象上下文從初始化改成新的對象,也就是括號裏面的本來的對象改成call()前面的對象、即用thisobj代替call前面的東西,最終用thisobj這個對象去執行call前面的方法。

若是沒有提供 thisObj 參數,那麼 Global 對象被用做 thisObj。 

其實call纔是函數調用最原始的方式,如今咱們使用的直接myFunc(args)調用函數的方式其實就是call調用的語法糖

7.使用js實現隨機選取10–100之間的10個數字,存入一個數組,並排序

let iArray = []; 
function getRandom(istart, iend){
    var iChoice =iend - istart + 1;
    return  Math.floor(Math.random() * iChoice + istart);
}
/*Math.random()就是獲取 0-1 之間的隨機數(永遠獲取不到 1)*/
for(let i=0; i<10; i++){
let result= getRandom(10,100);
iArray.push(result);
}
iArray.sort(function(a,b){
 return a>b;
}); 
console.log(iArray);

8.輸出如下運行結果:

let foo=1;
function bar(){
    foo=10;
    return;
    functionfoo(){}
}

bar();
console.log(foo); //1
爲何是1而不是10先分析一下每步流程:
第一步:varfoo=1;全局變量foo被初始化賦值成1。
第二步:執行bar();方法。
第三步:bar()方法裏,函數聲明functionfoo(){}優先處理,這裏JavaScript解析語法時(在運行以前)函數優先於一切。因此foo被初始化賦值爲function(){};
第四步:執行foo=10;這裏製造了一個假象,認爲沒有用var聲明指向的是外層foo=1;。其實不是。而是先在自身函數體裏找有沒有foo聲明,找到以前聲明的functionfoo(){};賦值成10,只是局部變量的值改寫。
第五步:輸出foo,這時找的是全局變量varfoo=1;輸出1。

CSS部分:

1.分別寫出box的高度

<style>
    .box {
        line-height: 24px;
        background-color: lightblue;
    }
    .box span {
        line-height: 48px;
        border: 1px solid;
    }
</style>
<div class="box">
    <span>content...</span>
</div>

考察的是inline box模型,它的工做就是包裹每行文字,一個沒有設置height屬性的div的高度就是由一個一個line boxes的高度堆積而成的,撐開div高度的是line-height不是文字內容.MDN 文檔中對line-height的描述以下:

line-height CSS 屬性用於設置多行元素的空間量, 好比文本。對於塊級元素, 它指定元素行盒(line boxes)的最小高度。 對於非替代的inline元素, 它用於計算行盒(line box)的高度。
適用元素 all elements. It also applies to ::first-letter and ::first-line.
如上面最終顯示 .box 容器 height = 48px;
1.
將<span>標籤裏的內容 改成<span>content ... <br> content ... </span> 後,
.box 的height = 96px(48px*2)。
2.
將<span>標籤裏的內容 改成content ... <br><span> content ... </span> 後,
.box 的height = 48 + 24 = 72px。

2.css實現0.5像素的邊框

半像素邊框固然不是簡單地把1px改成0.5px,瀏覽器中最小的像素單位爲1像素,是不能識別0.5個像素,

1.設置目標元素做爲定位參照
box{position:relative}

2.給目標元素添加一個僞元素before或者after,並設置絕對定位
.box:before{content:""; position:absolute;}

3.給僞元素添加1px邊框
border:1px solid #000;

4.設置僞元素的寬高爲目標元素的2倍
width:200%; height:200%;

5.縮小0.5倍(縮放到原來大小)
transform-origin: 0 0;
transform:scale(0.5,0.5);

6.把border 邊框在線框內繪製
box-sizing:border-box;

image.png

Vue框架部分:

1.vue組件中的data爲何必須是個函數

簡單地說,對象是引用數據類型,那你每次導入這個組件的時候,其實引用的是同一個內存地址,componentA改變了引用這塊地址的數據後,componentB中的這塊地址對應的數據也會被改變。
那是由於在js中,函數的{}纔有獨立的做用域,對象的{},if(){}是不構成做用域的.
函數裏面,每調用一次函數就會建立一個新的函數做用域,他們之間是互相獨立的,這樣的話,無論你同時引入同一個組件多少次,他們之間的組件屬性都是獨立的,互不干擾。

2.解釋vue的響應式原理

vue的響應式核心是Object.defineProperty實現的.

Object.defineProperty(obj, key, {
    set:function(){},
    get:function(){}
})

被Object.defineProperty綁定過的數據會被監聽到,改變這個對象的時候會觸發get和set事件,這也是vue的model層和view層通訊的基礎,其實vue中的Observer就是基於Object.defineProperty來實現的。
Observer是數據的觀察者,與model層直接通訊,當數據更改時,它會通知dep(專門管理數據監聽依賴的東西),dep會收集到它所須要的依賴,當get的時候,收集訂閱者(這裏的訂閱者實際上是觀察者模式下的訂閱者,簡單地說,就是它須要知道具體get什麼訂閱者,什麼是觀察者模式和發佈訂閱者設計模式,具體網上不少相關資料解釋),把他添加到依賴,好比,watch和computed都依賴一個data進行監聽或者計算,那麼dep會將這兩個不一樣的依賴收集。當set的時候會發布更新,通知watcher更新view層。
一個屬性可能有多個依賴,每一個響應式數據都有一個Dep來管理它的依賴。
每個依賴又是依靠一箇中介的角色來通知變化從而更新視圖的,所以watcher能通知變化去執行各自的代碼,固然它也能區分本身所屬的依賴,好比本身是屬於data仍是watch仍是computed.
放兩張網上的圖能夠更明瞭的說明他們之間的關係,也能夠看看大佬們的文章,講的更仔細,想學會這種設計模式仍是要擼源碼,應付面試已經夠了。
image.png
原圖連接

image.png
原圖連接

3.解釋v-model的原理

v-model本質上就是一個語法糖,實現原理其實就是上面說過的數據綁定加上底層的input事件監聽,經過v-bind綁定一個數據傳給子組件,子組件裏面的model默認用value屬性接受,而後子組件監聽數據發生變化,emit觸發父組件的input事件,經過觸發事件來進行傳值,實現了父子組件數據的雙向綁定。

4.設計模式-發佈訂閱者模式

定義了一種一對多的依賴關係,即當一個對象的狀態發生改變的時候,全部依賴他的對象都會獲得通知。

觀察者模式是由具體目標(發佈者/被觀察者)調度的,而發佈/訂閱模式是由獨立的調度中心進行調度,因此觀察者模式的訂閱者與發佈者之間是存在依賴的,而發佈/訂閱模式則不會(至關於一箇中介的角色,一個全局的Event,發佈者不須要知道具體要通知誰,訂閱者也不須要知道具體是誰通知的);能夠說發佈訂閱模式是觀察者模式進一步解耦,在實際中被大量運用的一種模式。

5.vue.js如何作單元測試?

單元測試:按空間切割,對每一個組件進行測試

好比,我要測試日期輸入框,那麼我編寫的測試用例應該包括如下部分:

  • 默認日期是否爲當天
  • 當用戶選擇日期範圍,data是否會作相應改變
  • ...

E2E測試:按時間切割,對每一個流程進行測試

好比,我要測試搜索功能,那麼我編寫的測試用例應該模擬如下步驟:

  • 打開主頁
  • 點擊菜單跳轉到詳情頁
  • 輸入搜索條件
  • 點擊搜索
  • 查看搜索結果是否與預期一致
vue init webpack test

6.vue v-on綁定多個方法

1.v-on綁定多個方法:
<p v-on="{click:dbClick,mousemove:MouseClick}"></p>

2.一個事件綁定多個函數:
<p @click="one(),two()">點擊</p>

7.舉例vue中經常使用的修飾符

.lazy:

v-modeil不用多說,輸入框改變,這個數據就會改變,lazy這個修飾符會在光標離開input框纔會更新數據:

<input type="text" v-model.lazy="value">

.trim:

輸入框過濾首尾的空格:

<input type="text" v-model.trim="value">

.number:

先輸入數字就會限制輸入只能是數字,先字符串就至關於沒有加number,注意,不是輸入框不能輸入字符串,是這個數據是數字:

<input type="text" v-model.number="value">

.stop:

阻止事件冒泡,至關於調用了event.stopPropagation()方法。這個應該不須要解釋:

<button @click.stop="test">test</button>

.prevent:

阻止默認行爲,至關於調用了event.preventDefault()方法,好比表單的提交、a標籤的跳轉就是默認事件:

<a @click.prevent="test">test</a>

.self:

只有元素自己觸發時才觸發方法,就是隻有點擊元素自己纔會觸發。好比一個div裏面有個按鈕,div和按鈕都有事件,咱們點擊按鈕,div綁定的方法也會觸發,若是div的click加上self,只有點擊到div的時候纔會觸發,變相的算是阻止冒泡:

<div @click.self="test"></div>

.once:

只能用一次,不管點擊幾回,執行一次以後都不會再執行:

<div @click.once="test"></div>

.capture:

事件的完整機制是捕獲-目標-冒泡,事件觸發是目標往外冒泡,好比:

<div @click="test(1)">  <button @click="test(2)">test</button></div>

順序是2 1,capture的做用就是讓這個順序相反:

<div @click.capture="test(1)">  <button @click="test(2)">test</button></div>

先1 後2。

.passive:

其實我不怎麼理解,官網解釋說能夠提高移動端的性能,查了查,大概解釋就是每次滾動都會有一個默認事件觸發,加了這個就是告訴瀏覽器,不須要查詢,不須要觸發這個默認事件preventDefault:

<!-- 滾動事件的默認行爲 (即滾動行爲) 將會當即觸發 --> 

<!-- 而不會等待 `onScroll` 完成 -->

 <!-- 這其中包含 `event.preventDefault()` 的狀況 -->

<div v-on:scroll.passive="onScroll">...</div>

.native:

組件綁定當前組件的事件是不會觸發的,須要用native才能觸發:

<My-component @click="shout(3)"></My-component>

鼠標.left、.reight、.middle:

就是鼠標點擊的時候就觸發:

<button @click.right="test">test</button>

.keyCode:

監聽按鍵的指令,具體能夠查看vue的鍵碼對應表:

<input type="text" @keyup.enter="test(1)">

<button @click.enter="test(1)">test</button>

注意,只有你點擊過一次或者聚焦到這個輸入框才能使用鍵盤觸發。

.exact:

系統修飾鍵,只有按着這個鍵而後用鼠標點擊纔會觸發,官網解釋:

<!-- 即便 Alt 或 Shift 被一同按下時也會觸發 -->

 <button @click.ctrl="onClick">A</button>

<!-- 有且只有 Ctrl 被按下的時候才觸發 -->

<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 沒有任何系統修飾符被按下的時候才觸發 -->
<button @click.exact="onClick">A</button>

可是我試了一下沒有用。

.sync

對prop進行雙向綁定,我的暫時用不習慣:

//父組件

<fa-comp :fatest.sync="test"></fa-comp>

//子組件

this.$emit('update:fatest,sontest);

......

持續更新~

推薦大佬的一篇關於瀏覽器和js線程的文章,炒雞棒

相關文章
相關標籤/搜索