Browser
DOM事件模型
一:DOM leave1 比如onclick只是一個屬性,可以被覆蓋,所以一個元素只能有一個onclick事件 寫在字串裡相當於執行字串裡的程式碼
二: DOM L2中,事件註冊(事件監聽佇列)
**三:**事件觸發時傳播的方式:先捕獲到最底層,再冒泡到最上層- 冒泡:addEventListener的第三個引數傳入
false
或者 不傳 引數 兒子,爸爸,爺爺 - 捕獲:addEventListener的第三個引數傳入
true
爺爺,爸爸,兒子 冒泡和捕獲的執行順序不受程式碼順序控制。只有同一個元素的事件佇列才受於程式碼中的事件繫結順序有關 - 阻止冒泡
event.stopPropagation()
。stopPropagation,停止傳播,不要再告訴父母了,不要再往上執行冒泡事件了 - 禁止預設效果與阻止冒泡
aTag.addEventListener("click",function(e){ e.preventDefault();//禁止預設效果 e.stopPropagation();//阻止冒泡 }); 複製程式碼
事件觸發一般來說會按照上面的順序進行,但是也有特例,如果給一個目標節點同時註冊冒泡和捕獲事件,事件觸發會按照註冊的順序執行。
// 以下會先列印冒泡然後是捕獲
node.addEventListener('click',(event) =>{
console.log('冒泡')
},false);
node.addEventListener('click',(event) =>{
console.log('捕獲 ')
},true)
複製程式碼
四:事件委託(事件代理) 事件代理 如果一個節點中的子節點是動態生成的,那麼子節點需要註冊事件的話應該註冊在父節點上
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
let ul = document.querySelector('##ul')
ul.addEventListener('click', (event) => {
console.log(event.target);//li
console.log(event.currentTarget)//ul
})
</script>
複製程式碼
事件代理的方式相對於直接給目標註冊事件來說,有節省記憶體的優點 event.target和event.currentTarget的區別: event.target是點選到的最底層的那個元素 event.currentTarget是註冊事件註冊在那個元素上,那個元素就是currentTarget,所以一般是父元素
跨域
1 jsonp
什麼可以傳送請求?不光form表單可以傳送請求,a標籤(需要點選),link標籤,script,圖片,都可以傳送請求。 解決前後端耦合:前端要做的事:事先寫好成功和失敗的函式。成功了就返回給我一個成功的提示,然後我根據提示執行成功的函式,如果給我的提示是失敗,就執行失敗的函式。
,不能訪問。 真名的名字應該是:動態標籤跨域請求!即利用動態標籤script進行跨域請求的技術。
面試官:說說jsonp:
為什麼要用jsonp?
jsonp要解決的是瀏覽器的跨域資料訪問的問題。(兩個不同域名的網站)。
由於同源策略,不同域名不能發請求。但是HTML的<script>
元素是一個例外,script標籤的請求是不受域名限制的,而Ajax是受域名限制的。
如何使用jsonp?
請求方:mataotao.com的前端(瀏覽器),一個網站的前端 響應方:jack.com的後端(伺服器),另一個網站的後端 過程:
- 請求方動態建立一個
<script>
標籤。src
指向響應方,同時傳一個查詢引數?callback=xxxfn
- 因為
<script>
得到響應後會立即執行響應過來的內容。所以響應方根據查詢引數構造形如xxxfn("後臺傳過來的資料")
這樣的響應。把要傳的資料寫在callback函式的引數裡。 - 請求方瀏覽器接收到響應後, 就會執行
xxxfn('後臺傳過來的資料')
來得到後臺傳過來的資料,並處理。
這就是jsonp
jsonp為什麼不能用post請求 jsonp是通過動態建立script實現的,而script標籤傳送的是get請求。(缺點,get不安全) 優缺點: JSONP 使用簡單且相容性不錯,但是隻限於 get 請求
返回的狀態碼: 2開頭:成功 3開頭:重定向 4開頭:客戶端錯誤 5開頭:伺服器錯誤
Ajax
用 form 可以發get或post或其他請求,但是會重新整理頁面或新開頁面 用 a 可以發 get 請求,但是也會重新整理頁面或新開頁面 用 img 可以發 get 請求,但是隻能以圖片的形式展示 用 link 可以發 get 請求,但是隻能以 CSS、favicon 的形式展示 用 script 可以發 get 請求,但是隻能以指令碼的形式執行。 上面幾個都可以發請求,但是各有缺點。
說說Ajax: Ajax 是JS 可以用直接發起 任意HTTP 請求的技術。
- AJAX 通過原生的XMLHttpRequest物件發出 HTTP 請求
- 從伺服器獲取響應資料後,可以區域性更新當前網頁,而不用重新整理。 使用方法:
具體來說,AJAX 包括以下幾個步驟。
- 建立 XMLHttpRequest 例項
- 發出 HTTP 請求
- 接收伺服器傳回的資料
- 更新網頁資料
面試問題:請使用原生JS傳送Ajax請求 一般面試大概率會問這個問題,寫不對一定過不了面試
下面四句程式碼一定要記住:
myButton.addEventListener("click",(e)=>{
//這四句一定要記住
let request = new XMLHttpRequest();
request.onreadystatechange = ()=>{
request.onreadystatechange = ()=>{
if(request.readyState ===4){//Ajax狀態碼為4
console.log("請求和響應都完畢了");
if ( request.status>=200&&request.status<300){//響應成功(http狀態碼)
console.log(request.responseText);//列印響應的第四部分,字串
}else if(request.status>=400){
console.log("響應失敗");
}
}
}
}
request.open('GET','/xxx')//配置request.引數分別為方法和路徑
request.setRequestHeader('content-type','x-www-form-urlencoded')//設定響應頭一定要寫在
request.send("a=1&b=2");//傳送請求
//這四句一定要記住
})
複製程式碼
同源策略和CORS(跨域)
什麼是同源策略?
用 form
、a
、img
、link
、script
、都可以跨域傳送請求。
但是隻有 協議+域名+埠 一模一樣才允許發 AJAX 請求。
為什麼要有同源策略?
簡單地說就是例如使用form傳送請求後,就會重新整理頁面,所以原頁面沒有了,就認為是安全的.但是Ajax可以吧響應內容讀取了.並且顯示在本頁面上.所以出現安全性問題。
Ajax無法跨域報的錯誤:
CORS的英文Cross-Origin Resource Sharing,即跨域(源,站)資源共享(跨域) 那麼如何使用CORS突破同源策略解決Ajax的無法跨域傳送請求的問題?
只要伺服器端設定響應頭就可以實現跨域:
response.setHeader('Access-Control-Allow-Origin','http://mataotao.com:8001')
複製程式碼
這句話是CORS跨域(突破同源策略)的核心,即允許別的網站(例如http://mataotao.com:8001)跨域向我發Ajax請求,並且允許響應。
為什麼不使用jsonp,而是用CORS來跨域? CORS相對於JSONP,CORS可以發任意請求,而JSONP只能傳送get請求
JSON 和 JS 物件互轉
要實現從物件轉換為 JSON 字串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'}); //結果是 '{"a": "Hello", "b": "World"}'
複製程式碼
要實現從 JSON 轉換為物件,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //結果是 {a: 'Hello', b: 'World'}
複製程式碼
Cookie
Cookie 是伺服器儲存在瀏覽器的一小段文字資訊。瀏覽器每次向伺服器發出請求,就會自動附上這段資訊。 Cookie的作用過程:
- 第一次登入的時候,伺服器通過 Set-Cookie 響應頭設定 Cookie,然後以響應的形式發給瀏覽器
- 瀏覽器得到 響應中Cookie 之後,之後每次請求這個域名都要帶上這個 Cookie
- 之後伺服器讀取當時自己設定的 Cookie 就知道使用者的資訊(比如使用者名稱,是否是同一個瀏覽器等)
COokie的作用:
- 分辨兩個請求是否來自同一個瀏覽器
- 用來儲存一些狀態資訊,例如:儲存登入、購物車等需要記錄的資訊。
HTTP 回應:Cookie 的生成(伺服器端生成cookies)
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
[page content]
複製程式碼
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly
複製程式碼
HTTP 請求:Cookie 的傳送(瀏覽器傳送Cookie)
瀏覽器向伺服器傳送 HTTP 請求時,每個請求都會帶上相應的 Cookie。也就是說,把伺服器早前儲存在瀏覽器的這段資訊,再發回伺服器。這時要使用 HTTP 頭資訊的Cookie欄位。
Cookie: foo=bar
複製程式碼
上面程式碼會向伺服器傳送名為foo的 Cookie,值為bar。
Cookie欄位可以包含多個 Cookie,使用分號(;)分隔。
Cookie: name=value; name2=value2; name3=value3
複製程式碼
下面是一個Http請求的例子。
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
複製程式碼
讀、寫、刪除、Cookie
-
讀
document.cookie
,前提是該 Cookie 不能有HTTPOnly
屬性。 -
document.cookie
寫入 Cookie 的例子如下。
document.cookie = 'fontSize=14; '
+ 'expires=' + someDate.toGMTString() + '; '
+ 'path=/subdirectory; '
+ 'domain=*.example.com';
複製程式碼
- Cookie 的刪除
刪除一個現存 Cookie 的唯一方法,是設定它的
expires
屬性為一個過去的日期。
session
什麼是session?
- 伺服器通過Cookie傳送給客戶端一個sessionID
- sessionID對應伺服器裡的一小塊記憶體,這裡儲存著使用者的資訊,例如登入資訊,購物車資訊等。
- 每次使用者訪問伺服器的時候,伺服器通過瀏覽器傳送來的cookie裡的sessionID去讀取對應的記憶體裡的資訊,以此來知道使用者的隱私資訊。
Storage
window.sessionStorage
和window.localStorage
介面用於指令碼在瀏覽器儲存資料。
基本使用
設定
window.sessionStorage.setItem('key', 'value');
window.localStorage.setItem('key', 'value');
複製程式碼
獲取
window.sessionStorage.getItem('key')
window.localStorage.getItem('key')
複製程式碼
清除
localStorage.removeItem('key');
window.localStorage.clear()
複製程式碼
總結
注意只能存字串型別的。
- LocalStorage 跟 HTTP 無關(而cookie是http的一個頭)
- 傳送HTTP請求時 不會帶上 LocalStorage 的值
- 只有相同域名的頁面才能互相讀取 LocalStorage(沒有同源那麼嚴格)
- 每個域名 localStorage 最大儲存量為 5Mb 左右(每個瀏覽器不一樣)
- 常用場景:記錄有沒有提示過使用者(沒有用的資訊,不能記錄密碼)
- LocalStorage 永久有效,除非使用者主動清理快取
區別:SessionStorage 在使用者關閉頁面(會話結束)後就失效。其餘的和localstorage一樣
Cookie和Storage對比:
HTTP快取
HTTP快取有利於web效能優化。HTTP快取可以重複利用之前獲取的資源而不用反覆請求,以達到效能優化的目的。 方法
1 Cache-Control
在響應裡設定響應頭
Cache-Control: max-age=30
意思就是30秒之內,瀏覽器再訪問相同的URL的時候,就不發請求,直接從記憶體裡拿到已經快取的main.js。
問題:那麼js和css更新了怎麼辦?
瀏覽器請求時發現是相同的URL才使用快取,那麼可以設定查詢引數,例如第二個版本的js可以寫<script src="./main.js?v=2"></script>
,來保證URL的不同,重新獲取新的js檔案。這樣即可以快取很久,又可以隨時更新.(總結:設定查詢引數,保證URL的不同)
Expires
-
Expires 是以前用來控制快取的http頭,Cache-Control是新版的API。
-
現在首選 Cache-Control。
-
如果在Cache-Control響應頭設定了 "max-age" 或者 "s-max-age" 指令,那麼 Expires 頭會被忽略。
-
響應頭設定方式:
Expires: Wed, 21 Oct 2015 07:28:00 GMT
-
Expires 響應頭包含日期/時間, 即在此時候之後,響應過期。 注意: 因為過期標準的時間用的是本地時間,所以不靠譜,所以要遊俠使用Cache-Control代替Expires
答面試官: 與Cache-Control的區別就是:
- Cache-Control設定過期時間長度
- Expires 設定過期時間點
MD5是訊息摘要演算法。用於確保資訊傳輸完整一致。可以判斷兩次資訊傳輸是否完整一致。
ETag
例如
- 我們請求一個js檔案。設定的ETage響應頭為這個JS檔案的MD5值
- 那麼,下一次請求這個JS的時候,瀏覽器會把上一次響應的那個ETage的值放到If-None-Match請求頭裡面傳送請求。
- 如果MD5一樣,說明檔案沒改過,那麼返回304
304 Not Modified: HTTP 304 未改變說明無需再次傳輸請求的內容,也就是說可以使用快取的內容。
HTTP 304 :沒有響應體
ETag與 Cache-Control的區別
- 由於CSS的請求是用快取(Cache-Control)的,所以直接不發請求
- 而js用的ETag,有請求也有響應,只不過如果MD5一樣,那麼就不下載響應體。
MVC
MVC是一種程式碼組織形式,只是組織程式碼的思想.給面試官將MVC
MVC處理的邏輯順序。MVC就是把程式碼分為三塊
- V(view)只負責看得見的東西.
- M(model)只負責跟資料相關的操作,不會出現DOM,不會出現任何的html/css操作.例如model裡只會有初始化資料庫,獲取資料方法fetch(),儲存資料的方法save()
- C(controller)只負責把這些view和model組合起來,找到view,找到model,使用model完成資料修改業務,並修改view的顯示 V:檢視
M,V,C在程式碼中可以用物件或者類來表示
webpack
曾使用 webpack3 用 babel-loader 把 ES6 轉譯為 ES5 用 sass-loader 把 SCSS 轉譯為 CSS 作用:
- 自從出現模組化以後,檔案變多。每個 JS 檔案都要傳送請求響應,會導致載入速度變慢。Webpack 最主要的目的就是為了解決這個問題,將所有小檔案打包成一個或多個大檔案。
- 可以使用各種前端新技術的工具,babel,sass。
面試題彙總
前端面試題(移動適配,閉包,this,HTTP狀態嗎,排序思路,頁面載入,陣列去重)
1 請寫出一個符合 W3C 規範的 HTML 檔案
請寫出一個符合 W3C 規範的 HTML 檔案,要求
- 頁面標題為「我的頁面」
- 頁面中引入了一個外部 CSS 檔案,檔案路徑為 /style.css
- 頁面中引入了另一個外部 CSS 檔案,路徑為 /print.css,該檔案僅在列印時生效
- 頁面中引入了另一個外部 CSS 檔案,路徑為 /mobile.css,該檔案僅在裝置寬度小於 500 畫素時生效
- 頁面中引入了一個外部 JS 檔案,路徑為 /main.js
- 頁面中引入了一個外部 JS 檔案,路徑為 /gbk.js,檔案編碼為 GBK
- 頁面中有一個 SVG 標籤,SVG 裡面有一個直徑為 100 畫素的圓圈,顏色隨意
- 注意題目中的路徑
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>我的頁面</title>
<link rel="stylesheet" href="./style.css">
<link rel="stylesheet" href="./print.css" media="print">
<link rel="stylesheet" href="./mobile.css" media="(max-width: 500px)">
<style>
body{
padding:0;
margin:0;
}
</style>
</head>
<body>
<svg version="1.1" width="100px" height="100px" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="50" fill="red"/>
</svg>
<script src="./main.js"></script>
<script src="./gbk.js" charset="GBK"></script>
</body>
</html>
複製程式碼
2 移動端是怎麼做適配的?
2016年騰訊前端面試題: 移動端是怎麼做適配的? 回答要點:
- meta viewport
- 媒體查詢
- 動態 rem 方案
(可以參考我寫的部落格 CSS5:移動端頁面(響應式) CSS9:動態 REM-手機專用的自適應方案) 答:
2.1做手機端頁面首先要加上一個meta標籤
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
複製程式碼
content="width=device-width
表示寬度等於裝置寬度,意思就是不要將頁面寬度變成980px,用裝置寬度.
user-scalable=no
表示使用者不以縮放
initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0
初始縮放倍數,最大縮放倍數,最小縮放倍數,都是1.0,即不能縮放
2.2媒體查詢
通過媒體查詢,根據不同條件,使用不同的css樣式。 例如:
<style>
@media (max-width: 800px){/*如果媒體滿足0到800 之間,那麼會應用這裡面的樣式*/
body{
background-color: red;
}
}
</style>
複製程式碼
2.3動態rem
因為手機需要相容很多不同寬度的手機裝置,所以將長度單位依賴於手機裝置寬度,使用動態rem方案,那麼就可以在不同手機上實現相同比例的頁面縮放而不影響佈局。
rem:root em,即<html>
的font-size
.
實現動態rem,主要需要下面兩步:
1在<head>
標籤里加上如下程式碼,讓10rem等於頁面寬度
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>動態REM</title>
<script></script>
</head>
複製程式碼
2使用sass自動將設計稿的px轉換為rem 在scss檔案裡寫這樣一個函式:
@function px( $px ){
@return $px/$designWidth*10 + rem;
}
$designWidth : 640; // 640 是設計稿的寬度,你要根據設計稿的寬度填寫。設計師的設計稿寬度需要統一
複製程式碼
就可以使用px()函式將畫素轉化為rem。
3 實現圓角矩形和陰影怎麼做?
2017年騰訊前端實習面試題(二面):
用過CSS3嗎? 實現圓角矩形和陰影怎麼做?
(搜尋MDN border-radius)
答:
用過。例如陰影,圓角,動畫,漸變和過渡
1.圓角:
簡寫屬性border-radius
。例如
border-radius: 30px;
border-radius: 50%;
半徑引數可以是長度單位,也可以是百分比單位。
也可以分別設定四個角
border-top-left-radius: 4px 2px;
border-top-right-radius: 3px 4px;
border-bottom-right-radius: 6px 2px;
border-bottom-left-radius: 3px 4px;
複製程式碼
半徑引數可以是一個或兩個,一個引數代表圓形圓角,兩個引數是橢圓圓角
2.陰影:
語法:
box-shadow:inset x-offset y-offset blur-radius spread-radius color
五個引數分別是:投影方式 X軸偏移量 Y軸偏移量 陰影模糊半徑 陰影擴充套件半徑 陰影顏色
4 什麼是閉包,閉包的用途是什麼?
出處同上(一面二面都問了): 什麼是閉包,閉包的用途是什麼? JavaScript高程P178 閉包的用途
答:
4.1什麼是閉包
閉包是指有權訪問另一個函式作用域中的變數的函式。 例如
function foo(){
var local = 1
function bar(){
local++
return local
}
return bar
}
var func = foo()
func()
複製程式碼
bar函式可以訪問變數local,bar就是一個閉包。
4.2閉包的用途
- 模仿塊級作用域
function A(num) { //核心程式碼 (funnction(){ for(var i = 0; i<num; i++) { num++; } })() //核心程式碼結束 console.log(i)//underfined } 複製程式碼
匿名自執行函式在內部形成了一個閉包,使i變數只有塊級作用域。閉包的本質是函式,其實在這裡閉包就是那個匿名函式,這個閉包可以得到函式A內部的活動變數,又能保證自己內部的變數在自執行後直接銷燬。
- 儲存變數 閉包的另一個特點是可以儲存外部函式的變數,原理是基於javascript中函式作用域鏈的特點,內部函式保留了對外部函式的活動變數的引用,所以變數不會被釋放
function B(){
var x = 100;
return {
function(){
return x
}
}
}
var m = B()//執行B函式,生成活動變數 x被m引用
複製程式碼
執行B函式,生成活動變數 x被m引用, 變數x不會被銷燬。 執行B函式,返回值就是B內部的匿名函式,此時m引用了變數x,所以B執行後x不會被釋放,利用這一點,我們可以把比較重要或者計算耗費很大的值存在x中,只需要第一次計算賦值後,就可以通過m函式引用x的值,不必重複計算,同時也不容易被修改。 3. 封裝私有變數
function Person(){
var name = 'default';
this.getName:function(){
return name;
}
this.setName:function(value){
name = value;
}
}
console.log(Person.getName())//default
console.log(Person.setName('mike'))
console.log(Person.getName())//mike
複製程式碼
設定了兩個閉包函式來操作Person函式內部的name變數,除了這兩個函式,在外部無法再訪問到name變數,name也就相當於是私有成員。
5 call、apply、bind 的用法分別是什麼?
阮一峰的javascript教程--this 深入淺出 妙用Javascript中apply、call、bind
答:
如果在函式中包含多層的this,this的指向是不確定的。需要把this固定下來,避免出現意想不到的情況。JavaScript提供了call、apply、bind這三個方法,來切換/固定this的指向。
5.1Function.prototype.call()
函式例項的call方法,可以指定函式內部this的指向(即函式執行時所在的作用域),然後在所指定的作用域中,呼叫該函式。
var obj = {};
var f = function () {
return this;
};
f() === window // true
f.call(obj) === obj // true
複製程式碼
call的第一個引數就是this所要指向的那個物件,後面的引數則是函式呼叫時所需的引數。
5.2Function.prototype.apply()
apply方法的作用與call方法類似,也是改變this指向,然後再呼叫該函式。唯一的區別就是,它接收一個陣列作為函式執行時的引數。
apply方法的第一個引數也是this所要指向的那個物件,如果設為null或undefined,則等同於指定全域性物件。第二個引數則是一個陣列,該陣列的所有成員依次作為引數,傳入原函式。原函式的引數,在call方法中必須一個個新增,但是在apply方法中,必須以陣列形式新增。
function f(x, y){
console.log(x + y);
}
f.call(null, 1, 1) // 2
f.apply(null, [1, 1]) // 2
複製程式碼
5.3Function.prototype.bind()
bind方法用於將函式體內的this繫結到某個物件,然後返回一個新函式。
bind方法的引數就是所要繫結this的物件。
var counter = {
count: 0,
inc: function () {
this.count++;
}
};
var func = counter.inc.bind(counter);
func();
counter.count // 1
複製程式碼
上面程式碼中,counter.inc方法被賦值給變數func。這時必須用bind方法將inc內部的this,繫結到counter,否則就會出錯。
6 HTTP 狀態碼
出處同上: 請說出至少 8 個 HTTP 狀態碼,並描述各狀態碼的意義。
例如:
狀態碼 200 表示響應成功。
答:
狀態碼 202 表示:伺服器已接受請求,但尚未處理。 狀態碼 204 表示:請求處理成功,但沒有資源可返回。 狀態碼 206 表示:伺服器已經成功處理了部分 GET 請求。
狀態碼 301 表示:請求的資源已被永久的分配了新的 URI。 狀態碼 302 表示:請求的資源臨時的分配了新的 URI。
狀態碼 400 表示:請求報文中存在語法錯誤。 狀態碼 401 表示:傳送的請求需要有通過 HTTP 認證的認證資訊。 狀態碼 403 表示:對請求資源的訪問被伺服器拒絕了。 狀態碼 404 表示:伺服器上無法找到請求的資源。
狀態碼 500 表示:伺服器端在執行請求時發生了錯誤。 狀態碼 503 表示:伺服器暫時處於超負債或正在進行停機維護,現在無法處理請求。
7 寫出一個 HTTP post 請求的內容
出處同上: 請寫出一個 HTTP post 請求的內容,包括四部分。 其中 第四部分的內容是 username=ff&password=123 第二部分必須含有 Content-Type 欄位 請求的路徑為 /path
看我的部落格HTTP入門(一):在Bash中curl檢視請求與響應
答: 請求:
1 POST /path HTTP/1.1
2 Host: www.baidu.com
2 User-Agent: curl/7.20.0 (x86_64-unknown-linux-gnu) libcurl/7.20.0 zlib/1.2.8
2 Accept: */*
2 Content-Length: 24
2 Content-Type: application/x-www-form-urlencoded
3
4 username=ff&password=123
複製程式碼
響應:
1 HTTP/1.1 200 OK
2Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
2Content-Length: 2443
2Content-Type: text/html(百度返回的時候百度的資料長度和內容的格式)
2Etag: "5886041d-98b"
2Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
3
4<!DOCTYPE html> ...
複製程式碼
1234567890
8 請說出至少三種排序的思路
這三種排序的時間複雜度分別為
O(n*n) O(n log2 n) O(n + max)
答:
O(n*n) 氣泡排序:遍歷整個陣列,依次比較相鄰兩個元素,將小的排在前面,大的排後面,這樣一遍迴圈下來就可以將最大的元素排到最後,除去已經排過的最大的數,然後再次迴圈以上操作,直到最後一個為止。
O(n log2 n) 快速排序:以第一個元素為基準,比這個元素小的元素排在左邊,比這個元素大的排右邊,再以該元素左邊和右邊的第一個元素為基準,在子區間重複以上的操作,直到只有一個數字排序為止。
O(n + max) 基數排序:首先根據個位數的數值,將需要排序的一串數值分配到0-9的桶中。接著將這些桶中的數值重新串起來,形成新的數列。接著根據十位數、百位數直至最高位重複以上操作。
9 頁面從輸入URL到頁面載入顯示完成的過程
著名前端面試題:
一個頁面從輸入 URL 到頁面載入顯示完成,這個過程中都發生了什麼? 這一題是在挖掘你的知識邊界,所以你知道多少就要答多少。
可以先查閱一些資料再查,但是不要把自己不懂的東西放在答案裡,面試官會追問的。
知乎上:從輸入 URL 到頁面載入完成的過程中都發生了什麼 答:
- DNS解析 DNS解析的過程就是瀏覽器查詢域名對應的 IP 地址;
- TCP連線 瀏覽器根據 IP 地址向伺服器發起 TCP 連線,與瀏覽器建立 TCP 三次握手: (1)主機向伺服器傳送一個建立連線的請求(您好,我想認識您); (2)伺服器接到請求後傳送同意連線的訊號(好的,很高興認識您); (3)主機接到同意連線的訊號後,再次向伺服器傳送了確認訊號(我也很高興認識您),自此,主機與伺服器兩者建立了連線。
- 傳送HTTP請求 瀏覽器根據 URL 內容生成 HTTP 請求報文。HTTP請求報文是由三部分組成: 請求行, 請求報頭和請求正文,其中包含請求檔案的位置、請求檔案的方式等等。
- 伺服器處理請求並返回HTTP報文
伺服器接到請求後,回想客戶端傳送HTTP響應報文。HTTP響應報文也是由三部分組成: 狀態碼, 響應報頭和響應報文。伺服器會根據 HTTP 請求中的內容來決定如何獲取相應的 HTML 檔案,並將得到的 HTML 檔案傳送給瀏覽器。
-
瀏覽器解析渲染頁面 瀏覽器是一個邊解析邊渲染的過程。在瀏覽器還沒有完全接收 HTML 檔案時便開始渲染、顯示網頁。在執行 HTML 中程式碼時,根據需要,瀏覽器會繼續請求圖片、CSS、JavsScript等檔案,過程同請求 HTML 。
-
關閉TCP連線或繼續保持連線
(1)主機向伺服器傳送一個斷開連線的請求(不早了,我該走了);
(2)伺服器接到請求後傳送確認收到請求的訊號(知道了);
(3)伺服器向主機傳送斷開通知(我也該走了);
(4)主機接到斷開通知後斷開連線並反饋一個確認訊號(嗯,好的),伺服器收到確認訊號後斷開連線;
10 如何實現陣列去重
著名面試題: 如何實現陣列去重? 假設有陣列 array = [1,5,2,3,4,2,3,1,3,4] 你要寫一個函式 unique,使得 unique(array) 的值為 [1,5,2,3,4] 也就是把重複的值都去掉,只保留不重複的值。
要求:
不要做多重迴圈,只能遍歷一次 請給出兩種方案,一種能在 ES 5 環境中執行,一種能在 ES 6 環境中執行(提示 ES 6 環境多了一個 Set 物件) 從 JavaScript 陣列去重談效能優化 也談JavaScript陣列去重 答:
ES5: 思路:核心是構建了一個 hash 物件來替代 indexOf. 注意在 JavaScript 裡,物件的鍵值只能是字串,因此需要 var key = typeof(item) + item 來區分數值 1 和字串 '1' 等情況。 只迴圈一遍
function unique(arr) {
var ret = []
var hash = {}
for (var i = 0; i < arr.length; i++) {
var item = arr[i]
var key = typeof(item) + item
if (hash[key] !== 1) {
ret.push(item)
hash[key] = 1
}
}
return ret
}
複製程式碼
ES6:ES2015引入了一種叫作Set的資料型別。顧名思義,Set就是集合的意思,它不允許重複元素出現。 如果重複新增同一個元素的話,Set中只會存在一個。包括NaN也是這樣
function unique(array) {
return Array.from(new Set(array));
}
複製程式碼
JS題目總結:原型鏈/new/json/MVC/Promise
1原型鏈相關
解讀: 上圖中,Object,Function,Array,Boolean都是構造函式第一個框:
object是例項物件,他的模板物件(原型物件)在Object()建構函式裡面.
建構函式.prototype
指向的是原型物件,即模板物件.
由建構函式構造出來的例項物件.__proto__
也指向的是原型物件,即模板物件.
所以true.
第二個框:
fn是一個例項函式,是由用來構造出函式的建構函式造出來的.
所以fn.__proto__ === Function.prototype
任何建構函式.prototype
都是一個物件.
因為fn.__proto__ === Function.prototype
所以fn.__proto__.__proto__ === Object.prototype
等價於
Function.prototype.__proto__ === Object.prototype
等價於
一個物件.__proto__ === Object.prototype
所以是true
第三個框同理.
第四個框比較難理解: 一個例項函式是由用來構造出函式的建構函式造出來的.
Object,Function,Array都是一個例項函式,函式也是一種型別,就像String是一種型別,Number是一種型別一樣,函式這個型別裡的例項函式由函式的建構函式造出來!很難理解
所以例項函式.__proto__===建構函式.prototype
例項函式的建構函式就是Function
有點雞生蛋蛋生雞的感覺.
第五個框同理
2物件導向,new,原型鏈相關
function fn(){
console.log(this)
}
new fn()
複製程式碼
new fn()
會執行 fn
,並列印出 this
,請問這個 this
有哪些屬性?這個 this
的原型有哪些屬性?
答:
這個this
就是new
建立的新物件.
this
(這個新物件)有__protot__
屬性,它指向fn
建構函式的原型即fn.prototype
這個原型(即fn.prototype
)有兩個屬性:
construct
:它的值是建構函式fn
__proto__
: 它指向Object.prototype
解讀:
fn()
是建構函式new fn()
就是一個建構函式new
出來的新物件. 他的自有屬性為空,共有屬性為空,因為都沒有設定 因為他的自有屬性為空,所以他只有一個__proto__
指向建構函式.prototype
(即原型)了. 共有屬性為空,所以他的原型就是隻有constructor
指向建構函式和__proto__
指向Object.prototype
(因為原型本身就是物件型別,所以指向物件的建構函式) 例子:
3 json
JSON 和 JavaScript 是什麼關係? JSON 和 JavaScript 的區別有哪些?
關係:JSON 是一門抄襲/借鑑 JavaScript 的語言,同時也是一種資料互動格式,JSON 是 JavaScript 的子集(或者說 JSON 只抄襲了一部分 JavaScript 語法,而且沒有新增任何原創的語法)
區別:JSON 不支援函式、undefined、變數、引用、單引號字串、物件的key不支援單引號也不支援不加引號、沒有內建的 Date、Math、RegExp 等。 而 JavaScript 全都支援。
4 MVC
前端 MVC 是什麼?(10分) 請用程式碼大概說明 MVC 三個物件分別有哪些重要屬性和方法。(10分)
答一:
MVC 是什麼 MVC 是一種設計模式(或者軟體架構),把系統分為三層:Model資料、View檢視和Controller控制器。 Model 資料管理,包括資料邏輯、資料請求、資料儲存等功能。前端 Model 主要負責 AJAX 請求或者 LocalStorage 儲存 View 負責使用者介面,前端 View 主要負責 HTML 渲染。 Controller 負責處理 View 的事件,並更新 Model;也負責監聽 Model 的變化,並更新 View,Controller 控制其他的所有流程。
答二: MVC就是把程式碼分為三塊
V(view)只負責看得見的東西. M(model)只負責跟資料相關的操作,不會出現DOM,不會出現任何的html/css操作.例如model裡只會有初始化資料庫,獲取資料方法fetch(),儲存資料的方法save() C(controller)只負責把這些view和model組合起來,找到view,找到model,使用model完成資料修改業務,並修改view的顯示 V:檢視 M:資料 C:控制器
MVC是一種程式碼組織形式,不是任何一種框架,也不是任何一種技術,只是組織程式碼的思想,要做的就是V和M傳給C,C去統籌 在js裡,MVC分別由三個物件去擔任三個職責
程式碼一:
window.View = function(xxx){
return document.querySelector(xxx);
}
複製程式碼
window.Model = function(object){
let resourceName = object.resourceName;
return {
init: function () {
},
fetch: function () {
},
save: function (object) {
}
}
}
複製程式碼
window.Controller = function(options){
var init = options.init;
let object = {
view:null,
model:null,
init:function(view,model){
this.view = view;
this.model = model;
this.model.init();
init.call(this,view,model);
this.bindEvents();
},
bindevnets:function(){},
};
for (let key in options) {
if(key !=='init'){
object[key] = options[key]
}
};
return object;
}
複製程式碼
程式碼二:
var model = {
data: null,
init(){}
fetch(){}
save(){}
update(){}
delete(){}
}
view = {
init() {}
template: '<h1>hi</h1'>
}
controller = {
view: null,
model: null,
init(view, model){
this.view = view
this.model = model
this.bindEvents()
}
render(){
this.view.querySelector('name').innerText = this.model.data.name
},
bindEvents(){}
}
複製程式碼
5 ES5類,原型鏈,建構函式,new
如何在 ES5 中如何用函式模擬一個類?(10分)
答一:
使用原型物件,建構函式,new來模擬類.
- 將公共屬性放到原型物件裡,並且將建構函式的
prototype
屬性指向原型物件. - 私有屬性(自有屬性)放到建構函式裡去定義.
- 將例項化的物件的
__proto__
指向原型物件. 這樣當建構函式建立一個例項化的物件的時候,就即擁有自己的私有變數和方法,也有公有的變數和方法了,例項化出來的物件的私有方法和變數修改都不會互相有影響,只有在修改公有的變數和方法的時候是對所有例項生效的
答二: ES 5 沒有 class 關鍵字,所以只能使用函式來模擬類。
function Human(name){
this.name = name
}
Human.prototype.run = function(){}
var person = new Human('frank')
複製程式碼
上面程式碼就是一個最簡單的類,Human
建構函式建立出來的物件自身有 name
屬性,其原型上面有一個 run
屬性。
Promise
用過 Promise 嗎?舉例說明。 如果要你建立一個返回 Promise 物件的函式,你會怎麼寫?舉例說明。
答:
用過Promise
答一: 用過 Promise,比如 jQuery 或者 axios 的 AJAX 功能,都返回的是 Promise 物件。
$.ajax({url:'/xxx', method:'get'}).then(success1, error1).then(success2, error2)
答二: 用過.例如使用jQuery的Ajax()傳送請求,成功或失敗後的回撥函式,就是使用promise封裝的
function success(responseText){
console.log("成功")
console.log(responseText);//responseTex
}
function fail(request){
console.log("失敗")
console.log(request);
}
myButton.addEventListener("click",(e)=>{
//使用ajax
$.ajax({
method:"post",
url:"/xxx",
data:"username=mtt&password=1",
dataType:'json'//預期伺服器返回的資料型別,如果不寫,就是響應裡設定的
}
).then(success,fail)//$.ajax()返回一個promise
})
複製程式碼
寫Promise
function xxx(){
return new Promise((f1, f2) => {
doSomething()
setTimeout(()=>{
if(success){
f1();
}else{
f2();
}
},3000)
})
}
呼叫方法:
xxx().then(success, fail)
複製程式碼
或者:
function asyncMethod(){
return new Promise(function (resolve, reject){
setTimeout(function(){
成功則呼叫 resolve
失敗則呼叫 reject
},3000)
})
}
複製程式碼