第一部分:基礎篇
#一、HTML、HTTP、web綜合問題
#1 前端需要注意哪些SEO
- 合理的
title
、description
、keywords
:搜索對着三項的權重逐個減小,title
值強調重點即可,重要關鍵詞出現不要超過2次,而且要靠前,不同頁面title
要有所不同;description
把頁面內容高度概括,長度合適,不可過分堆砌關鍵詞,不同頁面description
有所不同;keywords
列舉出重要關鍵詞即可 - 語義化的
HTML
代碼,符合W3C規範:語義化代碼讓搜索引擎容易理解網頁 - 重要內容
HTML
代碼放在最前:搜索引擎抓取HTML
順序是從上到下,有的搜索引擎對抓取長度有限制,保證重要內容一定會被抓取 - 重要內容不要用
js
輸出:爬蟲不會執行js獲取內容 - 少用
iframe
:搜索引擎不會抓取iframe
中的內容 - 非裝飾性圖片必須加
alt
- 提高網站速度:網站速度是搜索引擎排序的一個重要指標
#2 <img>
的title
和alt
有什麼區別
- 通常當鼠標滑動到元素上的時候顯示
alt
是<img>
的特有屬性,是圖片內容的等價描述,用於圖片無法加載時顯示、讀屏器閱讀圖片。可提圖片高可訪問性,除了純裝飾圖片外都必須設置有意義的值,搜索引擎會重點分析。
#3 HTTP的幾種請求方法用途
-
GET
方法- 發送一個請求來取得服務器上的某一資源
-
POST
方法- 向
URL
指定的資源提交數據或附加新的數據
- 向
-
PUT
方法- 跟
POST
方法很像,也是想服務器提交數據。但是,它們之間有不同。PUT
指定了資源在服務器上的位置,而POST
沒有
- 跟
-
HEAD
方法- 只請求頁面的首部
-
DELETE
方法- 刪除服務器上的某資源
-
OPTIONS
方法- 它用於獲取當前
URL
所支持的方法。如果請求成功,會有一個Allow
的頭包含類似“GET,POST”
這樣的信息
- 它用於獲取當前
-
TRACE
方法TRACE
方法被用於激發一個遠程的,應用層的請求消息迴路
-
CONNECT
方法- 把請求連接轉換到透明的
TCP/IP
通道
- 把請求連接轉換到透明的
#4 從瀏覽器地址欄輸入url到顯示頁面的步驟
基礎版本
- 瀏覽器根據請求的
URL
交給DNS
域名解析,找到真實IP
,向服務器發起請求; - 服務器交給後臺處理完成後返回數據,瀏覽器接收文件(
HTML、JS、CSS
、圖象等); - 瀏覽器對加載到的資源(
HTML、JS、CSS
等)進行語法解析,建立相應的內部數據結構(如HTML
的DOM
); - 載入解析到的資源文件,渲染頁面,完成。
詳細版
- 在瀏覽器地址欄輸入URL
- 瀏覽器查看緩存,如果請求資源在緩存中並且新鮮,跳轉到轉碼步驟
- 如果資源未緩存,發起新請求
- 如果已緩存,檢驗是否足夠新鮮,足夠新鮮直接提供給客戶端,否則與服務器進行驗證。
- 檢驗新鮮通常有兩個HTTP頭進行控制
Expires
和Cache-Control
:- HTTP1.0提供Expires,值爲一個絕對時間表示緩存新鮮日期
- HTTP1.1增加了Cache-Control: max-age=,值爲以秒爲單位的最大新鮮時間
- 瀏覽器解析URL獲取協議,主機,端口,path
- 瀏覽器組裝一個HTTP(GET)請求報文
- 瀏覽器獲取主機ip地址,過程如下:
- 瀏覽器緩存
- 本機緩存
- hosts文件
- 路由器緩存
- ISP DNS緩存
- DNS遞歸查詢(可能存在負載均衡導致每次IP不一樣)
- 打開一個socket與目標IP地址,端口建立TCP鏈接,三次握手如下:
- 客戶端發送一個TCP的SYN=1,Seq=X的包到服務器端口
- 服務器發回SYN=1, ACK=X+1, Seq=Y的響應包
- 客戶端發送ACK=Y+1, Seq=Z
- TCP鏈接建立後發送HTTP請求
- 服務器接受請求並解析,將請求轉發到服務程序,如虛擬主機使用HTTP Host頭部判斷請求的服務程序
- 服務器檢查HTTP請求頭是否包含緩存驗證信息如果驗證緩存新鮮,返回304等對應狀態碼
- 處理程序讀取完整請求並準備HTTP響應,可能需要查詢數據庫等操作
- 服務器將響應報文通過TCP連接發送回瀏覽器
- 瀏覽器接收HTTP響應,然後根據情況選擇關閉TCP連接或者保留重用,關閉TCP連接的四次握手如下:
- 主動方發送Fin=1, Ack=Z, Seq= X報文
- 被動方發送ACK=X+1, Seq=Z報文
- 被動方發送Fin=1, ACK=X, Seq=Y報文
- 主動方發送ACK=Y, Seq=X報文
- 瀏覽器檢查響應狀態嗎:是否爲1XX,3XX, 4XX, 5XX,這些情況處理與2XX不同
- 如果資源可緩存,進行緩存
- 對響應進行解碼(例如gzip壓縮)
- 根據資源類型決定如何處理(假設資源爲HTML文檔)
- 解析HTML文檔,構件DOM樹,下載資源,構造CSSOM樹,執行js腳本,這些操作沒有嚴格的先後順序,以下分別解釋
- 構建DOM樹:
- Tokenizing:根據HTML規範將字符流解析爲標記
- Lexing:詞法分析將標記轉換爲對象並定義屬性和規則
- DOM construction:根據HTML標記關係將對象組成DOM樹
- 解析過程中遇到圖片、樣式表、js文件,啓動下載
- 構建CSSOM樹:
- Tokenizing:字符流轉換爲標記流
- Node:根據標記創建節點
- CSSOM:節點創建CSSOM樹
- 根據DOM樹和CSSOM樹構建渲染樹:
- 從DOM樹的根節點遍歷所有可見節點,不可見節點包括:1)
script
,meta
這樣本身不可見的標籤。2)被css隱藏的節點,如display: none
- 對每一個可見節點,找到恰當的CSSOM規則並應用
- 發佈可視節點的內容和計算樣式
- 從DOM樹的根節點遍歷所有可見節點,不可見節點包括:1)
- js解析如下:
- 瀏覽器創建Document對象並解析HTML,將解析到的元素和文本節點添加到文檔中,此時document.readystate爲loading
- HTML解析器遇到沒有async和defer的script時,將他們添加到文檔中,然後執行行內或外部腳本。這些腳本會同步執行,並且在腳本下載和執行時解析器會暫停。這樣就可以用document.write()把文本插入到輸入流中。同步腳本經常簡單定義函數和註冊事件處理程序,他們可以遍歷和操作script和他們之前的文檔內容
- 當解析器遇到設置了async屬性的script時,開始下載腳本並繼續解析文檔。腳本會在它下載完成後儘快執行,但是解析器不會停下來等它下載。異步腳本禁止使用document.write(),它們可以訪問自己script和之前的文檔元素
- 當文檔完成解析,document.readState變成interactive
- 所有defer腳本會按照在文檔出現的順序執行,延遲腳本能訪問完整文檔樹,禁止使用document.write()
- 瀏覽器在Document對象上觸發DOMContentLoaded事件
- 此時文檔完全解析完成,瀏覽器可能還在等待如圖片等內容加載,等這些內容完成載入並且所有異步腳本完成載入和執行,document.readState變爲complete,window觸發load事件
- 顯示頁面(HTML解析過程中會逐步顯示頁面)
詳細簡版
-
從瀏覽器接收
url
到開啓網絡請求線程(這一部分可以展開瀏覽器的機制以及進程與線程之間的關係) -
開啓網絡線程到發出一個完整的
HTTP
請求(這一部分涉及到dns查詢,TCP/IP
請求,五層因特網協議棧等知識) -
從服務器接收到請求到對應後臺接收到請求(這一部分可能涉及到負載均衡,安全攔截以及後臺內部的處理等等)
-
後臺和前臺的
HTTP
交互(這一部分包括HTTP
頭部、響應碼、報文結構、cookie
等知識,可以提下靜態資源的cookie
優化,以及編碼解碼,如gzip
壓縮等) -
單獨拎出來的緩存問題,
HTTP
的緩存(這部分包括http緩存頭部,ETag
,catch-control
等) -
瀏覽器接收到
HTTP
數據包後的解析流程(解析html
-詞法分析然後解析成dom
樹、解析css
生成css
規則樹、合併成render
樹,然後layout
、painting
渲染、複合圖層的合成、GPU
繪製、外鏈資源的處理、loaded
和DOMContentLoaded
等) -
CSS
的可視化格式模型(元素的渲染規則,如包含塊,控制框,BFC
,IFC
等概念) -
JS
引擎解析過程(JS
的解釋階段,預處理階段,執行階段生成執行上下文,VO
,作用域鏈、回收機制等等) -
其它(可以拓展不同的知識模塊,如跨域,web安全,
hybrid
模式等等內容)
#5 如何進行網站性能優化
-
content
方面- 減少
HTTP
請求:合併文件、CSS
精靈、inline Image
- 減少
DNS
查詢:DNS
緩存、將資源分佈到恰當數量的主機名 - 減少
DOM
元素數量
- 減少
-
Server
方面- 使用
CDN
- 配置
ETag
- 對組件使用
Gzip
壓縮
- 使用
-
Cookie
方面- 減小
cookie
大小
- 減小
-
css
方面- 將樣式表放到頁面頂部
- 不使用
CSS
表達式 - 使用
<link>
不使用@import
-
Javascript
方面- 將腳本放到頁面底部
- 將
javascript
和css
從外部引入 - 壓縮
javascript
和css
- 刪除不需要的腳本
- 減少
DOM
訪問
-
圖片方面
- 優化圖片:根據實際顏色需要選擇色深、壓縮
- 優化
css
精靈 - 不要在
HTML
中拉伸圖片
#6 HTTP狀態碼及其含義
1XX
:信息狀態碼100 Continue
繼續,一般在發送post
請求時,已發送了http header
之後服務端將返回此信息,表示確認,之後發送具體參數信息
2XX
:成功狀態碼200 OK
正常返回信息201 Created
請求成功並且服務器創建了新的資源202 Accepted
服務器已接受請求,但尚未處理
3XX
:重定向301 Moved Permanently
請求的網頁已永久移動到新位置。302 Found
臨時性重定向。303 See Other
臨時性重定向,且總是使用GET
請求新的URI
。304 Not Modified
自從上次請求後,請求的網頁未修改過。
4XX
:客戶端錯誤400 Bad Request
服務器無法理解請求的格式,客戶端不應當嘗試再次使用相同的內容發起請求。401 Unauthorized
請求未授權。403 Forbidden
禁止訪問。404 Not Found
找不到如何與URI
相匹配的資源。
5XX:
服務器錯誤500 Internal Server Error
最常見的服務器端錯誤。503 Service Unavailable
服務器端暫時無法處理請求(可能是過載或維護)。
#7 語義化的理解
- 用正確的標籤做正確的事情!
HTML
語義化就是讓頁面的內容結構化,便於對瀏覽器、搜索引擎解析;- 在沒有樣式
CSS
情況下也以一種文檔格式顯示,並且是容易閱讀的。 - 搜索引擎的爬蟲依賴於標記來確定上下文和各個關鍵字的權重,利於
SEO
。 - 使閱讀源代碼的人對網站更容易將網站分塊,便於閱讀維護理解
#8 介紹一下你對瀏覽器內核的理解?
-
主要分成兩部分:渲染引擎(
layout engineer
或Rendering Engine
)和JS
引擎 -
渲染引擎:負責取得網頁的內容(
HTML
、XML
、圖像等等)、整理訊息(例如加入CSS
等),以及計算網頁的顯示方式,然後會輸出至顯示器或打印機。瀏覽器的內核的不同對於網頁的語法解釋會有不同,所以渲染的效果也不相同。所有網頁瀏覽器、電子郵件客戶端以及其它需要編輯、顯示網絡內容的應用程序都需要內核 -
JS
引擎則:解析和執行javascript
來實現網頁的動態效果 -
最開始渲染引擎和
JS
引擎並沒有區分的很明確,後來JS引擎越來越獨立,內核就傾向於只指渲染引擎
#9 html5有哪些新特性、移除了那些元素?
-
HTML5
現在已經不是SGML
的子集,主要是關於圖像,位置,存儲,多任務等功能的增加- 繪畫
canvas
- 用於媒介回放的
video
和audio
元素 - 本地離線存儲
localStorage
長期存儲數據,瀏覽器關閉後數據不丟失 sessionStorage
的數據在瀏覽器關閉後自動刪除- 語意化更好的內容元素,比如
article
、footer
、header
、nav
、section
- 表單控件,
calendar
、date
、time
、email
、url
、search
- 新的技術
webworker
、websocket
、Geolocation
- 繪畫
-
移除的元素:
- 純表現的元素:
basefont
、big
、center
、font
、s
、strike
、tt
、u
- 對可用性產生負面影響的元素:
frame
、frameset
、noframes
- 純表現的元素:
-
支持
HTML5
新標籤:IE8/IE7/IE6
支持通過document.createElement
方法產生的標籤- 可以利用這一特性讓這些瀏覽器支持
HTML5
新標籤 - 瀏覽器支持新標籤後,還需要添加標籤默認的樣式
-
當然也可以直接使用成熟的框架、比如
html5shim
#10 HTML5
的離線儲存怎麼使用,工作原理能不能解釋一下?
-
在用戶沒有與因特網連接時,可以正常訪問站點或應用,在用戶與因特網連接時,更新用戶機器上的緩存文件
-
原理:
HTML5
的離線存儲是基於一個新建的.appcache
文件的緩存機制(不是存儲技術),通過這個文件上的解析清單離線存儲資源,這些資源就會像cookie
一樣被存儲了下來。之後當網絡在處於離線狀態下時,瀏覽器會通過被離線存儲的數據進行頁面展示 -
如何使用:
- 頁面頭部像下面一樣加入一個
manifest
的屬性; - 在
cache.manifest
文件的編寫離線存儲的資源 - 在離線狀態時,操作
window.applicationCache
進行需求實現
- 頁面頭部像下面一樣加入一個
CACHE MANIFEST
#v0.11
CACHE:
js/app.js
css/style.css
NETWORK:
resourse/logo.png
FALLBACK:
/offline.html
#11 瀏覽器是怎麼對HTML5
的離線儲存資源進行管理和加載的呢
-
在線的情況下,瀏覽器發現
html
頭部有manifest
屬性,它會請求manifest
文件,如果是第一次訪問app
,那麼瀏覽器就會根據manifest文件的內容下載相應的資源並且進行離線存儲。如果已經訪問過app
並且資源已經離線存儲了,那麼瀏覽器就會使用離線的資源加載頁面,然後瀏覽器會對比新的manifest
文件與舊的manifest
文件,如果文件沒有發生改變,就不做任何操作,如果文件改變了,那麼就會重新下載文件中的資源並進行離線存儲。 -
離線的情況下,瀏覽器就直接使用離線存儲的資源。
#12 請描述一下 cookies
,sessionStorage
和 localStorage
的區別?
-
cookie
是網站爲了標示用戶身份而儲存在用戶本地終端(Client Side)上的數據(通常經過加密) -
cookie數據始終在同源的http請求中攜帶(即使不需要),記會在瀏覽器和服務器間來回傳遞
-
sessionStorage
和localStorage
不會自動把數據發給服務器,僅在本地保存 -
存儲大小:
cookie
數據大小不能超過4ksessionStorage
和localStorage
雖然也有存儲大小的限制,但比cookie
大得多,可以達到5M或更大
-
有期時間:
localStorage
存儲持久數據,瀏覽器關閉後數據不丟失除非主動刪除數據sessionStorage
數據在當前瀏覽器窗口關閉後自動刪除cookie
設置的cookie
過期時間之前一直有效,即使窗口或瀏覽器關閉
#13 iframe有那些缺點?
iframe
會阻塞主頁面的Onload
事件- 搜索引擎的檢索程序無法解讀這種頁面,不利於
SEO
iframe
和主頁面共享連接池,而瀏覽器對相同域的連接有限制,所以會影響頁面的並行加載- 使用
iframe
之前需要考慮這兩個缺點。如果需要使用iframe
,最好是通過javascript
動態給iframe
添加src
屬性值,這樣可以繞開以上兩個問題
#14 WEB標準以及W3C標準是什麼?
- 標籤閉合、標籤小寫、不亂嵌套、使用外鏈
css
和js
、結構行爲表現的分離
#15 xhtml和html有什麼區別?
-
一個是功能上的差別
- 主要是
XHTML
可兼容各大瀏覽器、手機以及PDA
,並且瀏覽器也能快速正確地編譯網頁
- 主要是
-
另外是書寫習慣的差別
XHTML
元素必須被正確地嵌套,閉合,區分大小寫,文檔必須擁有根元素
#16 Doctype作用? 嚴格模式與混雜模式如何區分?它們有何意義?
- 頁面被加載的時,
link
會同時被加載,而@imort
頁面被加載的時,link
會同時被加載,而@import
引用的CSS
會等到頁面被加載完再加載import
只在IE5
以上才能識別,而link
是XHTML
標籤,無兼容問題link
方式的樣式的權重 高於@import
的權重 <!DOCTYPE>
聲明位於文檔中的最前面,處於<html>
標籤之前。告知瀏覽器的解析器, 用什麼文檔類型 規範來解析這個文檔- 嚴格模式的排版和
JS
運作模式是 以該瀏覽器支持的最高標準運行 - 在混雜模式中,頁面以寬鬆的向後兼容的方式顯示。模擬老式瀏覽器的行爲以防止站點無法工作。
DOCTYPE
不存在或格式不正確會導致文檔以混雜模式呈現
#17 行內元素有哪些?塊級元素有哪些? 空(void)元素有那些?行內元素和塊級元素有什麼區別?
- 行內元素有:
a b span img input select strong
- 塊級元素有:
div ul ol li dl dt dd h1 h2 h3 h4… p
- 空元素:
<br> <hr> <img> <input> <link> <meta>
- 行內元素不可以設置寬高,不獨佔一行
- 塊級元素可以設置寬高,獨佔一行
#18 HTML全局屬性(global attribute)有哪些
class
:爲元素設置類標識data-*
: 爲元素增加自定義屬性draggable
: 設置元素是否可拖拽id
: 元素id
,文檔內唯一lang
: 元素內容的的語言style
: 行內css
樣式title
: 元素相關的建議信息
#19 Canvas和SVG有什麼區別?
svg
繪製出來的每一個圖形的元素都是獨立的DOM
節點,能夠方便的綁定事件或用來修改。canvas
輸出的是一整幅畫布svg
輸出的圖形是矢量圖形,後期可以修改參數來自由放大縮小,不會失真和鋸齒。而canvas
輸出標量畫布,就像一張圖片一樣,放大會失真或者鋸齒
#20 HTML5 爲什麼只需要寫 <!DOCTYPE HTML>
HTML5
不基於SGML
,因此不需要對DTD
進行引用,但是需要doctype
來規範瀏覽器的行爲- 而
HTML4.01
基於SGML
,所以需要對DTD
進行引用,才能告知瀏覽器文檔所使用的文檔類型
#21 如何在頁面上實現一個圓形的可點擊區域?
svg
border-radius
- 純
js
實現 需要求一個點在不在圓上簡單算法、獲取鼠標座標等等
#22 網頁驗證碼是幹嘛的,是爲了解決什麼安全問題
- 區分用戶是計算機還是人的公共全自動程序。可以防止惡意破解密碼、刷票、論壇灌水
- 有效防止黑客對某一個特定註冊用戶用特定程序暴力破解方式進行不斷的登陸嘗試
#23 viewport
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
// width 設置viewport寬度,爲一個正整數,或字符串‘device-width’
// device-width 設備寬度
// height 設置viewport高度,一般設置了寬度,會自動解析出高度,可以不用設置
// initial-scale 默認縮放比例(初始縮放比例),爲一個數字,可以帶小數
// minimum-scale 允許用戶最小縮放比例,爲一個數字,可以帶小數
// maximum-scale 允許用戶最大縮放比例,爲一個數字,可以帶小數
// user-scalable 是否允許手動縮放
- 延伸提問
- 怎樣處理 移動端
1px
被 渲染成2px
問題
- 怎樣處理 移動端
局部處理
mate
標籤中的viewport
屬性 ,initial-scale
設置爲1
rem
按照設計稿標準走,外加利用transfrome
的scale(0.5)
縮小一倍即可;
全局處理
mate
標籤中的viewport
屬性 ,initial-scale
設置爲0.5
rem
按照設計稿標準走即可
#24 渲染優化
-
禁止使用
iframe
(阻塞父文檔onload
事件)iframe
會阻塞主頁面的Onload
事件- 搜索引擎的檢索程序無法解讀這種頁面,不利於SEO
iframe
和主頁面共享連接池,而瀏覽器對相同域的連接有限制,所以會影響頁面的並行加載- 使用
iframe
之前需要考慮這兩個缺點。如果需要使用iframe
,最好是通過javascript
- 動態給
iframe
添加src
屬性值,這樣可以繞開以上兩個問題
-
禁止使用
gif
圖片實現loading
效果(降低CPU
消耗,提升渲染性能) -
使用
CSS3
代碼代替JS
動畫(儘可能避免重繪重排以及迴流) -
對於一些小圖標,可以使用base64位編碼,以減少網絡請求。但不建議大圖使用,比較耗費
CPU
- 小圖標優勢在於
- 減少
HTTP
請求 - 避免文件跨域
- 修改及時生效
- 減少
- 小圖標優勢在於
-
頁面頭部的
<style></style>
<script></script>
會阻塞頁面;(因爲Renderer
進程中JS
線程和渲染線程是互斥的) -
頁面中空的
href
和src
會阻塞頁面其他資源的加載 (阻塞下載進程) -
網頁
gzip
,CDN
託管,data
緩存 ,圖片服務器 -
前端模板 JS+數據,減少由於
HTML
標籤導致的帶寬浪費,前端用變量保存AJAX請求結果,每次操作本地變量,不用請求,減少請求次數 -
用
innerHTML
代替DOM
操作,減少DOM
操作次數,優化javascript
性能 -
當需要設置的樣式很多時設置
className
而不是直接操作style
-
少用全局變量、緩存
DOM
節點查找的結果。減少IO
讀取操作 -
圖片預加載,將樣式表放在頂部,將腳本放在底部 加上時間戳
-
對普通的網站有一個統一的思路,就是儘量向前端優化、減少數據庫操作、減少磁盤
IO
#25 meta viewport相關
<!DOCTYPE html> <!--H5標準聲明,使用 HTML5 doctype,不區分大小寫-->
<head lang=”en”> <!--標準的 lang 屬性寫法-->
<meta charset=’utf-8′> <!--聲明文檔使用的字符編碼-->
<meta http-equiv=”X-UA-Compatible” content=”IE=edge,chrome=1″/> <!--優先使用 IE 最新版本和 Chrome-->
<meta name=”description” content=”不超過150個字符”/> <!--頁面描述-->
<meta name=”keywords” content=””/> <!-- 頁面關鍵詞-->
<meta name=”author” content=”name, [email protected]”/> <!--網頁作者-->
<meta name=”robots” content=”index,follow”/> <!--搜索引擎抓取-->
<meta name=”viewport” content=”initial-scale=1, maximum-scale=3, minimum-scale=1, user-scalable=no”> <!--爲移動設備添加 viewport-->
<meta name=”apple-mobile-web-app-title” content=”標題”> <!--iOS 設備 begin-->
<meta name=”apple-mobile-web-app-capable” content=”yes”/> <!--添加到主屏後的標題(iOS 6 新增)
是否啓用 WebApp 全屏模式,刪除蘋果默認的工具欄和菜單欄-->
<meta name=”apple-itunes-app” content=”app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL”>
<!--添加智能 App 廣告條 Smart App Banner(iOS 6+ Safari)-->
<meta name=”apple-mobile-web-app-status-bar-style” content=”black”/>
<meta name=”format-detection” content=”telphone=no, email=no”/> <!--設置蘋果工具欄顏色-->
<meta name=”renderer” content=”webkit”> <!-- 啓用360瀏覽器的極速模式(webkit)-->
<meta http-equiv=”X-UA-Compatible” content=”IE=edge”> <!--避免IE使用兼容模式-->
<meta http-equiv=”Cache-Control” content=”no-siteapp” /> <!--不讓百度轉碼-->
<meta name=”HandheldFriendly” content=”true”> <!--針對手持設備優化,主要是針對一些老的不識別viewport的瀏覽器,比如黑莓-->
<meta name=”MobileOptimized” content=”320″> <!--微軟的老式瀏覽器-->
<meta name=”screen-orientation” content=”portrait”> <!--uc強制豎屏-->
<meta name=”x5-orientation” content=”portrait”> <!--QQ強制豎屏-->
<meta name=”full-screen” content=”yes”> <!--UC強制全屏-->
<meta name=”x5-fullscreen” content=”true”> <!--QQ強制全屏-->
<meta name=”browsermode” content=”application”> <!--UC應用模式-->
<meta name=”x5-page-mode” content=”app”> <!-- QQ應用模式-->
<meta name=”msapplication-tap-highlight” content=”no”> <!--windows phone 點擊無高亮
設置頁面不緩存-->
<meta http-equiv=”pragma” content=”no-cache”>
<meta http-equiv=”cache-control” content=”no-cache”>
<meta http-equiv=”expires” content=”0″>
#26 你做的頁面在哪些流覽器測試過?這些瀏覽器的內核分別是什麼?
IE
:trident
內核Firefox
:gecko
內核Safari
:webkit
內核Opera
:以前是presto
內核,Opera
現已改用Google -Chrome
的Blink
內核Chrome:Blink
(基於webkit
,Google與Opera Software共同開發)
#27 div+css的佈局較table佈局有什麼優點?
- 改版的時候更方便 只要改
css
文件。 - 頁面加載速度更快、結構化清晰、頁面顯示簡潔。
- 表現與結構相分離。
- 易於優化(
seo
)搜索引擎更友好,排名更容易靠前。
#28 a:img的alt與title有何異同?b:strong與em的異同?
-
alt(alt text)
:爲不能顯示圖像、窗體或applets
的用戶代理(UA
),alt
屬性用來指定替換文字。替換文字的語言由lang
屬性指定。(在IE瀏覽器下會在沒有title
時把alt
當成tool tip
顯示) -
title(tool tip)
:該屬性爲設置該屬性的元素提供建議性的信息 -
strong
:粗體強調標籤,強調,表示內容的重要性 -
em
:斜體強調標籤,更強烈強調,表示內容的強調點
#29 你能描述一下漸進增強和優雅降級之間的不同嗎
- 漸進增強:針對低版本瀏覽器進行構建頁面,保證最基本的功能,然後再針對高級瀏覽器進行效果、交互等改進和追加功能達到更好的用戶體驗。
- 優雅降級:一開始就構建完整的功能,然後再針對低版本瀏覽器進行兼容。
區別:優雅降級是從複雜的現狀開始,並試圖減少用戶體驗的供給,而漸進增強則是從一個非常基礎的,能夠起作用的版本開始,並不斷擴充,以適應未來環境的需要。降級(功能衰減)意味着往回看;而漸進增強則意味着朝前看,同時保證其根基處於安全地帶
#30 爲什麼利用多個域名來存儲網站資源會更有效?
CDN
緩存更方便- 突破瀏覽器併發限制
- 節約
cookie
帶寬 - 節約主域名的連接數,優化頁面響應速度
- 防止不必要的安全問題
#31 簡述一下src與href的區別
src
用於替換當前元素,href用於在當前文檔和引用資源之間確立聯繫。src
是source
的縮寫,指向外部資源的位置,指向的內容將會嵌入到文檔中當前標籤所在位置;在請求src
資源時會將其指向的資源下載並應用到文檔內,例如js
腳本,img
圖片和frame
等元素
<script src ="js.js"></script>
當瀏覽器解析到該元素時,會暫停其他資源的下載和處理,直到將該資源加載、編譯、執行完畢,圖片和框架等元素也如此,類似於將所指向資源嵌入當前標籤內。這也是爲什麼將js腳本放在底部而不是頭部
href
是Hypertext Reference
的縮寫,指向網絡資源所在位置,建立和當前元素(錨點)或當前文檔(鏈接)之間的鏈接,如果我們在文檔中添加<link href="common.css" rel="stylesheet"/>
那麼瀏覽器會識別該文檔爲css
文件,就會並行下載資源並且不會停止對當前文檔的處理。這也是爲什麼建議使用link
方式來加載css
,而不是使用@import
方式
#32 知道的網頁製作會用到的圖片格式有哪些?
png-8
、png-24
、jpeg
、gif
、svg
但是上面的那些都不是面試官想要的最後答案。面試官希望聽到是
Webp
,Apng
。(是否有關注新技術,新鮮事物)
- Webp:
WebP
格式,谷歌(google)開發的一種旨在加快圖片加載速度的圖片格式。圖片壓縮體積大約只有JPEG
的2/3
,並能節省大量的服務器帶寬資源和數據空間。Facebook Ebay
等知名網站已經開始測試並使用WebP
格式。 - 在質量相同的情況下,WebP格式圖像的體積要比JPEG格式圖像小
40%
。 - Apng:全稱是
“Animated Portable Network Graphics”
, 是PNG的位圖動畫擴展,可以實現png格式的動態圖片效果。04年誕生,但一直得不到各大瀏覽器廠商的支持,直到日前得到iOS safari 8
的支持,有望代替GIF
成爲下一代動態圖標準
#33 在css/js代碼上線之後開發人員經常會優化性能,從用戶刷新網頁開始,一次js請求一般情況下有哪些地方會有緩存處理?
dns
緩存,cdn
緩存,瀏覽器緩存,服務器緩存
#33 一個頁面上有大量的圖片(大型電商網站),加載很慢,你有哪些方法優化這些圖片的加載,給用戶更好的體驗。
- 圖片懶加載,在頁面上的未可視區域可以添加一個滾動事件,判斷圖片位置與瀏覽器頂端的距離與頁面的距離,如果前者小於後者,優先加載。
- 如果爲幻燈片、相冊等,可以使用圖片預加載技術,將當前展示圖片的前一張和後一張優先下載。
- 如果圖片爲css圖片,可以使用
CSSsprite
,SVGsprite
,Iconfont
、Base64
等技術。 - 如果圖片過大,可以使用特殊編碼的圖片,加載時會先加載一張壓縮的特別厲害的縮略圖,以提高用戶體驗。
- 如果圖片展示區域小於圖片的真實大小,則因在服務器端根據業務需要先行進行圖片壓縮,圖片壓縮後大小與展示一致。
#34 常見排序算法的時間複雜度,空間複雜度
#35 web開發中會話跟蹤的方法有哪些
cookie
session
url
重寫- 隱藏
input
ip
地址
#36 HTTP request報文結構是怎樣的
- 首行是Request-Line包括:請求方法,請求URI,協議版本,CRLF
- 首行之後是若干行請求頭,包括general-header,request-header或者entity-header,每個一行以CRLF結束
- 請求頭和消息實體之間有一個CRLF分隔
- 根據實際請求需要可能包含一個消息實體 一個請求報文例子如下:
GET /Protocols/rfc2616/rfc2616-sec5.html HTTP/1.1
Host: www.w3.org
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36
Referer: https://www.google.com.hk/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Cookie: authorstyle=yes
If-None-Match: "2cc8-3e3073913b100"
If-Modified-Since: Wed, 01 Sep 2004 13:24:52 GMT
name=qiu&age=25
#37 HTTP response報文結構是怎樣的
- 首行是狀態行包括:HTTP版本,狀態碼,狀態描述,後面跟一個CRLF
- 首行之後是若干行響應頭,包括:通用頭部,響應頭部,實體頭部
- 響應頭部和響應實體之間用一個CRLF空行分隔
- 最後是一個可能的消息實體 響應報文例子如下:
HTTP/1.1 200 OK
Date: Tue, 08 Jul 2014 05:28:43 GMT
Server: Apache/2
Last-Modified: Wed, 01 Sep 2004 13:24:52 GMT
ETag: "40d7-3e3073913b100"
Accept-Ranges: bytes
Content-Length: 16599
Cache-Control: max-age=21600
Expires: Tue, 08 Jul 2014 11:28:43 GMT
P3P: policyref="http://www.w3.org/2001/05/P3P/p3p.xml"
Content-Type: text/html; charset=iso-8859-1
{"name": "qiu", "age": 25}
#二、CSS部分
#1 css sprite是什麼,有什麼優缺點
-
概念:將多個小圖片拼接到一個圖片中。通過
background-position
和元素尺寸調節需要顯示的背景圖案。 -
優點:
- 減少
HTTP
請求數,極大地提高頁面加載速度 - 增加圖片信息重複度,提高壓縮比,減少圖片大小
- 更換風格方便,只需在一張或幾張圖片上修改顏色或樣式即可實現
- 減少
-
缺點:
- 圖片合併麻煩
- 維護麻煩,修改一個圖片可能需要從新佈局整個圖片,樣式
#2 display: none;
與visibility: hidden;
的區別
-
聯繫:它們都能讓元素不可見
-
區別:
display:none
;會讓元素完全從渲染樹中消失,渲染的時候不佔據任何空間;visibility: hidden
;不會讓元素從渲染樹消失,渲染師元素繼續佔據空間,只是內容不可見display: none
;是非繼承屬性,子孫節點消失由於元素從渲染樹消失造成,通過修改子孫節點屬性無法顯示;visibility: hidden;
是繼承屬性,子孫節點消失由於繼承了hidden
,通過設置visibility: visible;
可以讓子孫節點顯式- 修改常規流中元素的
display
通常會造成文檔重排。修改visibility
屬性只會造成本元素的重繪。 - 讀屏器不會讀取
display: none
;元素內容;會讀取visibility: hidden;
元素內容
#3 link
與@import
的區別
link
是HTML
方式,@import
是CSS方式link
最大限度支持並行下載,@import
過多嵌套導致串行下載,出現FOUC
(文檔樣式短暫失效)link
可以通過rel="alternate stylesheet"
指定候選樣式- 瀏覽器對
link
支持早於@import
,可以使用@import
對老瀏覽器隱藏樣式 @import
必須在樣式規則之前,可以在css文件中引用其他文件- 總體來說:
link
優於@import
#4 什麼是FOUC?如何避免
Flash Of Unstyled Content
:用戶定義樣式表加載之前瀏覽器使用默認樣式顯示文檔,用戶樣式加載渲染之後再從新顯示文檔,造成頁面閃爍。- 解決方法:把樣式表放到文檔的
<head>
#5 如何創建塊級格式化上下文(block formatting context),BFC有什麼用
-
創建規則:
- 根元素
- 浮動元素(
float
不取值爲none
) - 絕對定位元素(
position
取值爲absolute
或fixed
) display
取值爲inline-block
、table-cell
、table-caption
、flex
、inline-flex
之一的元素overflow
不取值爲visible
的元素
-
作用:
- 可以包含浮動元素
- 不被浮動元素覆蓋
- 阻止父子元素的
margin
摺疊
#6 display、float、position的關係
- 如果
display
取值爲none
,那麼position
和float
都不起作用,這種情況下元素不產生框 - 否則,如果
position
取值爲absolute
或者fixed
,框就是絕對定位的,float
的計算值爲none
,display
根據下面的表格進行調整。 - 否則,如果
float
不是none
,框是浮動的,display
根據下表進行調整 - 否則,如果元素是根元素,
display
根據下表進行調整 - 其他情況下
display
的值爲指定值 - 總結起來:絕對定位、浮動、根元素都需要調整
display
#7 清除浮動的幾種方式,各自的優缺點
- 父級
div
定義height
- 結尾處加空
div
標籤clear:both
- 父級
div
定義僞類:after
和zoom
- 父級
div
定義overflow:hidden
- 父級
div
也浮動,需要定義寬度 - 結尾處加
br
標籤clear:both
- 比較好的是第3種方式,好多網站都這麼用
#8 爲什麼要初始化CSS樣式?
- 因爲瀏覽器的兼容問題,不同瀏覽器對有些標籤的默認值是不同的,如果沒對
CSS
初始化往往會出現瀏覽器之間的頁面顯示差異。 - 當然,初始化樣式會對
SEO
有一定的影響,但魚和熊掌不可兼得,但力求影響最小的情況下初始化
#9 css3有哪些新特性
- 新增各種
css
選擇器 - 圓角
border-radius
- 多列布局
- 陰影和反射
- 文字特效
text-shadow
- 線性漸變
- 旋轉
transform
CSS3新增僞類有那些?
p:first-of-type
選擇屬於其父元素的首個<p>
元素的每個<p>
元素。p:last-of-type
選擇屬於其父元素的最後<p>
元素的每個<p>
元素。p:only-of-type
選擇屬於其父元素唯一的<p>
元素的每個<p>
元素。p:only-child
選擇屬於其父元素的唯一子元素的每個<p>
元素。p:nth-child(2)
選擇屬於其父元素的第二個子元素的每個<p>
元素。:after
在元素之前添加內容,也可以用來做清除浮動。:before
在元素之後添加內容。:enabled
已啓用的表單元素。:disabled
已禁用的表單元素。:checked
單選框或複選框被選中。
#10 display有哪些值?說明他們的作用
block
轉換成塊狀元素。inline
轉換成行內元素。none
設置元素不可見。inline-block
象行內元素一樣顯示,但其內容象塊類型元素一樣顯示。list-item
象塊類型元素一樣顯示,並添加樣式列表標記。table
此元素會作爲塊級表格來顯示inherit
規定應該從父元素繼承display
屬性的值
#11 介紹一下標準的CSS的盒子模型?低版本IE的盒子模型有什麼不同的?
- 有兩種,
IE
盒子模型、W3C
盒子模型; - 盒模型: 內容(content)、填充(
padding
)、邊界(margin
)、 邊框(border
); - 區 別:
IE
的content
部分把border
和padding
計算了進去;
#12 CSS優先級算法如何計算?
- 優先級就近原則,同權重情況下樣式定義最近者爲準
- 載入樣式以最後載入的定位爲準
- 優先級爲:
!important > id > class > tag
;!important
比 內聯優先級高
#13 對BFC規範的理解?
- 它決定了元素如何對其內容進行定位,以及與其他元素的關係和相互作用
#14 談談浮動和清除浮動
- 浮動的框可以向左或向右移動,直到他的外邊緣碰到包含框或另一個浮動框的邊框爲止。由於浮動框不在文檔的普通流中,所以文檔的普通流的塊框表現得就像浮動框不存在一樣。浮動的塊框會漂浮在文檔普通流的塊框上
#15 position的值, relative和absolute定位原點是
absolute
:生成絕對定位的元素,相對於static
定位以外的第一個父元素進行定位fixed
:生成絕對定位的元素,相對於瀏覽器窗口進行定位relative
:生成相對定位的元素,相對於其正常位置進行定位static
默認值。沒有定位,元素出現在正常的流中inherit
規定從父元素繼承position
屬性的值
#16 display:inline-block 什麼時候不會顯示間隙?(攜程)
- 移除空格
- 使用
margin
負值 - 使用
font-size:0
letter-spacing
word-spacing
#17 PNG\GIF\JPG的區別及如何選
-
GIF
8
位像素,256
色- 無損壓縮
- 支持簡單動畫
- 支持
boolean
透明 - 適合簡單動畫
-
JPEG
- 顏色限於
256
- 有損壓縮
- 可控制壓縮質量
- 不支持透明
- 適合照片
- 顏色限於
-
PNG
- 有
PNG8
和truecolor PNG
PNG8
類似GIF
顏色上限爲256
,文件小,支持alpha
透明度,無動畫- 適合圖標、背景、按鈕
- 有
#18 行內元素float:left後是否變爲塊級元素?
行內元素設置成浮動之後變得更加像是
inline-block
(行內塊級元素,設置成這個屬性的元素會同時擁有行內和塊級的特性,最明顯的不同是它的默認寬度不是100%
),這時候給行內元素設置padding-top
和padding-bottom
或者width
、height
都是有效果的
#19 在網頁中的應該使用奇數還是偶數的字體?爲什麼呢?
- 偶數字號相對更容易和 web 設計的其他部分構成比例關係
#20 ::before 和 :after中雙冒號和單冒號 有什麼區別?解釋一下這2個僞元素的作用
- 單冒號(
:
)用於CSS3
僞類,雙冒號(::
)用於CSS3
僞元素 - 用於區分僞類和僞元素
#21 如果需要手動寫動畫,你認爲最小時間間隔是多久,爲什麼?(阿里)
- 多數顯示器默認頻率是
60Hz
,即1
秒刷新60
次,所以理論上最小間隔爲1/60*1000ms = 16.7ms
#22 CSS合併方法
- 避免使用
@import
引入多個css
文件,可以使用CSS
工具將CSS
合併爲一個CSS
文件,例如使用Sass\Compass
等
#23 CSS不同選擇器的權重(CSS層疊的規則)
!important
規則最重要,大於其它規則- 行內樣式規則,加
1000
- 對於選擇器中給定的各個
ID
屬性值,加100
- 對於選擇器中給定的各個類屬性、屬性選擇器或者僞類選擇器,加
10
- 對於選擇其中給定的各個元素標籤選擇器,加1
- 如果權值一樣,則按照樣式規則的先後順序來應用,順序靠後的覆蓋靠前的規則
#24 列出你所知道可以改變頁面佈局的屬性
position
、display
、float
、width
、height
、margin
、padding
、top
、left
、right
、`
#25 CSS在性能優化方面的實踐
css
壓縮與合併、Gzip
壓縮css
文件放在head
裏、不要用@import
- 儘量用縮寫、避免用濾鏡、合理使用選擇器
#26 CSS3動畫(簡單動畫的實現,如旋轉等)
- 依靠
CSS3
中提出的三個屬性:transition
、transform
、animation
transition
:定義了元素在變化過程中是怎麼樣的,包含transition-property
、transition-duration
、transition-timing-function
、transition-delay
。transform
:定義元素的變化結果,包含rotate
、scale
、skew
、translate
。animation
:動畫定義了動作的每一幀(@keyframes
)有什麼效果,包括animation-name
,animation-duration
、animation-timing-function
、animation-delay
、animation-iteration-count
、animation-direction
#27 base64的原理及優缺點
- 優點可以加密,減少了
HTTTP
請求 - 缺點是需要消耗
CPU
進行編解碼
#28 幾種常見的CSS佈局
#流體佈局
.left {
float: left;
width: 100px;
height: 200px;
background: red;
}
.right {
float: right;
width: 200px;
height: 200px;
background: blue;
}
.main {
margin-left: 120px;
margin-right: 220px;
height: 200px;
background: green;
}
<div class="container">
<div class="left"></div>
<div class="right"></div>
<div class="main"></div>
</div>
#聖盃佈局
.container {
margin-left: 120px;
margin-right: 220px;
}
.main {
float: left;
width: 100%;
height:300px;
background: green;
}
.left {
position: relative;
left: -120px;
float: left;
height: 300px;
width: 100px;
margin-left: -100%;
background: red;
}
.right {
position: relative;
right: -220px;
float: right;
height: 300px;
width: 200px;
margin-left: -200px;
background: blue;
}
<div class="container">
<div class="main"></div>
<div class="left"></div>
<div class="right"></div>
</div>
#雙飛翼佈局
.content {
float: left;
width: 100%;
}
.main {
height: 200px;
margin-left: 110px;
margin-right: 220px;
background: green;
}
.main::after {
content: '';
display: block;
font-size:0;
height: 0;
zoom: 1;
clear: both;
}
.left {
float:left;
height: 200px;
width: 100px;
margin-left: -100%;
background: red;
}
.right {
float: right;
height: 200px;
width: 200px;
margin-left: -200px;
background: blue;
}
<div class="content">
<div class="main"></div>
</div>
<div class="left"></div>
<div class="right"></div>
#29 stylus/sass/less區別
- 均具有“變量”、“混合”、“嵌套”、“繼承”、“顏色混合”五大基本特性
Scss
和LESS
語法較爲嚴謹,LESS
要求一定要使用大括號“{}”,Scss
和Stylus
可以通過縮進表示層次與嵌套關係Scss
無全局變量的概念,LESS
和Stylus
有類似於其它語言的作用域概念Sass
是基於Ruby
語言的,而LESS
和Stylus
可以基於NodeJS
NPM
下載相應庫後進行編譯;
#30 postcss的作用
- 可以直觀的理解爲:它就是一個平臺。爲什麼說它是一個平臺呢?因爲我們直接用它,感覺不能幹什麼事情,但是如果讓一些插件在它上面跑,那麼將會很強大
PostCSS
提供了一個解析器,它能夠將CSS
解析成抽象語法樹- 通過在
PostCSS
這個平臺上,我們能夠開發一些插件,來處理我們的CSS
,比如熱門的:autoprefixer
postcss
可以對sass處理過後的css
再處理 最常見的就是autoprefixer
#31 css樣式(選擇器)的優先級
- 計算權重確定
!important
- 內聯樣式
- 後寫的優先級高
#32 自定義字體的使用場景
- 宣傳/品牌/
banner
等固定文案 - 字體圖標
#33 如何美化CheckBox
<label>
屬性for
和id
- 隱藏原生的
<input>
:checked + <label>
#34 僞類和僞元素的區別
- 僞類表狀態
- 僞元素是真的有元素
- 前者單冒號,後者雙冒號
#35 base64
的使用
- 用於減少
HTTP
請求 - 適用於小圖片
base64
的體積約爲原圖的4/3
#36 自適應佈局
思路:
- 左側浮動或者絕對定位,然後右側
margin
撐開 - 使用
<div>
包含,然後靠負margin
形成bfc
- 使用
flex
#37 請用CSS寫一個簡單的幻燈片效果頁面
知道是要用
CSS3
。使用animation
動畫實現一個簡單的幻燈片效果
/**css**/
.ani{
width:480px;
height:320px;
margin:50px auto;
overflow: hidden;
box-shadow:0 0 5px rgba(0,0,0,1);
background-size: cover;
background-position: center;
-webkit-animation-name: "loops";
-webkit-animation-duration: 20s;
-webkit-animation-iteration-count: infinite;
}
@-webkit-keyframes "loops" {
0% {
background:url(http://d.hiphotos.baidu.com/image/w%3D400/sign=c01e6adca964034f0fcdc3069fc27980/e824b899a9014c08e5e38ca4087b02087af4f4d3.jpg) no-repeat;
}
25% {
background:url(http://b.hiphotos.baidu.com/image/w%3D400/sign=edee1572e9f81a4c2632edc9e72b6029/30adcbef76094b364d72bceba1cc7cd98c109dd0.jpg) no-repeat;
}
50% {
background:url(http://b.hiphotos.baidu.com/image/w%3D400/sign=937dace2552c11dfded1be2353266255/d8f9d72a6059252d258e7605369b033b5bb5b912.jpg) no-repeat;
}
75% {
background:url(http://g.hiphotos.baidu.com/image/w%3D400/sign=7d37500b8544ebf86d71653fe9f9d736/0df431adcbef76095d61f0972cdda3cc7cd99e4b.jpg) no-repeat;
}
100% {
background:url(http://c.hiphotos.baidu.com/image/w%3D400/sign=cfb239ceb0fb43161a1f7b7a10a54642/3b87e950352ac65ce2e73f76f9f2b21192138ad1.jpg) no-repeat;
}
}
#38 什麼是外邊距重疊?重疊的結果是什麼?
外邊距重疊就是margin-collapse
- 在CSS當中,相鄰的兩個盒子(可能是兄弟關係也可能是祖先關係)的外邊距可以結合成一個單獨的外邊距。這種合併外邊距的方式被稱爲摺疊,並且因而所結合成的外邊距稱爲摺疊外邊距。
摺疊結果遵循下列計算規則:
- 兩個相鄰的外邊距都是正數時,摺疊結果是它們兩者之間較大的值。
- 兩個相鄰的外邊距都是負數時,摺疊結果是兩者絕對值的較大值。
- 兩個外邊距一正一負時,摺疊結果是兩者的相加的和。
#39 rgba()和opacity的透明效果有什麼不同?
rgba()
和opacity
都能實現透明效果,但最大的不同是opacity
作用於元素,以及元素內的所有內容的透明度,- 而
rgba()
只作用於元素的顏色或其背景色。(設置rgba
透明的元素的子元素不會繼承透明效果!)
#40 css中可以讓文字在垂直和水平方向上重疊的兩個屬性是什麼?
- 垂直方向:
line-height
- 水平方向:
letter-spacing
#41 如何垂直居中一個浮動元素?
/**方法一:已知元素的高寬**/
#div1{
background-color:#6699FF;
width:200px;
height:200px;
position: absolute; //父元素需要相對定位
top: 50%;
left: 50%;
margin-top:-100px ; //二分之一的height,width
margin-left: -100px;
}
/**方法二:**/
#div1{
width: 200px;
height: 200px;
background-color: #6699FF;
margin:auto;
position: absolute; //父元素需要相對定位
left: 0;
top: 0;
right: 0;
bottom: 0;
}
如何垂直居中一個<img>
?(用更簡便的方法。)
#container /**<img>的容器設置如下**/
{
display:table-cell;
text-align:center;
vertical-align:middle;
}
#42 px和em的區別
px
和em
都是長度單位,區別是,px
的值是固定的,指定是多少就是多少,計算比較容易。em
得值不是固定的,並且em
會繼承父級元素的字體大小。- 瀏覽器的默認字體高都是
16px
。所以未經調整的瀏覽器都符合:1em=16px
。那麼12px=0.75em
,10px=0.625em
。
#43 Sass、LESS是什麼?大家爲什麼要使用他們?
- 他們是
CSS
預處理器。他是CSS
上的一種抽象層。他們是一種特殊的語法/語言編譯成CSS
。 - 例如Less是一種動態樣式語言. 將CSS賦予了動態語言的特性,如變量,繼承,運算, 函數.
LESS
既可以在客戶端上運行 (支持IE 6+
,Webkit
,Firefox
),也可一在服務端運行 (藉助Node.js
)
爲什麼要使用它們?
- 結構清晰,便於擴展。
- 可以方便地屏蔽瀏覽器私有語法差異。這個不用多說,封裝對- 瀏覽器語法差異的重複處理,減少無意義的機械勞動。
- 可以輕鬆實現多重繼承。
- 完全兼容 CSS 代碼,可以方便地應用到老項目中。LESS 只- 是在 CSS 語法上做了擴展,所以老的 CSS 代碼也可以與 LESS 代碼一同編譯
#44 知道css有個content屬性嗎?有什麼作用?有什麼應用?
css的
content
屬性專門應用在before/after
僞元素上,用於來插入生成內容。最常見的應用是利用僞類清除浮動。
/**一種常見利用僞類清除浮動的代碼**/
.clearfix:after {
content:"."; //這裏利用到了content屬性
display:block;
height:0;
visibility:hidden;
clear:both;
}
.clearfix {
*zoom:1;
}
#45 水平居中的方法
- 元素爲行內元素,設置父元素
text-align:center
- 如果元素寬度固定,可以設置左右
margin
爲auto
; - 如果元素爲絕對定位,設置父元素
position
爲relative
,元素設left:0;right:0;margin:auto;
- 使用
flex-box
佈局,指定justify-content
屬性爲center display
設置爲tabel-ceil
#46 垂直居中的方法
- 將顯示方式設置爲表格,
display:table-cell
,同時設置vertial-align:middle
- 使用
flex
佈局,設置爲align-item:center
- 絕對定位中設置
bottom:0,top:0
,並設置margin:auto
- 絕對定位中固定高度時設置
top:50%,margin-top
值爲高度一半的負值 - 文本垂直居中設置
line-height
爲height
值
#47 如何使用CSS實現硬件加速?
硬件加速是指通過創建獨立的複合圖層,讓GPU來渲染這個圖層,從而提高性能,
- 一般觸發硬件加速的
CSS
屬性有transform
、opacity
、filter
,爲了避免2D動畫在 開始和結束的時候的repaint
操作,一般使用tranform:translateZ(0)
#48 重繪和迴流(重排)是什麼,如何避免?
- DOM的變化影響到了元素的幾何屬性(寬高),瀏覽器重新計算元素的幾何屬性,其他元素的幾何
- 屬性和位置也會受到影響,瀏覽器需要重新構造渲染樹,這個過程稱爲重排,瀏覽器將受到影響的部分
- 重新繪製到屏幕上的過程稱爲重繪。引起重排的原因有
- 添加或者刪除可見的DOM元素,
- 元素位置、尺寸、內容改變,
- 瀏覽器頁面初始化,
- 瀏覽器窗口尺寸改變,重排一定重繪,重繪不一定重排,
減少重繪和重排的方法:
- 不在佈局信息改變時做
DOM
查詢 - 使用
cssText
或者className
一次性改變屬性 - 使用
fragment
- 對於多次重排的元素,如動畫,使用絕對定位脫離文檔流,讓他的改變不影響到其他元素
#49 說一說css3的animation
- css3的
animation
是css3新增的動畫屬性,這個css3動畫的每一幀是通過@keyframes
來聲明的,keyframes
聲明瞭動畫的名稱,通過from
、to
或者是百分比來定義 - 每一幀動畫元素的狀態,通過
animation-name
來引用這個動畫,同時css3動畫也可以定義動畫運行的時長、動畫開始時間、動畫播放方向、動畫循環次數、動畫播放的方式, - 這些相關的動畫子屬性有:
animation-name
定義動畫名、animation-duration
定義動畫播放的時長、animation-delay
定義動畫延遲播放的時間、animation-direction
定義 動畫的播放方向、animation-iteration-count
定義播放次數、animation-fill-mode
定義動畫播放之後的狀態、animation-play-state
定義播放狀態,如暫停運行等、animation-timing-function
- 定義播放的方式,如恆速播放、艱澀播放等。
#50 左邊寬度固定,右邊自適應
左側固定寬度,右側自適應寬度的兩列布局實現
html結構
<div class="outer">
<div class="left">固定寬度</div>
<div class="right">自適應寬度</div>
</div>
在外層
div
(類名爲outer
)的div
中,有兩個子div
,類名分別爲left
和right
,其中left
爲固定寬度,而right
爲自適應寬度
方法1:左側div設置成浮動:float: left,右側div寬度會自拉昇適應
.outer {
width: 100%;
height: 500px;
background-color: yellow;
}
.left {
width: 200px;
height: 200px;
background-color: red;
float: left;
}
.right {
height: 200px;
background-color: blue;
}
方法2:對右側:div進行絕對定位,然後再設置right=0,即可以實現寬度自適應
絕對定位元素的第一個高級特性就是其具有自動伸縮的功能,當我們將
width
設置爲auto
的時候(或者不設置,默認爲auto
),絕對定位元素會根據其left
和right
自動伸縮其大小
.outer {
width: 100%;
height: 500px;
background-color: yellow;
position: relative;
}
.left {
width: 200px;
height: 200px;
background-color: red;
}
.right {
height: 200px;
background-color: blue;
position: absolute;
left: 200px;
top:0;
right: 0;
}
方法3:將左側div進行絕對定位,然後右側div設置margin-left: 200px
.outer {
width: 100%;
height: 500px;
background-color: yellow;
position: relative;
}
.left {
width: 200px;
height: 200px;
background-color: red;
position: absolute;
}
.right {
height: 200px;
background-color: blue;
margin-left: 200px;
}
方法4:使用flex佈局
.outer {
width: 100%;
height: 500px;
background-color: yellow;
display: flex;
flex-direction: row;
}
.left {
width: 200px;
height: 200px;
background-color: red;
}
.right {
height: 200px;
background-color: blue;
flex: 1;
}
#51 兩種以上方式實現已知或者未知寬度的垂直水平居中
/** 1 **/
.wraper {
position: relative;
.box {
position: absolute;
top: 50%;
left: 50%;
width: 100px;
height: 100px;
margin: -50px 0 0 -50px;
}
}
/** 2 **/
.wraper {
position: relative;
.box {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
/** 3 **/
.wraper {
.box {
display: flex;
justify-content:center;
align-items: center;
height: 100px;
}
}
/** 4 **/
.wraper {
display: table;
.box {
display: table-cell;
vertical-align: middle;
}
}
#52 如何實現小於12px的字體效果
transform:scale()
這個屬性只可以縮放可以定義寬高的元素,而行內元素是沒有寬高的,我們可以加上一個display:inline-block
;
transform: scale(0.7);
css
的屬性,可以縮放大小
#三、JavaScript
#1 閉包
-
閉包就是能夠讀取其他函數內部變量的函數
-
閉包是指有權訪問另一個函數作用域中變量的函數,創建閉包的最常見的方式就是在一個函數內創建另一個函數,通過另一個函數訪問這個函數的局部變量,利用閉包可以突破作用鏈域
-
閉包的特性:
- 函數內再嵌套函數
- 內部函數可以引用外層的參數和變量
- 參數和變量不會被垃圾回收機制回收
說說你對閉包的理解
-
使用閉包主要是爲了設計私有的方法和變量。閉包的優點是可以避免全局變量的污染,缺點是閉包會常駐內存,會增大內存使用量,使用不當很容易造成內存泄露。在js中,函數即閉包,只有函數纔會產生作用域的概念
-
閉包 的最大用處有兩個,一個是可以讀取函數內部的變量,另一個就是讓這些變量始終保持在內存中
-
閉包的另一個用處,是封裝對象的私有屬性和私有方法
-
好處:能夠實現封裝和緩存等;
-
壞處:就是消耗內存、不正當使用會造成內存溢出的問題
使用閉包的注意點
- 由於閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露
- 解決方法是,在退出函數之前,將不使用的局部變量全部刪除
#2 說說你對作用域鏈的理解
- 作用域鏈的作用是保證執行環境裏有權訪問的變量和函數是有序的,作用域鏈的變量只能向上訪問,變量訪問到
window
對象即被終止,作用域鏈向下訪問變量是不被允許的 - 簡單的說,作用域就是變量與函數的可訪問範圍,即作用域控制着變量與函數的可見性和生命週期
#3 JavaScript原型,原型鏈 ? 有什麼特點?
-
每個對象都會在其內部初始化一個屬性,就是
prototype
(原型),當我們訪問一個對象的屬性時 -
如果這個對象內部不存在這個屬性,那麼他就會去
prototype
裏找這個屬性,這個prototype
又會有自己的prototype
,於是就這樣一直找下去,也就是我們平時所說的原型鏈的概念 -
關係:
instance.constructor.prototype = instance.__proto__
-
特點:
JavaScript
對象是通過引用來傳遞的,我們創建的每個新對象實體中並沒有一份屬於自己的原型副本。當我們修改原型時,與之相關的對象也會繼承這一改變
-
當我們需要一個屬性的時,
Javascript
引擎會先看當前對象中是否有這個屬性, 如果沒有的 -
就會查找他的
Prototype
對象是否有這個屬性,如此遞推下去,一直檢索到Object
內建對象
#4 請解釋什麼是事件代理
- 事件代理(
Event Delegation
),又稱之爲事件委託。是JavaScript
中常用綁定事件的常用技巧。顧名思義,“事件代理”即是把原本需要綁定的事件委託給父元素,讓父元素擔當事件監聽的職務。事件代理的原理是DOM元素的事件冒泡。使用事件代理的好處是可以提高性能 - 可以大量節省內存佔用,減少事件註冊,比如在
table
上代理所有td
的click
事件就非常棒 - 可以實現當新增子對象時無需再次對其綁定
#5 Javascript如何實現繼承?
-
構造繼承
-
原型繼承
-
實例繼承
-
拷貝繼承
-
原型
prototype
機制或apply
和call
方法去實現較簡單,建議使用構造函數與原型混合方式
function Parent(){
this.name = 'wang';
}
function Child(){
this.age = 28;
}
Child.prototype = new Parent();//繼承了Parent,通過原型
var demo = new Child();
alert(demo.age);
alert(demo.name);//得到被繼承的屬性
#6 談談This對象的理解
this
總是指向函數的直接調用者(而非間接調用者)- 如果有
new
關鍵字,this
指向new
出來的那個對象 - 在事件中,
this
指向觸發這個事件的對象,特殊的是,IE
中的attachEvent
中的this
總是指向全局對象Window
#7 事件模型
W3C
中定義事件的發生經歷三個階段:捕獲階段(capturing
)、目標階段(targetin
)、冒泡階段(bubbling
)
- 冒泡型事件:當你使用事件冒泡時,子級元素先觸發,父級元素後觸發
- 捕獲型事件:當你使用事件捕獲時,父級元素先觸發,子級元素後觸發
DOM
事件流:同時支持兩種事件模型:捕獲型事件和冒泡型事件- 阻止冒泡:在
W3c
中,使用stopPropagation()
方法;在IE下設置cancelBubble = true
- 阻止捕獲:阻止事件的默認行爲,例如
click - <a>
後的跳轉。在W3c
中,使用preventDefault()
方法,在IE
下設置window.event.returnValue = false
#8 new操作符具體幹了什麼呢?
- 創建一個空對象,並且
this
變量引用該對象,同時還繼承了該函數的原型 - 屬性和方法被加入到
this
引用的對象中 - 新創建的對象由
this
所引用,並且最後隱式的返回this
#9 Ajax原理
Ajax
的原理簡單來說是在用戶和服務器之間加了—箇中間層(AJAX
引擎),通過XmlHttpRequest
對象來向服務器發異步請求,從服務器獲得數據,然後用javascrip
t來操作DOM
而更新頁面。使用戶操作與服務器響應異步化。這其中最關鍵的一步就是從服務器獲得請求數據Ajax
的過程只涉及JavaScript
、XMLHttpRequest
和DOM
。XMLHttpRequest
是aja
x的核心機制
/** 1. 創建連接 **/
var xhr = null;
xhr = new XMLHttpRequest()
/** 2. 連接服務器 **/
xhr.open('get', url, true)
/** 3. 發送請求 **/
xhr.send(null);
/** 4. 接受請求 **/
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
success(xhr.responseText);
} else {
/** false **/
fail && fail(xhr.status);
}
}
}
ajax 有那些優缺點?
- 優點:
- 通過異步模式,提升了用戶體驗.
- 優化了瀏覽器和服務器之間的傳輸,減少不必要的數據往返,減少了帶寬佔用.
Ajax
在客戶端運行,承擔了一部分本來由服務器承擔的工作,減少了大用戶量下的服務器負載。Ajax
可以實現動態不刷新(局部刷新)
- 缺點:
- 安全問題
AJAX
暴露了與服務器交互的細節。 - 對搜索引擎的支持比較弱。
- 不容易調試。
- 安全問題
#10 如何解決跨域問題?
首先了解下瀏覽器的同源策略 同源策略
/SOP(Same origin policy)
是一種約定,由Netscape公司1995年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS
、CSFR
等攻擊。所謂同源是指"協議+域名+端口"三者相同,即便兩個不同的域名指向同一個ip地址,也非同源
那麼怎樣解決跨域問題的呢?
- 通過jsonp跨域
var script = document.createElement('script');
script.type = 'text/javascript';
// 傳參並指定回調執行函數爲onBack
script.src = 'http://www.....:8080/login?user=admin&callback=onBack';
document.head.appendChild(script);
// 回調執行函數
function onBack(res) {
alert(JSON.stringify(res));
}
- document.domain + iframe跨域
此方案僅限主域相同,子域不同的跨域應用場景
1.)父窗口:(http://www.domain.com/a.html)
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
document.domain = 'domain.com';
var user = 'admin';
</script>
2.)子窗口:(http://child.domain.com/b.html)
document.domain = 'domain.com';
// 獲取父窗口中變量
alert('get js data from parent ---> ' + window.parent.user);
- nginx代理跨域
- nodejs中間件代理跨域
- 後端在頭部信息裏面設置安全域名
#11 模塊化開發怎麼做?
- 立即執行函數,不暴露私有成員
var module1 = (function(){
var _count = 0;
var m1 = function(){
//...
};
var m2 = function(){
//...
};
return {
m1 : m1,
m2 : m2
};
})();
#12 異步加載JS的方式有哪些?
- defer,只支持
IE
async
:- 創建
script
,插入到DOM
中,加載完畢後callBack
#13 那些操作會造成內存泄漏?
- 內存泄漏指任何對象在您不再擁有或需要它之後仍然存在
setTimeout
的第一個參數使用字符串而非函數的話,會引發內存泄漏- 閉包使用不當
#14 XML和JSON的區別?
-
數據體積方面
JSON
相對於XML
來講,數據的體積小,傳遞的速度更快些。
-
數據交互方面
JSON
與JavaScript
的交互更加方便,更容易解析處理,更好的數據交互
-
數據描述方面
JSON
對數據的描述性比XML
較差
-
傳輸速度方面
JSON
的速度要遠遠快於XML
#15 談談你對webpack的看法
WebPack
是一個模塊打包工具,你可以使用WebPack
管理你的模塊依賴,並編繹輸出模塊們所需的靜態文件。它能夠很好地管理、打包Web
開發中所用到的HTML
、Javascript
、CSS
以及各種靜態文件(圖片、字體等),讓開發過程更加高效。對於不同類型的資源,webpack
有對應的模塊加載器。webpack
模塊打包器會分析模塊間的依賴關係,最後 生成了優化且合併後的靜態資源
#16 說說你對AMD和Commonjs的理解
CommonJS
是服務器端模塊的規範,Node.js
採用了這個規範。CommonJS
規範加載模塊是同步的,也就是說,只有加載完成,才能執行後面的操作。AMD
規範則是非同步加載模塊,允許指定回調函數AMD
推薦的風格通過返回一個對象做爲模塊對象,CommonJS
的風格通過對module.exports
或exports
的屬性賦值來達到暴露模塊對象的目的
#17 常見web安全及防護原理
-
sql
注入原理- 就是通過把
SQL
命令插入到Web
表單遞交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令
- 就是通過把
-
總的來說有以下幾點
- 永遠不要信任用戶的輸入,要對用戶的輸入進行校驗,可以通過正則表達式,或限制長度,對單引號和雙
"-"
進行轉換等 - 永遠不要使用動態拼裝SQL,可以使用參數化的
SQL
或者直接使用存儲過程進行數據查詢存取 - 永遠不要使用管理員權限的數據庫連接,爲每個應用使用單獨的權限有限的數據庫連接
- 不要把機密信息明文存放,請加密或者
hash
掉密碼和敏感的信息
- 永遠不要信任用戶的輸入,要對用戶的輸入進行校驗,可以通過正則表達式,或限制長度,對單引號和雙
XSS原理及防範
Xss(cross-site scripting)
攻擊指的是攻擊者往Web
頁面裏插入惡意html
標籤或者javascript
代碼。比如:攻擊者在論壇中放一個看似安全的鏈接,騙取用戶點擊後,竊取cookie
中的用戶私密信息;或者攻擊者在論壇中加一個惡意表單,當用戶提交表單的時候,卻把信息傳送到攻擊者的服務器中,而不是用戶原本以爲的信任站點
XSS防範方法
- 首先代碼裏對用戶輸入的地方和變量都需要仔細檢查長度和對
”<”,”>”,”;”,”’”
等字符做過濾;其次任何內容寫到頁面之前都必須加以encode,避免不小心把html tag
弄出來。這一個層面做好,至少可以堵住超過一半的XSS 攻擊
XSS與CSRF有什麼區別嗎?
-
XSS
是獲取信息,不需要提前知道其他用戶頁面的代碼和數據包。CSRF
是代替用戶完成指定的動作,需要知道其他用戶頁面的代碼和數據包。要完成一次CSRF
攻擊,受害者必須依次完成兩個步驟 -
登錄受信任網站
A
,並在本地生成Cookie
-
在不登出
A
的情況下,訪問危險網站B
CSRF的防禦
- 服務端的
CSRF
方式方法很多樣,但總的思想都是一致的,就是在客戶端頁面增加僞隨機數 - 通過驗證碼的方法
#18 用過哪些設計模式?
-
工廠模式:
- 工廠模式解決了重複實例化的問題,但還有一個問題,那就是識別問題,因爲根本無法
- 主要好處就是可以消除對象間的耦合,通過使用工程方法而不是
new
關鍵字
-
構造函數模式
- 使用構造函數的方法,即解決了重複實例化的問題,又解決了對象識別的問題,該模式與工廠模式的不同之處在於
- 直接將屬性和方法賦值給
this
對象;
#19 爲什麼要有同源限制?
- 同源策略指的是:協議,域名,端口相同,同源策略是一種安全協議
- 舉例說明:比如一個黑客程序,他利用
Iframe
把真正的銀行登錄頁面嵌到他的頁面上,當你使用真實的用戶名,密碼登錄時,他的頁面就可以通過Javascript
讀取到你的表單中input
中的內容,這樣用戶名,密碼就輕鬆到手了。
#20 offsetWidth/offsetHeight,clientWidth/clientHeight與scrollWidth/scrollHeight的區別
offsetWidth/offsetHeight
返回值包含content + padding + border,效果與e.getBoundingClientRect()相同clientWidth/clientHeight
返回值只包含content + padding,如果有滾動條,也不包含滾動條scrollWidth/scrollHeight
返回值包含content + padding + 溢出內容的尺寸
#21 javascript有哪些方法定義對象
- 對象字面量:
var obj = {};
- 構造函數:
var obj = new Object();
- Object.create():
var obj = Object.create(Object.prototype);
#22 常見兼容性問題?
png24
位的圖片在iE6瀏覽器上出現背景,解決方案是做成PNG8
- 瀏覽器默認的
margin
和padding
不同。解決方案是加一個全局的*{margin:0;padding:0;}
來統一,,但是全局效率很低,一般是如下這樣解決:
body,ul,li,ol,dl,dt,dd,form,input,h1,h2,h3,h4,h5,h6,p{
margin:0;
padding:0;
}
IE
下,event
對象有x
,y
屬性,但是沒有pageX
,pageY
屬性Firefox
下,event
對象有pageX
,pageY
屬性,但是沒有x,y
屬性.
#23 說說你對promise的瞭解
-
依照
Promise/A+
的定義,Promise
有四種狀態:-
pending:
初始狀態, 非fulfilled
或rejected.
-
fulfilled:
成功的操作. -
rejected:
失敗的操作. -
settled: Promise
已被fulfilled
或rejected
,且不是pending
-
-
另外,
fulfilled
與rejected
一起合稱settled
-
Promise
對象用來進行延遲(deferred
) 和異步(asynchronous
) 計算
Promise 的構造函數
- 構造一個
Promise
,最基本的用法如下:
var promise = new Promise(function(resolve, reject) {
if (...) { // succeed
resolve(result);
} else { // fails
reject(Error(errMessage));
}
});
Promise
實例擁有then
方法(具有then
方法的對象,通常被稱爲thenable
)。它的使用方法如下:
promise.then(onFulfilled, onRejected)
- 接收兩個函數作爲參數,一個在
fulfilled
的時候被調用,一個在rejected
的時候被調用,接收參數就是future
,onFulfilled
對應resolve
,onRejected
對應reject
#24 你覺得jQuery源碼有哪些寫的好的地方
jquery
源碼封裝在一個匿名函數的自執行環境中,有助於防止變量的全局污染,然後通過傳入window
對象參數,可以使window
對象作爲局部變量使用,好處是當jquery
中訪問window
對象的時候,就不用將作用域鏈退回到頂層作用域了,從而可以更快的訪問window對象。同樣,傳入undefined
參數,可以縮短查找undefined
時的作用域鏈jquery
將一些原型屬性和方法封裝在了jquery.prototype
中,爲了縮短名稱,又賦值給了jquery.fn
,這是很形象的寫法- 有一些數組或對象的方法經常能使用到,
jQuery
將其保存爲局部變量以提高訪問速度 jquery
實現的鏈式調用可以節約代碼,所返回的都是同一個對象,可以提高代碼效率
#25 vue、react、angular
-
Vue.js
一個用於創建web
交互界面的庫,是一個精簡的MVVM
。它通過雙向數據綁定把View
層和Model
層連接了起來。實際的DOM
封裝和輸出格式都被抽象爲了Directives
和Filters
-
AngularJS
是一個比較完善的前端MVVM
框架,包含模板,數據雙向綁定,路由,模塊化,服務,依賴注入等所有功能,模板功能強大豐富,自帶了豐富的Angular
指令 -
react
React
僅僅是VIEW
層是facebook
公司。推出的一個用於構建UI
的一個庫,能夠實現服務器端的渲染。用了virtual dom
,所以性能很好。
#26 Node的應用場景
-
特點:
- 1、它是一個
Javascript
運行環境 - 2、依賴於
Chrome V8
引擎進行代碼解釋 - 3、事件驅動
- 4、非阻塞
I/O
- 5、單進程,單線程
- 1、它是一個
-
優點:
- 高併發(最重要的優點)
-
缺點:
- 1、只支持單核
CPU
,不能充分利用CPU
- 2、可靠性低,一旦代碼某個環節崩潰,整個系統都崩潰
- 1、只支持單核
#27 談談你對AMD、CMD的理解
-
CommonJS
是服務器端模塊的規範,Node.js
採用了這個規範。CommonJS
規範加載模塊是同步的,也就是說,只有加載完成,才能執行後面的操作。AMD
規範則是非同步加載模塊,允許指定回調函數 -
AMD
推薦的風格通過返回一個對象做爲模塊對象,CommonJS
的風格通過對module.exports
或exports
的屬性賦值來達到暴露模塊對象的目的
es6模塊 CommonJS、AMD、CMD
CommonJS
的規範中,每個JavaScript
文件就是一個獨立的模塊上下文(module context
),在這個上下文中默認創建的屬性都是私有的。也就是說,在一個文件定義的變量(還包括函數和類),都是私有的,對其他文件是不可見的。CommonJS
是同步加載模塊,在瀏覽器中會出現堵塞情況,所以不適用AMD
異步,需要定義回調define
方式es6
一個模塊就是一個獨立的文件,該文件內部的所有變量,外部無法獲取。如果你希望外部能夠讀取模塊內部的某個變量,就必須使用export
關鍵字輸出該變量es6
還可以導出類、方法,自動適用嚴格模式
#28 那些操作會造成內存泄漏
- 內存泄漏指任何對象在您不再擁有或需要它之後仍然存在
setTimeout
的第一個參數使用字符串而非函數的話,會引發內存泄漏- 閉包、控制檯日誌、循環(在兩個對象彼此引用且彼此保留時,就會產生一個循環)
#29 web開發中會話跟蹤的方法有哪些
cookie
session
url
重寫- 隱藏
input
ip
地址
#30 介紹js的基本數據類型
Undefined
、Null
、Boolean
、Number
、String
#31 介紹js有哪些內置對象
Object
是JavaScript
中所有對象的父對象- 數據封裝類對象:
Object
、Array
、Boolean
、Number
和String
- 其他對象:
Function
、Arguments
、Math
、Date
、RegExp
、Error
#32 說幾條寫JavaScript的基本規範
- 不要在同一行聲明多個變量
- 請使用
===/!==
來比較true/false
或者數值 - 使用對象字面量替代
new Array
這種形式 - 不要使用全局函數
Switch
語句必須帶有default
分支If
語句必須使用大括號for-in
循環中的變量 應該使用var
關鍵字明確限定作用域,從而避免作用域污
#33 JavaScript有幾種類型的值
- 棧:原始數據類型(
Undefined
,Null
,Boolean
,Number
、String
) - 堆:引用數據類型(對象、數組和函數)
- 兩種類型的區別是:存儲位置不同;
- 原始數據類型直接存儲在棧(
stack
)中的簡單數據段,佔據空間小、大小固定,屬於被頻繁使用數據,所以放入棧中存儲; - 引用數據類型存儲在堆(
heap
)中的對象,佔據空間大、大小不固定,如果存儲在棧中,將會影響程序運行的性能;引用數據類型在棧中存儲了指針,該指針指向堆中該實體的起始地址。當解釋器尋找引用值時,會首先檢索其 - 在棧中的地址,取得地址後從堆中獲得實體
#34 javascript創建對象的幾種方式
javascript
創建對象簡單的說,無非就是使用內置對象或各種自定義對象,當然還可以用JSON
;但寫法有很多種,也能混合使用
- 對象字面量的方式
person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
- 用
function
來模擬無參的構造函數
function Person(){}
var person=new Person();//定義一個function,如果使用new"實例化",該function可以看作是一個Class
person.name="Mark";
person.age="25";
person.work=function(){
alert(person.name+" hello...");
}
person.work();
- 用
function
來模擬參構造函數來實現(用this
關鍵字定義構造的上下文屬性)
function Pet(name,age,hobby){
this.name=name;//this作用域:當前對象
this.age=age;
this.hobby=hobby;
this.eat=function(){
alert("我叫"+this.name+",我喜歡"+this.hobby+",是個程序員");
}
}
var maidou =new Pet("麥兜",25,"coding");//實例化、創建對象
maidou.eat();//調用eat方法
- 用工廠方式來創建(內置對象)
var wcDog =new Object();
wcDog.name="旺財";
wcDog.age=3;
wcDog.work=function(){
alert("我是"+wcDog.name+",汪汪汪......");
}
wcDog.work();
- 用原型方式來創建
function Dog(){}
Dog.prototype.name="旺財";
Dog.prototype.eat=function(){
alert(this.name+"是個吃貨");
}
var wangcai =new Dog();
wangcai.eat();
- 用混合方式來創建
function Car(name,price){
this.name=name;
this.price=price;
}
Car.prototype.sell=function(){
alert("我是"+this.name+",我現在賣"+this.price+"萬元");
}
var camry =new Car("凱美瑞",27);
camry.sell();
#35 eval是做什麼的
- 它的功能是把對應的字符串解析成
JS
代碼並運行 - 應該避免使用
eval
,不安全,非常耗性能(2
次,一次解析成js
語句,一次執行) - 由
JSON
字符串轉換爲JSON對象的時候可以用eval,var obj =eval('('+ str +')')
#36 null,undefined 的區別
-
undefined
表示不存在這個值。 -
undefined
:是一個表示"無"的原始值或者說表示"缺少值",就是此處應該有一個值,但是還沒有定義。當嘗試讀取時會返回undefined
-
例如變量被聲明瞭,但沒有賦值時,就等於
undefined
-
null
表示一個對象被定義了,值爲“空值” -
null
: 是一個對象(空對象, 沒有任何屬性和方法) -
例如作爲函數的參數,表示該函數的參數不是對象;
-
在驗證
null
時,一定要使用===
,因爲==
無法分別null
和undefined
#37 ["1", "2", "3"].map(parseInt) 答案是多少
[1, NaN, NaN]
因爲parseInt
需要兩個參數(val, radix)
,其中radix
表示解析時用的基數。map
傳了3
個(element, index, array)
,對應的radix
不合法導致解析失敗。
#38 javascript 代碼中的"use strict";是什麼意思
use strict
是一種ECMAscript 5
添加的(嚴格)運行模式,這種模式使得 Javascript 在更嚴格的條件下運行,使JS
編碼更加規範化的模式,消除Javascript
語法的一些不合理、不嚴謹之處,減少一些怪異行爲
#39 JSON 的瞭解
-
JSON(JavaScript Object Notation)
是一種輕量級的數據交換格式 -
它是基於
JavaScript
的一個子集。數據格式簡單, 易於讀寫, 佔用帶寬小 -
JSON
字符串轉換爲JSON對象:
var obj =eval('('+ str +')');
var obj = str.parseJSON();
var obj = JSON.parse(str);
JSON
對象轉換爲JSON字符串:
var last=obj.toJSONString();
var last=JSON.stringify(obj);
#40 js延遲加載的方式有哪些
defer
和async
、動態創建DOM
方式(用得最多)、按需異步載入js
#41 同步和異步的區別
- 同步:瀏覽器訪問服務器請求,用戶看得到頁面刷新,重新發請求,等請求完,頁面刷新,新內容出現,用戶看到新內容,進行下一步操作
- 異步:瀏覽器訪問服務器請求,用戶正常操作,瀏覽器後端進行請求。等請求完,頁面不刷新,新內容也會出現,用戶看到新內容
#42 漸進增強和優雅降級
- 漸進增強 :針對低版本瀏覽器進行構建頁面,保證最基本的功能,然後再針對高級瀏覽器進行效果、交互等改進和追加功能達到更好的用戶體驗。
- 優雅降級 :一開始就構建完整的功能,然後再針對低版本瀏覽器進行兼容
#43 defer和async
defer
並行加載js
文件,會按照頁面上script
標籤的順序執行async
並行加載js
文件,下載完成立即執行,不會按照頁面上script
標籤的順序執行
#44 說說嚴格模式的限制
- 變量必須聲明後再使用
- 函數的參數不能有同名屬性,否則報錯
- 不能使用
with
語句 - 禁止
this
指向全局對象
#45 attribute和property的區別是什麼
attribute
是dom
元素在文檔中作爲html
標籤擁有的屬性;property
就是dom
元素在js
中作爲對象擁有的屬性。- 對於
html
的標準屬性來說,attribute
和property
是同步的,是會自動更新的 - 但是對於自定義的屬性來說,他們是不同步的
#46 談談你對ES6的理解
- 新增模板字符串(爲
JavaScript
提供了簡單的字符串插值功能) - 箭頭函數
for-of
(用來遍歷數據—例如數組中的值。)arguments
對象可被不定參數和默認參數完美代替。ES6
將promise
對象納入規範,提供了原生的Promise
對象。- 增加了
let
和const
命令,用來聲明變量。 - 增加了塊級作用域。
let
命令實際上就增加了塊級作用域。- 還有就是引入
module
模塊的概念
#47 ECMAScript6 怎麼寫class麼
- 這個語法糖可以讓有
OOP
基礎的人更快上手js
,至少是一個官方的實現了 - 但對熟悉
js
的人來說,這個東西沒啥大影響;一個Object.creat()
搞定繼承,比class
簡潔清晰的多
#48 什麼是面向對象編程及面向過程編程,它們的異同和優缺點
- 面向過程就是分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就可以了
- 面向對象是把構成問題事務分解成各個對象,建立對象的目的不是爲了完成一個步驟,而是爲了描敘某個事物在整個解決問題的步驟中的行爲
- 面向對象是以功能來劃分問題,而不是步驟
#49 面向對象編程思想
- 基本思想是使用對象,類,繼承,封裝等基本概念來進行程序設計
- 優點
- 易維護
- 採用面向對象思想設計的結構,可讀性高,由於繼承的存在,即使改變需求,那麼維護也只是在局部模塊,所以維護起來是非常方便和較低成本的
- 易擴展
- 開發工作的重用性、繼承性高,降低重複工作量。
- 縮短了開發週期
- 易維護
#50 對web標準、可用性、可訪問性的理解
- 可用性(Usability):產品是否容易上手,用戶能否完成任務,效率如何,以及這過程中用戶的主觀感受可好,是從用戶的角度來看產品的質量。可用性好意味着產品質量高,是企業的核心競爭力
- 可訪問性(Accessibility):Web內容對於殘障用戶的可閱讀和可理解性
- 可維護性(Maintainability):一般包含兩個層次,一是當系統出現問題時,快速定位並解決問題的成本,成本低則可維護性好。二是代碼是否容易被人理解,是否容易修改和增強功能。
#51 如何通過JS判斷一個數組
instanceof
方法instanceof
運算符是用來測試一個對象是否在其原型鏈原型構造函數的屬性
var arr = [];
arr instanceof Array; // true
constructor
方法constructor
屬性返回對創建此對象的數組函數的引用,就是返回對象相對應的構造函數
var arr = [];
arr.constructor == Array; //true
- 最簡單的方法
- 這種寫法,是
jQuery
正在使用的
- 這種寫法,是
Object.prototype.toString.call(value) == '[object Array]'
// 利用這個方法,可以寫一個返回數據類型的方法
var isType = function (obj) {
return Object.prototype.toString.call(obj).slice(8,-1);
}
ES5
新增方法isArray()
var a = new Array(123);
var b = new Date();
console.log(Array.isArray(a)); //true
console.log(Array.isArray(b)); //false
#52 談一談let與var的區別
let
命令不存在變量提升,如果在let
前使用,會導致報錯- 如果塊區中存在
let
和const
命令,就會形成封閉作用域 - 不允許重複聲明,因此,不能在函數內部重新聲明參數
#53 map與forEach的區別
forEach
方法,是最基本的方法,就是遍歷與循環,默認有3個傳參:分別是遍歷的數組內容item
、數組索引index
、和當前遍歷數組Array
map
方法,基本用法與forEach
一致,但是不同的,它會返回一個新的數組,所以在callback需要有return
值,如果沒有,會返回undefined
#54 談一談你理解的函數式編程
- 簡單說,"函數式編程"是一種"編程範式"(programming paradigm),也就是如何編寫程序的方法論
- 它具有以下特性:閉包和高階函數、惰性計算、遞歸、函數是"第一等公民"、只用"表達式"
#55 談一談箭頭函數與普通函數的區別?
- 函數體內的
this
對象,就是定義時所在的對象,而不是使用時所在的對象 - 不可以當作構造函數,也就是說,不可以使用
new
命令,否則會拋出一個錯誤 - 不可以使用
arguments
對象,該對象在函數體內不存在。如果要用,可以用Rest
參數代替 - 不可以使用
yield
命令,因此箭頭函數不能用作Generator
函數
#56 談一談函數中this的指向
-
this的指向在函數定義的時候是確定不了的,只有函數執行的時候才能確定this到底指向誰,實際上this的最終指向的是那個調用它的對象
-
《javascript語言精髓》中大概概括了4種調用方式:
-
方法調用模式
-
函數調用模式
-
構造器調用模式
graph LR
A-->B
- apply/call調用模式
#57 異步編程的實現方式
-
回調函數
- 優點:簡單、容易理解
- 缺點:不利於維護,代碼耦合高
-
事件監聽(採用時間驅動模式,取決於某個事件是否發生):
- 優點:容易理解,可以綁定多個事件,每個事件可以指定多個回調函數
- 缺點:事件驅動型,流程不夠清晰
-
發佈/訂閱(觀察者模式)
- 類似於事件監聽,但是可以通過‘消息中心’,瞭解現在有多少發佈者,多少訂閱者
-
Promise對象
- 優點:可以利用then方法,進行鏈式寫法;可以書寫錯誤時的回調函數;
- 缺點:編寫和理解,相對比較難
-
Generator函數
- 優點:函數體內外的數據交換、錯誤處理機制
- 缺點:流程管理不方便
-
async函數
- 優點:內置執行器、更好的語義、更廣的適用性、返回的是Promise、結構清晰。
- 缺點:錯誤處理機制
#58 對原生Javascript瞭解程度
- 數據類型、運算、對象、Function、繼承、閉包、作用域、原型鏈、事件、
RegExp
、JSON
、Ajax
、DOM
、BOM
、內存泄漏、跨域、異步裝載、模板引擎、前端MVC
、路由、模塊化、Canvas
、ECMAScript
#59 Js動畫與CSS動畫區別及相應實現
CSS3
的動畫的優點- 在性能上會稍微好一些,瀏覽器會對
CSS3
的動畫做一些優化 - 代碼相對簡單
- 在性能上會稍微好一些,瀏覽器會對
- 缺點
- 在動畫控制上不夠靈活
- 兼容性不好
JavaScript
的動畫正好彌補了這兩個缺點,控制能力很強,可以單幀的控制、變換,同時寫得好完全可以兼容IE6
,並且功能強大。對於一些複雜控制的動畫,使用javascript
會比較靠譜。而在實現一些小的交互動效的時候,就多考慮考慮CSS
吧
#60 JS 數組和對象的遍歷方式,以及幾種方式的比較
通常我們會用循環的方式來遍歷數組。但是循環是 導致js 性能問題的原因之一。一般我們會採用下幾種方式來進行數組的遍歷
-
for in
循環 -
for
循環 -
forEach
- 這裏的
forEach
回調中兩個參數分別爲value
,index
forEach
無法遍歷對象- IE不支持該方法;
Firefox
和chrome
支持 forEach
無法使用break
,continue
跳出循環,且使用return
是跳過本次循環
- 這裏的
-
這兩種方法應該非常常見且使用很頻繁。但實際上,這兩種方法都存在性能問題
-
在方式一中,
for-in
需要分析出array
的每個屬性,這個操作性能開銷很大。用在key
已知的數組上是非常不划算的。所以儘量不要用for-in
,除非你不清楚要處理哪些屬性,例如JSON
對象這樣的情況 -
在方式2中,循環每進行一次,就要檢查一下數組長度。讀取屬性(數組長度)要比讀局部變量慢,尤其是當
array
裏存放的都是DOM
元素,因爲每次讀取都會掃描一遍頁面上的選擇器相關元素,速度會大大降低
#61 gulp是什麼
gulp
是前端開發過程中一種基於流的代碼構建工具,是自動化項目的構建利器;它不僅能對網站資源進行優化,而且在開發過程中很多重複的任務能夠使用正確的工具自動完成- Gulp的核心概念:流
- 流,簡單來說就是建立在面向對象基礎上的一種抽象的處理數據的工具。在流中,定義了一些處理數據的基本操作,如讀取數據,寫入數據等,程序員是對流進行所有操作的,而不用關心流的另一頭數據的真正流向
- gulp正是通過流和代碼優於配置的策略來儘量簡化任務編寫的工作
- Gulp的特點:
- 易於使用:通過代碼優於配置的策略,gulp 讓簡單的任務簡單,複雜的任務可管理
- 構建快速 利用
Node.js
流的威力,你可以快速構建項目並減少頻繁的IO
操作 - 易於學習 通過最少的
API
,掌握gulp
毫不費力,構建工作盡在掌握:如同一系列流管道
#62 說一下Vue的雙向綁定數據的原理
vue.js
則是採用數據劫持結合發佈者-訂閱者模式的方式,通過Object.defineProperty()
來劫持各個屬性的setter
,getter
,在數據變動時發佈消息給訂閱者,觸發相應的監聽回調
#63 事件的各個階段
- 1:捕獲階段 ---> 2:目標階段 ---> 3:冒泡階段
document
--->target
目標 ---->document
- 由此,
addEventListener
的第三個參數設置爲true
和false
的區別已經非常清晰了true
表示該元素在事件的“捕獲階段”(由外往內傳遞時)響應事件false
表示該元素在事件的“冒泡階段”(由內向外傳遞時)響應事件
#64 let var const
let
- 允許你聲明一個作用域被限制在塊級中的變量、語句或者表達式
- let綁定不受變量提升的約束,這意味着let聲明不會被提升到當前
- 該變量處於從塊開始到初始化處理的“暫存死區”
var
- 聲明變量的作用域限制在其聲明位置的上下文中,而非聲明變量總是全局的
- 由於變量聲明(以及其他聲明)總是在任意代碼執行之前處理的,所以在代碼中的任意位置聲明變量總是等效於在代碼開頭聲明
const
- 聲明創建一個值的只讀引用 (即指針)
- 基本數據當值發生改變時,那麼其對應的指針也將發生改變,故造成
const
申明基本數據類型時 - 再將其值改變時,將會造成報錯, 例如
const a = 3
;a = 5
時 將會報錯 - 但是如果是複合類型時,如果只改變複合類型的其中某個
Value
項時, 將還是正常使用
#65 快速的讓一個數組亂序
var arr = [1,2,3,4,5,6,7,8,9,10];
arr.sort(function(){
return Math.random() - 0.5;
})
console.log(arr);
#66 如何渲染幾萬條數據並不卡住界面
這道題考察瞭如何在不卡住頁面的情況下渲染數據,也就是說不能一次性將幾萬條都渲染出來,而應該一次渲染部分
DOM
,那麼就可以通過requestAnimationFrame
來每16 ms
刷新一次
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<ul>控件</ul>
<script>
setTimeout(() => {
// 插入十萬條數據
const total = 100000
// 一次插入 20 條,如果覺得性能不好就減少
const once = 20
// 渲染數據總共需要幾次
const loopCount = total / once
let countOfRender = 0
let ul = document.querySelector("ul");
function add() {
// 優化性能,插入不會造成迴流
const fragment = document.createDocumentFragment();
for (let i = 0; i < once; i++) {
const li = document.createElement("li");
li.innerText = Math.floor(Math.random() * total);
fragment.appendChild(li);
}
ul.appendChild(fragment);
countOfRender += 1;
loop();
}
function loop() {
if (countOfRender < loopCount) {
window.requestAnimationFrame(add);
}
}
loop();
}, 0);
</script>
</body>
</html>
#67 希望獲取到頁面中所有的checkbox怎麼做?
不使用第三方框架
var domList = document.getElementsByTagName(‘input’)
var checkBoxList = [];
var len = domList.length; //緩存到局部變量
while (len--) { //使用while的效率會比for循環更高
if (domList[len].type == ‘checkbox’) {
checkBoxList.push(domList[len]);
}
}
#68 怎樣添加、移除、移動、複製、創建和查找節點
創建新節點
createDocumentFragment() //創建一個DOM片段
createElement() //創建一個具體的元素
createTextNode() //創建一個文本節點
添加、移除、替換、插入
appendChild() //添加
removeChild() //移除
replaceChild() //替換
insertBefore() //插入
查找
getElementsByTagName() //通過標籤名稱
getElementsByName() //通過元素的Name屬性的值
getElementById() //通過元素Id,唯一性
#69 正則表達式
正則表達式構造函數
var reg=new RegExp(“xxx”)
與正則表達字面量var reg=//
有什麼不同?匹配郵箱的正則表達式?
- 當使用
RegExp()
構造函數的時候,不僅需要轉義引號(即\
”表示”),並且還需要雙反斜槓(即\\
表示一個\
)。使用正則表達字面量的效率更高
郵箱的正則匹配:
var regMail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/;
#70 Javascript中callee和caller的作用?
caller
是返回一個對函數的引用,該函數調用了當前函數;callee
是返回正在被執行的function
函數,也就是所指定的function
對象的正文
那麼問題來了?如果一對兔子每月生一對兔子;一對新生兔,從第二個月起就開始生兔子;假定每對兔子都是一雌一雄,試問一對兔子,第n個月能繁殖成多少對兔子?(使用
callee
完成)
var result=[];
function fn(n){ //典型的斐波那契數列
if(n==1){
return 1;
}else if(n==2){
return 1;
}else{
if(result[n]){
return result[n];
}else{
//argument.callee()表示fn()
result[n]=arguments.callee(n-1)+arguments.callee(n-2);
return result[n];
}
}
}
#71 window.onload和$(document).ready
原生
JS
的window.onload
與Jquery
的$(document).ready(function(){})
有什麼不同?如何用原生JS實現Jq的ready
方法?
window.onload()
方法是必須等到頁面內包括圖片的所有元素加載完畢後才能執行。$(document).ready()
是DOM
結構繪製完畢後就執行,不必等到加載完畢
function ready(fn){
if(document.addEventListener) { //標準瀏覽器
document.addEventListener('DOMContentLoaded', function() {
//註銷事件, 避免反覆觸發
document.removeEventListener('DOMContentLoaded',arguments.callee, false);
fn(); //執行函數
}, false);
}else if(document.attachEvent) { //IE
document.attachEvent('onreadystatechange', function() {
if(document.readyState == 'complete') {
document.detachEvent('onreadystatechange', arguments.callee);
fn(); //函數執行
}
});
}
};
#72 addEventListener()和attachEvent()的區別
addEventListener()
是符合W3C規範的標準方法;attachEvent()
是IE低版本的非標準方法addEventListener()
支持事件冒泡和事件捕獲; - 而attachEvent()
只支持事件冒泡addEventListener()
的第一個參數中,事件類型不需要添加on
;attachEvent()
需要添加'on'
- 如果爲同一個元素綁定多個事件,
addEventListener()
會按照事件綁定的順序依次執行,attachEvent()
會按照事件綁定的順序倒序執行
#73 獲取頁面所有的checkbox
var resultArr= [];
var input = document.querySelectorAll('input');
for( var i = 0; i < input.length; i++ ) {
if( input[i].type == 'checkbox' ) {
resultArr.push( input[i] );
}
}
//resultArr即中獲取到了頁面中的所有checkbox
#74 數組去重方法總結
方法一、利用ES6 Set去重(ES6中最常用)
function unique (arr) {
return Array.from(new Set(arr))
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]
方法二、利用for嵌套for,然後splice去重(ES5中最常用)
function unique(arr){
for(var i=0; i<arr.length; i++){
for(var j=i+1; j<arr.length; j++){
if(arr[i]==arr[j]){ //第一個等同於第二個,splice方法刪除第二個
arr.splice(j,1);
j--;
}
}
}
return arr;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}] //NaN和{}沒有去重,兩個null直接消失了
- 雙層循環,外層循環元素,內層循環時比較值。值相同時,則刪去這個值。
- 想快速學習更多常用的
ES6
語法
方法三、利用indexOf去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array .indexOf(arr[i]) === -1) {
array .push(arr[i])
}
}
return array;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
// [1, "true", true, 15, false, undefined, null, NaN, NaN, "NaN", 0, "a", {…}, {…}] //NaN、{}沒有去重
新建一個空的結果數組,
for
循環原數組,判斷結果數組是否存在當前元素,如果有相同的值則跳過,不相同則push
進數組
方法四、利用sort()
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return;
}
arr = arr.sort()
var arrry= [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i-1]) {
arrry.push(arr[i]);
}
}
return arrry;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
// [0, 1, 15, "NaN", NaN, NaN, {…}, {…}, "a", false, null, true, "true", undefined] //NaN、{}沒有去重
利用
sort()
排序方法,然後根據排序後的結果進行遍歷及相鄰元素比對
方法五、利用對象的屬性不能相同的特點進行去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var arrry= [];
var obj = {};
for (var i = 0; i < arr.length; i++) {
if (!obj[arr[i]]) {
arrry.push(arr[i])
obj[arr[i]] = 1
} else {
obj[arr[i]]++
}
}
return arrry;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", 15, false, undefined, null, NaN, 0, "a", {…}] //兩個true直接去掉了,NaN和{}去重
方法六、利用includes
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array =[];
for(var i = 0; i < arr.length; i++) {
if( !array.includes( arr[i]) ) {//includes 檢測數組是否有某個值
array.push(arr[i]);
}
}
return array
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}] //{}沒有去重
方法七、利用hasOwnProperty
function unique(arr) {
var obj = {};
return arr.filter(function(item, index, arr){
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}] //所有的都去重了
利用
hasOwnProperty
判斷是否存在對象屬性
方法八、利用filter
function unique(arr) {
return arr.filter(function(item, index, arr) {
//當前元素,在原始數組中的第一個索引==當前索引值,否則返回當前元素
return arr.indexOf(item, 0) === index;
});
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, "NaN", 0, "a", {…}, {…}]
方法九、利用遞歸去重
function unique(arr) {
var array= arr;
var len = array.length;
array.sort(function(a,b){ //排序後更加方便去重
return a - b;
})
function loop(index){
if(index >= 1){
if(array[index] === array[index-1]){
array.splice(index,1);
}
loop(index - 1); //遞歸loop,然後數組去重
}
}
loop(len-1);
return array;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]
方法十、利用Map數據結構去重
function arrayNonRepeatfy(arr) {
let map = new Map();
let array = new Array(); // 數組用於返回結果
for (let i = 0; i < arr.length; i++) {
if(map .has(arr[i])) { // 如果有該key值
map .set(arr[i], true);
} else {
map .set(arr[i], false); // 如果沒有該key值
array .push(arr[i]);
}
}
return array ;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]
創建一個空
Map
數據結構,遍歷需要去重的數組,把數組的每一個元素作爲key
存到Map
中。由於Map
中不會出現相同的key
值,所以最終得到的就是去重後的結果
方法十一、利用reduce+includes
function unique(arr){
return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr));
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]
方法十二、[...new Set(arr)]
[...new Set(arr)]
//代碼就是這麼少----(其實,嚴格來說並不算是一種,相對於第一種方法來說只是簡化了代碼)
#75 (設計題)想實現一個對頁面某個節點的拖曳?如何做?(使用原生JS)
- 給需要拖拽的節點綁定
mousedown
,mousemove
,mouseup
事件 mousedown
事件觸發後,開始拖拽mousemove
時,需要通過event.clientX
和clientY
獲取拖拽位置,並實時更新位置mouseup
時,拖拽結束- 需要注意瀏覽器邊界的情況
#76 Javascript全局函數和全局變量
全局變量
Infinity
代表正的無窮大的數值。NaN
指示某個值是不是數字值。undefined
指示未定義的值。
全局函數
decodeURI()
解碼某個編碼的URI
。decodeURIComponent()
解碼一個編碼的URI
組件。encodeURI()
把字符串編碼爲 URI。encodeURIComponent()
把字符串編碼爲URI
組件。escape()
對字符串進行編碼。eval()
計算JavaScript
字符串,並把它作爲腳本代碼來執行。isFinite()
檢查某個值是否爲有窮大的數。isNaN()
檢查某個值是否是數字。Number()
把對象的值轉換爲數字。parseFloat()
解析一個字符串並返回一個浮點數。parseInt()
解析一個字符串並返回一個整數。String()
把對象的值轉換爲字符串。unescape()
對由escape()
編碼的字符串進行解碼
#77 使用js實現一個持續的動畫效果
定時器思路
var e = document.getElementById('e')
var flag = true;
var left = 0;
setInterval(() => {
left == 0 ? flag = true : left == 100 ? flag = false : ''
flag ? e.style.left = ` ${left++}px` : e.style.left = ` ${left--}px`
}, 1000 / 60)
requestAnimationFrame
//兼容性處理
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
var e = document.getElementById("e");
var flag = true;
var left = 0;
function render() {
left == 0 ? flag = true : left == 100 ? flag = false : '';
flag ? e.style.left = ` ${left++}px` :
e.style.left = ` ${left--}px`;
}
(function animloop() {
render();
requestAnimFrame(animloop);
})();
使用css實現一個持續的動畫效果
animation:mymove 5s infinite;
@keyframes mymove {
from {top:0px;}
to {top:200px;}
}
animation-name
規定需要綁定到選擇器的keyframe
名稱。animation-duration
規定完成動畫所花費的時間,以秒或毫秒計。animation-timing-function
規定動畫的速度曲線。animation-delay
規定在動畫開始之前的延遲。animation-iteration-count
規定動畫應該播放的次數。animation-direction
規定是否應該輪流反向播放動畫
#78 封裝一個函數,參數是定時器的時間,.then執行回調函數
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
#79 怎麼判斷兩個對象相等?
obj={
a:1,
b:2
}
obj2={
a:1,
b:2
}
obj3={
a:1,
b:'2'
}
可以轉換爲字符串來判斷
JSON.stringify(obj)==JSON.stringify(obj2);//true
JSON.stringify(obj)==JSON.stringify(obj3);//false
#80 項目做過哪些性能優化?
- 減少
HTTP
請求數 - 減少
DNS
查詢 - 使用
CDN
- 避免重定向
- 圖片懶加載
- 減少
DOM
元素數量 - 減少
DOM
操作 - 使用外部
JavaScript
和CSS
- 壓縮
JavaScript
、CSS
、字體、圖片等 - 優化
CSS Sprite
- 使用
iconfont
- 字體裁剪
- 多域名分發劃分內容到不同域名
- 儘量減少
iframe
使用 - 避免圖片
src
爲空 - 把樣式表放在
link
中 - 把
JavaScript
放在頁面底部
#81 瀏覽器緩存
瀏覽器緩存分爲強緩存和協商緩存。當客戶端請求某個資源時,獲取緩存的流程如下
- 先根據這個資源的一些
http header
判斷它是否命中強緩存,如果命中,則直接從本地獲取緩存資源,不會發請求到服務器; - 當強緩存沒有命中時,客戶端會發送請求到服務器,服務器通過另一些
request header
驗證這個資源是否命中協商緩存,稱爲http
再驗證,如果命中,服務器將請求返回,但不返回資源,而是告訴客戶端直接從緩存中獲取,客戶端收到返回後就會從緩存中獲取資源; - 強緩存和協商緩存共同之處在於,如果命中緩存,服務器都不會返回資源; 區別是,強緩存不對發送請求到服務器,但協商緩存會。
- 當協商緩存也沒命中時,服務器就會將資源發送回客戶端。
- 當
ctrl+f5
強制刷新網頁時,直接從服務器加載,跳過強緩存和協商緩存; - 當
f5
刷新網頁時,跳過強緩存,但是會檢查協商緩存;
強緩存
Expires
(該字段是http1.0
時的規範,值爲一個絕對時間的GMT
格式的時間字符串,代表緩存資源的過期時間)Cache-Control:max-age
(該字段是http1.1
的規範,強緩存利用其max-age
值來判斷緩存資源的最大生命週期,它的值單位爲秒)
協商緩存
Last-Modified
(值爲資源最後更新時間,隨服務器response返回)If-Modified-Since
(通過比較兩個時間來判斷資源在兩次請求期間是否有過修改,如果沒有修改,則命中協商緩存)ETag
(表示資源內容的唯一標識,隨服務器response
返回)If-None-Match
(服務器通過比較請求頭部的If-None-Match
與當前資源的ETag
是否一致來判斷資源是否在兩次請求之間有過修改,如果沒有修改,則命中協商緩存)
#82 WebSocket
由於
http
存在一個明顯的弊端(消息只能有客戶端推送到服務器端,而服務器端不能主動推送到客戶端),導致如果服務器如果有連續的變化,這時只能使用輪詢,而輪詢效率過低,並不適合。於是WebSocket
被髮明出來
相比與
http
具有以下有點
- 支持雙向通信,實時性更強;
- 可以發送文本,也可以二進制文件;
- 協議標識符是
ws
,加密後是wss
; - 較少的控制開銷。連接創建後,
ws
客戶端、服務端進行數據交換時,協議控制的數據包頭部較小。在不包含頭部的情況下,服務端到客戶端的包頭只有2~10
字節(取決於數據包長度),客戶端到服務端的的話,需要加上額外的4字節的掩碼。而HTTP
協議每次通信都需要攜帶完整的頭部; - 支持擴展。ws協議定義了擴展,用戶可以擴展協議,或者實現自定義的子協議。(比如支持自定義壓縮算法等)
- 無跨域問題。
實現比較簡單,服務端庫如
socket.io
、ws
,可以很好的幫助我們入門。而客戶端也只需要參照api
實現即可
#83 儘可能多的說出你對 Electron 的理解
最最重要的一點,
electron
實際上是一個套了Chrome
的nodeJS
程序
所以應該是從兩個方面說開來
Chrome
(無各種兼容性問題);NodeJS
(NodeJS
能做的它也能做)
#84 深淺拷貝
淺拷貝
Object.assign
- 或者展開運算符
深拷貝
- 可以通過
JSON.parse(JSON.stringify(object))
來解決
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE
該方法也是有侷限性的
- 會忽略
undefined
- 不能序列化函數
- 不能解決循環引用的對象
#85 防抖/節流
防抖
在滾動事件中需要做個複雜計算或者實現一個按鈕的防二次點擊操作。可以通過函數防抖動來實現
// 使用 underscore 的源碼來解釋防抖動
/**
* underscore 防抖函數,返回函數連續調用時,空閒時間必須大於或等於 wait,func 纔會執行
*
* @param {function} func 回調函數
* @param {number} wait 表示時間窗口的間隔
* @param {boolean} immediate 設置爲ture時,是否立即調用函數
* @return {function} 返回客戶調用函數
*/
_.debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result;
var later = function() {
// 現在和上一次時間戳比較
var last = _.now() - timestamp;
// 如果當前間隔時間少於設定時間且大於0就重新設置定時器
if (last < wait && last >= 0) {
timeout = setTimeout(later, wait - last);
} else {
// 否則的話就是時間到了執行回調函數
timeout = null;
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};
return function() {
context = this;
args = arguments;
// 獲得時間戳
timestamp = _.now();
// 如果定時器不存在且立即執行函數
var callNow = immediate && !timeout;
// 如果定時器不存在就創建一個
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
// 如果需要立即執行函數的話 通過 apply 執行
result = func.apply(context, args);
context = args = null;
}
return result;
};
};
整體函數實現
對於按鈕防點擊來說的實現
- 開始一個定時器,只要我定時器還在,不管你怎麼點擊都不會執行回調函數。一旦定時器結束並設置爲 null,就可以再次點擊了
- 對於延時執行函數來說的實現:每次調用防抖動函數都會判斷本次調用和之前的時間間隔,如果小於需要的時間間隔,就會重新創建一個定時器,並且定時器的延時爲設定時間減去之前的時間間隔。一旦時間到了,就會執行相應的回調函數
節流
防抖動和節流本質是不一樣的。防抖動是將多次執行變爲最後一次執行,節流是將多次執行變成每隔一段時間執行
/**
* underscore 節流函數,返回函數連續調用時,func 執行頻率限定爲 次 / wait
*
* @param {function} func 回調函數
* @param {number} wait 表示時間窗口的間隔
* @param {object} options 如果想忽略開始函數的的調用,傳入{leading: false}。
* 如果想忽略結尾函數的調用,傳入{trailing: false}
* 兩者不能共存,否則函數不能執行
* @return {function} 返回客戶調用函數
*/
_.throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
// 之前的時間戳
var previous = 0;
// 如果 options 沒傳則設爲空對象
if (!options) options = {};
// 定時器回調函數
var later = function() {
// 如果設置了 leading,就將 previous 設爲 0
// 用於下面函數的第一個 if 判斷
previous = options.leading === false ? 0 : _.now();
// 置空一是爲了防止內存泄漏,二是爲了下面的定時器判斷
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function() {
// 獲得當前時間戳
var now = _.now();
// 首次進入前者肯定爲 true
// 如果需要第一次不執行函數
// 就將上次時間戳設爲當前的
// 這樣在接下來計算 remaining 的值時會大於0
if (!previous && options.leading === false) previous = now;
// 計算剩餘時間
var remaining = wait - (now - previous);
context = this;
args = arguments;
// 如果當前調用已經大於上次調用時間 + wait
// 或者用戶手動調了時間
// 如果設置了 trailing,只會進入這個條件
// 如果沒有設置 leading,那麼第一次會進入這個條件
// 還有一點,你可能會覺得開啓了定時器那麼應該不會進入這個 if 條件了
// 其實還是會進入的,因爲定時器的延時
// 並不是準確的時間,很可能你設置了2秒
// 但是他需要2.2秒才觸發,這時候就會進入這個條件
if (remaining <= 0 || remaining > wait) {
// 如果存在定時器就清理掉否則會調用二次回調
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
// 判斷是否設置了定時器和 trailing
// 沒有的話就開啓一個定時器
// 並且不能不能同時設置 leading 和 trailing
timeout = setTimeout(later, remaining);
}
return result;
};
};
#86 談談變量提升?
當執行 JS 代碼時,會生成執行環境,只要代碼不是寫在函數中的,就是在全局執行環境中,函數中的代碼會產生函數執行環境,只此兩種執行環境
- 接下來讓我們看一個老生常談的例子,
var
b() // call b
console.log(a) // undefined
var a = 'Hello world'
function b() {
console.log('call b')
}
變量提升
這是因爲函數和變量提升的原因。通常提升的解釋是說將聲明的代碼移動到了頂部,這其實沒有什麼錯誤,便於大家理解。但是更準確的解釋應該是:在生成執行環境時,會有兩個階段。第一個階段是創建的階段,JS 解釋器會找出需要提升的變量和函數,並且給他們提前在內存中開闢好空間,函數的話會將整個函數存入內存中,變量只聲明並且賦值爲 undefined
,所以在第二個階段,也就是代碼執行階段,我們可以直接提前使用
在提升的過程中,相同的函數會覆蓋上一個函數,並且函數優先於變量提升
b() // call b second
function b() {
console.log('call b fist')
}
function b() {
console.log('call b second')
}
var b = 'Hello world'
複製代碼
var
會產生很多錯誤,所以在ES6
中引入了let
。let
不能在聲明前使用,但是這並不是常說的let
不會提升,let
提升了,在第一階段內存也已經爲他開闢好了空間,但是因爲這個聲明的特性導致了並不能在聲明前使用
#87 什麼是單線程,和異步的關係
- 單線程 - 只有一個線程,只能做一件事
- 原因 - 避免
DOM
渲染的衝突- 瀏覽器需要渲染
DOM
JS
可以修改DOM
結構JS
執行的時候,瀏覽器DOM
渲染會暫停- 兩段 JS 也不能同時執行(都修改
DOM
就衝突了) webworker
支持多線程,但是不能訪問DOM
- 瀏覽器需要渲染
- 解決方案 - 異步
#88 是否用過 jQuery 的 Deferred
#89 前端面試之hybrid
#90 前端面試之組件化
#91 前端面試之MVVM淺析
#92 實現效果,點擊容器內的圖標,圖標邊框變成border 1px solid red,點擊空白處重置
const box = document.getElementById('box');
function isIcon(target) {
return target.className.includes('icon');
}
box.onClick = function(e) {
e.stopPropagation();
const target = e.target;
if (isIcon(target)) {
target.style.border = '1px solid red';
}
}
const doc = document;
doc.onclick = function(e) {
const children = box.children;
for(let i; i < children.length; i++) {
if (isIcon(children[i])) {
children[i].style.border = 'none';
}
}
}
#93 請簡單實現雙向數據綁定mvvm
<input id="input"/>
const data = {};
const input = document.getElementById('input');
Object.defineProperty(data, 'text', {
set(value) {
input.value = value;
this.value = value;
}
});
input.onChange = function(e) {
data.text = e.target.value;
}
#94 實現Storage,使得該對象爲單例,並對localStorage
進行封裝設置值setItem(key,value)和getItem(key)
var instance = null;
class Storage {
static getInstance() {
if (!instance) {
instance = new Storage();
}
return instance;
}
setItem = (key, value) => localStorage.setItem(key, value),
getItem = key => localStorage.getItem(key)
}
#95 說說event loop
首先,
js
是單線程的,主要的任務是處理用戶的交互,而用戶的交互無非就是響應DOM
的增刪改,使用事件隊列的形式,一次事件循環只處理一個事件響應,使得腳本執行相對連續,所以有了事件隊列,用來儲存待執行的事件,那麼事件隊列的事件從哪裏被push
進來的呢。那就是另外一個線程叫事件觸發線程做的事情了,他的作用主要是在定時觸發器線程、異步HTTP
請求線程滿足特定條件下的回調函數push
到事件隊列中,等待js
引擎空閒的時候去執行,當然js引擎執行過程中有優先級之分,首先js引擎在一次事件循環中,會先執行js線程的主任務,然後會去查找是否有微任務microtask(promise)
,如果有那就優先執行微任務,如果沒有,在去查找宏任務macrotask(setTimeout、setInterval)
進行執行
#96 說說事件流
事件流分爲兩種,捕獲事件流和冒泡事件流
- 捕獲事件流從根節點開始執行,一直往子節點查找執行,直到查找執行到目標節點
- 冒泡事件流從目標節點開始執行,一直往父節點冒泡查找執行,直到查到到根節點
事件流分爲三個階段,一個是捕獲節點,一個是處於目標節點階段,一個是冒泡階段
#97 爲什麼canvas
的圖片爲什麼過有跨域問題
#98 我現在有一個canvas
,上面隨機布着一些黑塊,請實現方法,計算canvas上有多少個黑塊
https://www.jianshu.com/p/f54d265f7aa4
#99 請手寫實現一個promise
https://segmentfault.com/a/1190000013396601
#100 說說從輸入URL到看到頁面發生的全過程,越詳細越好
- 首先瀏覽器主進程接管,開了一個下載線程。
- 然後進行HTTP請求(DNS查詢、IP尋址等等),中間會有三次捂手,等待響應,開始下載響應報文。
- 將下載完的內容轉交給Renderer進程管理。
- Renderer進程開始解析css rule tree和dom tree,這兩個過程是並行的,所以一般我會把link標籤放在頁面頂部。
- 解析繪製過程中,當瀏覽器遇到link標籤或者script、img等標籤,瀏覽器會去下載這些內容,遇到時候緩存的使用緩存,不適用緩存的重新下載資源。
- css rule tree和dom tree生成完了之後,開始合成render tree,這個時候瀏覽器會進行layout,開始計算每一個節點的位置,然後進行繪製。
- 繪製結束後,關閉TCP連接,過程有四次揮手
#101 描述一下this
this
,函數執行的上下文,可以通過apply
,call
,bind
改變this
的指向。對於匿名函數或者直接調用的函數來說,this指向全局上下文(瀏覽器爲window,NodeJS爲global
),剩下的函數調用,那就是誰調用它,this
就指向誰。當然還有es6的箭頭函數,箭頭函數的指向取決於該箭頭函數聲明的位置,在哪裏聲明,this
就指向哪裏
#102 說一下瀏覽器的緩存機制
瀏覽器緩存機制有兩種,一種爲強緩存,一種爲協商緩存
- 對於強緩存,瀏覽器在第一次請求的時候,會直接下載資源,然後緩存在本地,第二次請求的時候,直接使用緩存。
- 對於協商緩存,第一次請求緩存且保存緩存標識與時間,重複請求向服務器發送緩存標識和最後緩存時間,服務端進行校驗,如果失效則使用緩存
協商緩存相關設置
Exprires
:服務端的響應頭,第一次請求的時候,告訴客戶端,該資源什麼時候會過期。Exprires
的缺陷是必須保證服務端時間和客戶端時間嚴格同步。Cache-control:max-age
:表示該資源多少時間後過期,解決了客戶端和服務端時間必須同步的問題,If-None-Match/ETag
:緩存標識,對比緩存時使用它來標識一個緩存,第一次請求的時候,服務端會返回該標識給客戶端,客戶端在第二次請求的時候會帶上該標識與服務端進行對比並返回If-None-Match
標識是否表示匹配。Last-modified/If-Modified-Since
:第一次請求的時候服務端返回Last-modified
表明請求的資源上次的修改時間,第二次請求的時候客戶端帶上請求頭If-Modified-Since
,表示資源上次的修改時間,服務端拿到這兩個字段進行對比
#103 現在要你完成一個Dialog組件,說說你設計的思路?它應該有什麼功能?
- 該組件需要提供
hook
指定渲染位置,默認渲染在body下面。 - 然後改組件可以指定外層樣式,如寬度等
- 組件外層還需要一層
mask
來遮住底層內容,點擊mask
可以執行傳進來的onCancel
函數關閉Dialog
。 - 另外組件是可控的,需要外層傳入
visible
表示是否可見。 - 然後
Dialog
可能需要自定義頭head和底部footer
,默認有頭部和底部,底部有一個確認按鈕和取消按鈕,確認按鈕會執行外部傳進來的onOk
事件,然後取消按鈕會執行外部傳進來的onCancel
事件。 - 當組件的
visible
爲true
時候,設置body
的overflow
爲hidden
,隱藏body
的滾動條,反之顯示滾動條。 - 組件高度可能大於頁面高度,組件內部需要滾動條。
- 只有組件的
visible
有變化且爲ture
時候,才重渲染組件內的所有內容
#104 caller
和callee
的區別
callee
caller
返回一個函數的引用,這個函數調用了當前的函數。
使用這個屬性要注意
- 這個屬性只有當函數在執行時纔有用
- 如果在
javascript
程序中,函數是由頂層調用的,則返回null
functionName.caller: functionName
是當前正在執行的函數。
function a() {
console.log(a.caller)
}
callee
callee
放回正在執行的函數本身的引用,它是arguments
的一個屬性
使用callee時要注意:
- 這個屬性只有在函數執行時纔有效
- 它有一個
length
屬性,可以用來獲得形參的個數,因此可以用來比較形參和實參個數是否一致,即比較arguments.length
是否等於arguments.callee.length
- 它可以用來遞歸匿名函數。
function a() {
console.log(arguments.callee)
}
#105 ajax、axios、fetch區別
jQuery ajax
$.ajax({
type: 'POST',
url: url,
data: data,
dataType: dataType,
success: function () {},
error: function () {}
});
優缺點:
- 本身是針對
MVC
的編程,不符合現在前端MVVM
的浪潮 - 基於原生的
XHR
開發,XHR
本身的架構不清晰,已經有了fetch
的替代方案 JQuery
整個項目太大,單純使用ajax
卻要引入整個JQuery
非常的不合理(採取個性化打包的方案又不能享受CDN服務)
axios
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
優缺點:
- 從瀏覽器中創建
XMLHttpRequest
- 從
node.js
發出http
請求 - 支持
Promise API
- 攔截請求和響應
- 轉換請求和響應數據
- 取消請求
- 自動轉換
JSON
數據 - 客戶端支持防止
CSRF/XSRF
fetch
try {
let response = await fetch(url);
let data = response.json();
console.log(data);
} catch(e) {
console.log("Oops, error", e);
}
優缺點:
fetcht
只對網絡請求報錯,對400
,500
都當做成功的請求,需要封裝去處理fetch
默認不會帶cookie
,需要添加配置項fetch
不支持abort
,不支持超時控制,使用setTimeout
及Promise.reject
的實現的超時控制並不能阻止請求過程繼續在後臺運行,造成了量的浪費fetch
沒有辦法原生監測請求的進度,而XHR可以
#四、jQuery
#1 你覺得jQuery或zepto源碼有哪些寫的好的地方
- jquery源碼封裝在一個匿名函數的自執行環境中,有助於防止變量的全局污染,然後通過傳入window對象參數,可以使window對象作爲局部變量使用,好處是當jquery中訪問window對象的時候,就不用將作用域鏈退回到頂層作用域了,從而可以更快的訪問window對象。同樣,傳入undefined參數,可以縮短查找undefined時的作用域鏈
(function( window, undefined ) {
//用一個函數域包起來,就是所謂的沙箱
//在這裏邊var定義的變量,屬於這個函數域內的局部變量,避免污染全局
//把當前沙箱需要的外部變量通過函數參數引入進來
//只要保證參數對內提供的接口的一致性,你還可以隨意替換傳進來的這個參數
window.jQuery = window.$ = jQuery;
})( window );
- jquery將一些原型屬性和方法封裝在了jquery.prototype中,爲了縮短名稱,又賦值給了jquery.fn,這是很形象的寫法
- 有一些數組或對象的方法經常能使用到,jQuery將其保存爲局部變量以提高訪問速度
- jquery實現的鏈式調用可以節約代碼,所返回的都是同一個對象,可以提高代碼效率
#2 jQuery 的實現原理
-
(function(window, undefined) {})(window);
-
jQuery
利用JS
函數作用域的特性,採用立即調用表達式包裹了自身,解決命名空間和變量污染問題 -
window.jQuery = window.$ = jQuery;
-
在閉包當中將 jQuery 和 $ 綁定到 window 上,從而將 jQuery 和 $ 暴露爲全局變量
#3 jQuery.fn
的 init
方法返回的 this
指的是什麼對象
- jQuery.fn 的 init 方法 返回的 this 就是 jQuery 對象
- 用戶使用 jQuery() 或 $() 即可初始化 jQuery 對象,不需要動態的去調用 init 方法
#4 jQuery.extend 與 jQuery.fn.extend 的區別
$.fn.extend()
和$.extend()
是jQuery
爲擴展插件提拱了兩個方法$.extend(object)
; // 爲jQuery添加“靜態方法”(工具方法)
$.extend({
min: function(a, b) { return a < b ? a : b; },
max: function(a, b) { return a > b ? a : b; }
});
$.min(2,3); // 2
$.max(4,5); // 5
- $.extend([true,] targetObject, object1[, object2]); // 對targt對象進行擴展
var settings = {validate:false, limit:5};
var options = {validate:true, name:"bar"};
$.extend(settings, options); // 注意:不支持第一個參數傳 false
// settings == {validate:true, limit:5, name:"bar"}
$.fn.extend(json)
; // 爲jQuery添加“成員函數”(實例方法)
$.fn.extend({
alertValue: function() {
$(this).click(function(){
alert($(this).val());
});
}
});
$("#email").alertValue();
#5 jQuery 的屬性拷貝(extend)的實現原理是什麼,如何實現深拷貝
-
淺拷貝(只複製一份原始對象的引用)
var newObject = $.extend({}, oldObject);
-
深拷貝(對原始對象屬性所引用的對象進行進行遞歸拷貝)
var newObject = $.extend(true, {}, oldObject);
#6 jQuery 的隊列是如何實現的
- jQuery 核心中有一組隊列控制方法,由
queue()/dequeue()/clearQueue()
三個方法組成。 - 主要應用於
animate()
,ajax
,其他要按時間順序執行的事件中
var func1 = function(){alert('事件1');}
var func2 = function(){alert('事件2');}
var func3 = function(){alert('事件3');}
var func4 = function(){alert('事件4');}
// 入棧隊列事件
$('#box').queue("queue1", func1); // push func1 to queue1
$('#box').queue("queue1", func2); // push func2 to queue1
// 替換隊列事件
$('#box').queue("queue1", []); // delete queue1 with empty array
$('#box').queue("queue1", [func3, func4]); // replace queue1
// 獲取隊列事件(返回一個函數數組)
$('#box').queue("queue1"); // [func3(), func4()]
// 出棧隊列事件並執行
$('#box').dequeue("queue1"); // return func3 and do func3
$('#box').dequeue("queue1"); // return func4 and do func4
// 清空整個隊列
$('#box').clearQueue("queue1"); // delete queue1 with clearQueue
#7 jQuery 中的 bind(), live(), delegate(), on()的區別
bind()
直接綁定在目標元素上live()
通過冒泡傳播事件,默認document
上,支持動態數據delegate()
更精確的小範圍使用事件代理,性能優於 liveon()
是最新的1.9
版本整合了之前的三種方式的新事件綁定機制
#8 是否知道自定義事件
- 事件即“發佈/訂閱”模式,自定義事件即“消息發佈”,事件的監聽即“訂閱訂閱”
- JS 原生支持自定義事件,示例:
document.createEvent(type); // 創建事件
event.initEvent(eventType, canBubble, prevent); // 初始化事件
target.addEventListener('dataavailable', handler, false); // 監聽事件
target.dispatchEvent(e); // 觸發事件
- jQuery 裏的
fire
函數用於調用jQuery
自定義事件列表中的事件
#9 jQuery 通過哪個方法和 Sizzle 選擇器結合的
Sizzle
選擇器採取Right To Left
的匹配模式,先搜尋所有匹配標籤,再判斷它的父節點jQuery
通過$(selecter).find(selecter);
和Sizzle
選擇器結合
#10 jQuery 中如何將數組轉化爲 JSON 字符串,然後再轉化回來
// 通過原生 JSON.stringify/JSON.parse 擴展 jQuery 實現
$.array2json = function(array) {
return JSON.stringify(array);
}
$.json2array = function(array) {
// $.parseJSON(array); // 3.0 開始,已過時
return JSON.parse(array);
}
// 調用
var json = $.array2json(['a', 'b', 'c']);
var array = $.json2array(json);
#11 jQuery 一個對象可以同時綁定多個事件,這是如何實現的
$("#btn").on("mouseover mouseout", func);
$("#btn").on({
mouseover: func1,
mouseout: func2,
click: func3
});
#12 針對 jQuery 的優化方法
- 緩存頻繁操作
DOM
對象 - 儘量使用
id
選擇器代替class
選擇器 - 總是從
#id
選擇器來繼承 - 儘量使用鏈式操作
- 使用時間委託
on
綁定事件 - 採用
jQuery
的內部函數data()
來存儲數據 - 使用最新版本的
jQuery
#13 jQuery 的 slideUp 動畫,當鼠標快速連續觸發, 動畫會滯後反覆執行,該如何處理呢
- 在觸發元素上的事件設置爲延遲處理:使用
JS
原生setTimeout
方法 - 在觸發元素的事件時預先停止所有的動畫,再執行相應的動畫事件:
$('.tab').stop().slideUp();
#14 jQuery UI 如何自定義組件
- 通過向
$.widget()
傳遞組件名稱和一個原型對象來完成 $.widget("ns.widgetName", [baseWidget], widgetPrototype);
#15 jQuery 與 jQuery UI、jQuery Mobile 區別
-
jQuery
是JS
庫,兼容各種PC瀏覽器,主要用作更方便地處理DOM
、事件、動畫、AJAX
-
jQuery UI
是建立在jQuery
庫上的一組用戶界面交互、特效、小部件及主題 -
jQuery Mobile
以jQuery
爲基礎,用於創建“移動Web應用”的框架
#16 jQuery 和 Zepto 的區別? 各自的使用場景
jQuery
主要目標是PC
的網頁中,兼容全部主流瀏覽器。在移動設備方面,單獨推出 `jQuery MobileZepto
從一開始就定位移動設備,相對更輕量級。它的
API基本兼容
jQuery`,但對PC瀏覽器兼容不理想
#17 jQuery對象的特點
- 只有
JQuery
對象才能使用JQuery
方法 JQuery
對象是一個數組對象
#五、Bootstrap
#1 什麼是Bootstrap?以及爲什麼要使用Bootstrap?
Bootstrap
是一個用於快速開發Web
應用程序和網站的前端框架。Bootstrap
是基於HTML
、CSS
、JAVASCRIPT
的
Bootstrap
具有移動設備優先、瀏覽器支持良好、容易上手、響應式設計等優點,所以Bootstrap
被廣泛應用
#2 使用Bootstrap時,要聲明的文檔類型是什麼?以及爲什麼要這樣聲明?
- 使用
Bootstrap
時,需要使用HTML5
文檔類型(Doctype
)。<!DOCTYPE html>
- 因爲
Bootstrap
使用了一些HTML5
元素和CSS
屬性,如果在Bootstrap
創建的網頁開頭不使用HTML5
的文檔類型(Doctype
),可能會面臨一些瀏覽器顯示不一致的問題,甚至可能面臨一些特定情境下的不一致,以致於代碼不能通過W3C
標準的驗證
#3 什麼是Bootstrap網格系統
Bootstrap
包含了一個響應式的、移動設備優先的、不固定的網格系統,可以隨着設備或視口大小的增加而適當地擴展到12
列。它包含了用於簡單的佈局選項的預定義類,也包含了用於生成更多語義佈局的功能強大的混合類
- 響應式網格系統隨着屏幕或視口(
viewport
)尺寸的增加,系統會自動分爲最多12
列。
#4 Bootstrap 網格系統(Grid System)的工作原理
- (1)行必須放置在
.container class
內,以便獲得適當的對齊(alignment
)和內邊距(padding
)。 - (2)使用行來創建列的水平組。
- (3)內容應該放置在列內,且唯有列可以是行的直接子元素。
- (4)預定義的網格類,比如
.row
和.col-xs-4
,可用於快速創建網格佈局。LESS
混合類可用於更多語義佈局。 - (5)列通過內邊距(
padding
)來創建列內容之間的間隙。該內邊距是通過.rows
上的外邊距(margin
)取負,表示第一列和最後一列的行偏移。 - (6)網格系統是通過指定您想要橫跨的十二個可用的列來創建的。例如,要創建三個相等的列,則使用三個
.col-xs-4
#5 對於各類尺寸的設備,Bootstrap設置的class前綴分別是什麼
- 超小設備手機(
<768px
):.col-xs-*
- 小型設備平板電腦(
>=768px
):.col-sm-*
- 中型設備臺式電腦(
>=992px
):.col-md-*
- 大型設備臺式電腦(
>=1200px
):.col-lg-*
#6 Bootstrap 網格系統列與列之間的間隙寬度是多少
間隙寬度爲
30px
(一個列的每邊分別是15px
)
#7 如果需要在一個標題的旁邊創建副標題,可以怎樣操作
在元素兩旁添加
<small>
,或者添加.small
的class
#8 用Bootstrap,如何設置文字的對齊方式?
class="text-center"
設置居中文本class="text-right"
設置向右對齊文本class="text-left"
設置向左對齊文本
#9 Bootstrap如何設置響應式表格?
增加
class="table-responsive"
#10 使用Bootstrap創建垂直表單的基本步驟?
-
(1)向父
<form>
元素添加role="form"
; -
(2)把標籤和控件放在一個帶有
class="form-group"
的<div>
中,這是獲取最佳間距所必需的; -
(3)向所有的文本元素
<input>
、<textarea>
、<select>
添加class="form-control"
#11 使用Bootstrap創建水平表單的基本步驟?
-
(1)向父
<form>
元素添加class="form-horizontal"
; -
(2)把標籤和控件放在一個帶有
class="form-group"
的<div>
中; -
(3)向標籤添加
class="control-label"
。
#12 使用Bootstrap如何創建表單控件的幫助文本?
增加
class="help-block"
的span
標籤或p
標籤。
#13 使用Bootstrap激活或禁用按鈕要如何操作?
- 激活按鈕:給按鈕增加
.active
的class
- 禁用按鈕:給按鈕增加
disabled="disabled"
的屬性
#14 Bootstrap有哪些關於的class?
- (1)
.img-rounded
爲圖片添加圓角 - (2)
.img-circle
將圖片變爲圓形 - (3)
.img-thumbnail
縮略圖功能 - (4)
.img-responsive
圖片響應式 (將很好地擴展到父元素)
#15 Bootstrap中有關元素浮動及清除浮動的class?
-
(1)
class="pull-left"
元素浮動到左邊 -
(2)
class="pull-right"
元素浮動到右邊 -
(3)
class="clearfix"
清除浮動
#16 除了屏幕閱讀器外,其他設備上隱藏元素的class?
`class="sr-only"``
#17 Bootstrap如何製作下拉菜單?
- (1)將下拉菜單包裹在
class="dropdown"
的<div>
中; - (2)在觸發下拉菜單的按鈕中添加:
class="btn dropdown-toggle" id="dropdownMenu1" data-toggle="dropdown"
- (3)在包裹下拉菜單的ul中添加:
class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1"
- (4)在下拉菜單的列表項中添加:
role="presentation"
。其中,下拉菜單的標題要添加class="dropdown-header"
,選項部分要添加tabindex="-1"
。
#18 Bootstrap如何製作按鈕組?以及水平按鈕組和垂直按鈕組的優先級?
- (1)用
class="btn-group"
的<div>
去包裹按鈕組;class="btn-group-vertical"
可設置垂直按鈕組。 - (2)
btn-group
的優先級高於btn-group-vertical
的優先級。
#19 Bootstrap如何設置按鈕的下拉菜單?
在一個
.btn-group
中放置按鈕和下拉菜單即可。
#20 Bootstrap中的輸入框組如何製作?
- (1)把前綴或者後綴元素放在一個帶有
class="input-group"
中的<div>
中 - (2)在該
<div>
內,在class="input-group-addon"
的<span>
裏面放置額外的內容; - (3)把
<span>
放在<input>
元素的前面或後面。
#21 Bootstrap中的導航都有哪些?
- (1)導航元素:有
class="nav nav-tabs"
的標籤頁導航,還有class="nav nav-pills"
的膠囊式標籤頁導航; - (2)導航欄:
class="navbar navbar-default" role="navigation"
; - (3)麪包屑導航:
class="breadcrumb"
#22 Bootstrap中設置分頁的class?
- 默認的分頁:
class="pagination"
- 默認的翻頁:
class="pager"
#23 Bootstrap中顯示標籤的class?
class="label"
#24 Bootstrap中如何製作徽章?
<span class="badge">26</span>
#25 Bootstrap中超大屏幕的作用是什麼?
設置
class="jumbotron"
可以製作超大屏幕,該組件可以增加標題的大小並增加更多的外邊距
#六、微信小程序
#1 微信小程序有幾個文件
WXSS (WeiXin Style Sheets)
是一套樣式語言,用於描述WXML
的組件樣式,js
邏輯處理,網絡請求json
小程序設置,如頁面註冊,頁面標題及tabBar
。app.json
必須要有這個文件,如果沒有這個文件,項目無法運行,因爲微信框架把這個作爲配置文件入口,整個小程序的全局配置。包括頁面註冊,網絡設置,以及小程序的window
背景色,配置導航條樣式,配置默認標題。app.js
必須要有這個文件,沒有也是會報錯!但是這個文件創建一下就行 什麼都不需要寫以後我們可以在這個文件中監聽並處理小程序的生命週期函數、聲明全局變量。app.wxss
配置全局css
#2 微信小程序怎樣跟事件傳值
給
HTML
元素添加data-*
屬性來傳遞我們需要的值,然後通過e.currentTarget.dataset
或onload
的param
參數獲取。但data -
名稱不能有大寫字母和不可以存放對象
#3 小程序的 wxss 和 css 有哪些不一樣的地方?
wxss
的圖片引入需使用外鏈地址- 沒有
Body
;樣式可直接使用import
導入
#4 小程序關聯微信公衆號如何確定用戶的唯一性
使用
wx.getUserInfo
方法withCredentials
爲true
時 可獲取encryptedData
,裏面有union_id
。後端需要進行對稱解密
#5 微信小程序與vue區別
- 生命週期不一樣,微信小程序生命週期比較簡單
- 數據綁定也不同,微信小程序數據綁定需要使用
{{}}
,vue
直接:
就可以 - 顯示與隱藏元素,
vue
中,使用v-if
和v-show
控制元素的顯示和隱藏,小程序中,使用wx-if
和hidden
控制元素的顯示和隱藏 - 事件處理不同,小程序中,全用
bindtap(bind+event)
,或者catchtap(catch+event)
綁定事件,vue:
使用v-on:event
綁定事件,或者使用@event
綁定事件 - 數據雙向綁定也不也不一樣在
vue
中,只需要再表單元素上加上v-model
,然後再綁定data
中對應的一個值,當表單元素內容發生變化時,data
中對應的值也會相應改變,這是vue
非常 nice 的一點。微信小程序必須獲取到表單元素,改變的值,然後再把值賦給一個data
中聲明的變量。
#七、webpack相關
#1 打包體積 優化思路
- 提取第三方庫或通過引用外部文件的方式引入第三方庫
- 代碼壓縮插件
UglifyJsPlugin
- 服務器啓用gzip壓縮
- 按需加載資源文件
require.ensure
- 優化
devtool
中的source-map
- 剝離
css
文件,單獨打包 - 去除不必要插件,通常就是開發環境與生產環境用同一套配置文件導致
#2 打包效率
- 開發環境採用增量構建,啓用熱更新
- 開發環境不做無意義的工作如提取
css
計算文件hash等 - 配置
devtool
- 選擇合適的
loader
- 個別
loader
開啓cache
如babel-loader
- 第三方庫採用引入方式
- 提取公共代碼
- 優化構建時的搜索路徑 指明需要構建目錄及不需要構建目錄
- 模塊化引入需要的部分
#3 Loader
編寫一個loader
loader
就是一個node
模塊,它輸出了一個函數。當某種資源需要用這個loader
轉換時,這個函數會被調用。並且,這個函數可以通過提供給它的this
上下文訪問Loader API
。reverse-txt-loader
// 定義
module.exports = function(src) {
//src是原文件內容(abcde),下面對內容進行處理,這裏是反轉
var result = src.split('').reverse().join('');
//返回JavaScript源碼,必須是String或者Buffer
return `module.exports = '${result}'`;
}
//使用
{
test: /\.txt$/,
use: [
{
'./path/reverse-txt-loader'
}
]
},
#4 說一下webpack的一些plugin,怎麼使用webpack對項目進行優化
構建優化
- 減少編譯體積
ContextReplacementPugin
、IgnorePlugin
、babel-plugin-import
、babel-plugin-transform-runtime
- 並行編譯
happypack
、thread-loader
、uglifyjsWebpackPlugin
開啓並行 - 緩存
cache-loader
、hard-source-webpack-plugin
、uglifyjsWebpackPlugin
開啓緩存、babel-loader
開啓緩存 - 預編譯
dllWebpackPlugin && DllReferencePlugin
、auto-dll-webapck-plugin
性能優化
- 減少編譯體積
Tree-shaking
、Scope Hositing
hash
緩存webpack-md5-plugin
- 拆包
splitChunksPlugin
、import()
、require.ensure
#八、編程題
#1 寫一個通用的事件偵聽器函數
// event(事件)工具集,來源:github.com/markyun
markyun.Event = {
// 視能力分別使用dom0||dom2||IE方式 來綁定事件
// 參數: 操作的元素,事件名稱 ,事件處理程序
addEvent : function(element, type, handler) {
if (element.addEventListener) {
//事件類型、需要執行的函數、是否捕捉
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent('on' + type, function() {
handler.call(element);
});
} else {
element['on' + type] = handler;
}
},
// 移除事件
removeEvent : function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.datachEvent) {
element.detachEvent('on' + type, handler);
} else {
element['on' + type] = null;
}
},
// 阻止事件 (主要是事件冒泡,因爲IE不支持事件捕獲)
stopPropagation : function(ev) {
if (ev.stopPropagation) {
ev.stopPropagation();
} else {
ev.cancelBubble = true;
}
},
// 取消事件的默認行爲
preventDefault : function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
// 獲取事件目標
getTarget : function(event) {
return event.target || event.srcElement;
}
#2 如何判斷一個對象是否爲數組
function isArray(arg) {
if (typeof arg === 'object') {
return Object.prototype.toString.call(arg) === '[object Array]';
}
return false;
}
#3 冒泡排序
- 每次比較相鄰的兩個數,如果後一個比前一個小,換位置
var arr = [3, 1, 4, 6, 5, 7, 2];
function bubbleSort(arr) {
for (var i = 0; i < arr.length - 1; i++) {
for(var j = 0; j < arr.length - i - 1; j++) {
if(arr[j + 1] < arr[j]) {
var temp;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
console.log(bubbleSort(arr));
#4 快速排序
- 採用二分法,取出中間數,數組每次和中間數比較,小的放到左邊,大的放到右邊
var arr = [3, 1, 4, 6, 5, 7, 2];
function quickSort(arr) {
if(arr.length == 0) {
return []; // 返回空數組
}
var cIndex = Math.floor(arr.length / 2);
var c = arr.splice(cIndex, 1);
var l = [];
var r = [];
for (var i = 0; i < arr.length; i++) {
if(arr[i] < c) {
l.push(arr[i]);
} else {
r.push(arr[i]);
}
}
return quickSort(l).concat(c, quickSort(r));
}
console.log(quickSort(arr));
#5 編寫一個方法 求一個字符串的字節長度
- 假設:一個英文字符佔用一個字節,一箇中文字符佔用兩個字節
function GetBytes(str){
var len = str.length;
var bytes = len;
for(var i=0; i<len; i++){
if (str.charCodeAt(i) > 255) bytes++;
}
return bytes;
}
alert(GetBytes("你好,as"));
#6 bind的用法,以及如何實現bind的函數和需要注意的點
bind
的作用與call
和apply
相同,區別是call
和apply
是立即調用函數,而bind
是返回了一個函數,需要調用的時候再執行。 一個簡單的bind
函數實現如下
Function.prototype.bind = function(ctx) {
var fn = this;
return function() {
fn.apply(ctx, arguments);
};
};
#7 實現一個函數clone
可以對
JavaScript
中的5種主要的數據類型,包括Number
、String
、Object
、Array
、Boolean
)進行值復
- 考察點1:對於基本數據類型和引用數據類型在內存中存放的是值還是指針這一區別是否清楚
- 考察點2:是否知道如何判斷一個變量是什麼類型的
- 考察點3:遞歸算法的設計
// 方法一:
Object.prototype.clone = function(){
var o = this.constructor === Array ? [] : {};
for(var e in this){
o[e] = typeof this[e] === "object" ? this[e].clone() : this[e];
}
return o;
}
//方法二:
/**
* 克隆一個對象
* @param Obj
* @returns
*/
function clone(Obj) {
var buf;
if (Obj instanceof Array) {
buf = []; //創建一個空的數組
var i = Obj.length;
while (i--) {
buf[i] = clone(Obj[i]);
}
return buf;
}else if (Obj instanceof Object){
buf = {}; //創建一個空對象
for (var k in Obj) { //爲這個對象添加新的屬性
buf[k] = clone(Obj[k]);
}
return buf;
}else{ //普通變量直接賦值
return Obj;
}
}
#8 下面這個ul,如何點擊每一列的時候alert其index
考察閉包
<ul id=”test”>
<li>這是第一條</li>
<li>這是第二條</li>
<li>這是第三條</li>
</ul>
// 方法一:
var lis=document.getElementById('2223').getElementsByTagName('li');
for(var i=0;i<3;i++)
{
lis[i].index=i;
lis[i].onclick=function(){
alert(this.index);
}
//方法二:
var lis=document.getElementById('2223').getElementsByTagName('li');
for(var i=0;i<3;i++)
{
lis[i].index=i;
lis[i].onclick=(function(a){
return function() {
alert(a);
}
})(i);
}
#9 定義一個log方法,讓它可以代理console.log的方法
可行的方法一:
function log(msg) {
console.log(msg);
}
log("hello world!") // hello world!
如果要傳入多個參數呢?顯然上面的方法不能滿足要求,所以更好的方法是:
function log(){
console.log.apply(console, arguments);
};
#10 輸出今天的日期
以
YYYY-MM-DD
的方式,比如今天是2014年9月26日,則輸出2014-09-26
var d = new Date();
// 獲取年,getFullYear()返回4位的數字
var year = d.getFullYear();
// 獲取月,月份比較特殊,0是1月,11是12月
var month = d.getMonth() + 1;
// 變成兩位
month = month < 10 ? '0' + month : month;
// 獲取日
var day = d.getDate();
day = day < 10 ? '0' + day : day;
alert(year + '-' + month + '-' + day);
#11 用js實現隨機選取10–100之間的10個數字,存入一個數組,並排序
var iArray = [];
funtion getRandom(istart, iend){
var iChoice = istart - iend +1;
return Math.floor(Math.random() * iChoice + istart;
}
for(var i=0; i<10; i++){
iArray.push(getRandom(10,100));
}
iArray.sort();
#12 寫一段JS程序提取URL中的各個GET參數
有這樣一個
URL
:http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e
,請寫一段JS程序提取URL中的各個GET參數(參數名和參數個數不確定),將其按key-value
形式返回到一個json
結構中,如{a:'1', b:'2', c:'', d:'xxx', e:undefined}
function serilizeUrl(url) {
var result = {};
url = url.split("?")[1];
var map = url.split("&");
for(var i = 0, len = map.length; i < len; i++) {
result[map[i].split("=")[0]] = map[i].split("=")[1];
}
return result;
}
#13 寫一個function
,清除字符串前後的空格
使用自帶接口
trim()
,考慮兼容性:
if (!String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+/, "").replace(/\s+$/,"");
}
}
// test the function
var str = " \t\n test string ".trim();
alert(str == "test string"); // alerts "true"
#14 實現每隔一秒鐘輸出1,2,3...數字
for(var i=0;i<10;i++){
(function(j){
setTimeout(function(){
console.log(j+1)
},j*1000)
})(i)
}
#15 實現一個函數,判斷輸入是不是迴文字符串
function run(input) {
if (typeof input !== 'string') return false;
return input.split('').reverse().join('') === input;
}
#16、數組扁平化處理
實現一個
flatten
方法,使得輸入一個數組,該數組裏面的元素也可以是數組,該方法會輸出一個扁平化的數組
function flatten(arr){
return arr.reduce(function(prev,item){
return prev.concat(Array.isArray(item)?flatten(item):item);
},[]);
}
#九、其他
#1 負載均衡
多臺服務器共同協作,不讓其中某一臺或幾臺超額工作,發揮服務器的最大作用
http
重定向負載均衡:調度者根據策略選擇服務器以302響應請求,缺點只有第一次有效果,後續操作維持在該服務器 dns負載均衡:解析域名時,訪問多個ip
服務器中的一個(可監控性較弱)- 反向代理負載均衡:訪問統一的服務器,由服務器進行調度訪問實際的某個服務器,對統一的服務器要求大,性能受到 服務器羣的數量
#2 CDN
內容分發網絡,基本思路是儘可能避開互聯網上有可能影響數據傳輸速度和穩定性的瓶頸和環節,使內容傳輸的更快、更穩定。
#3 內存泄漏
定義:程序中己動態分配的堆內存由於某種原因程序未釋放或無法釋放引發的各種問題。
js中可能出現的內存泄漏情況
結果:變慢,崩潰,延遲大等,原因:
- 全局變量
dom
清空時,還存在引用ie
中使用閉包- 定時器未清除
- 子元素存在引起的內存泄露
避免策略
- 減少不必要的全局變量,或者生命週期較長的對象,及時對無用的數據進行垃圾回收;
- 注意程序邏輯,避免“死循環”之類的 ;
- 避免創建過多的對象 原則:不用了的東西要及時歸還。
- 減少層級過多的引用
#4 babel原理
ES6、7
代碼輸入 ->babylon
進行解析 -> 得到AST
(抽象語法樹)->plugin
用babel-traverse
對AST
樹進行遍歷轉譯 ->得到新的AST
樹->用babel-generator
通過AST
樹生成ES5
代碼
#5 js自定義事件
三要素:
document.createEvent()
event.initEvent()
element.dispatchEvent()
// (en:自定義事件名稱,fn:事件處理函數,addEvent:爲DOM元素添加自定義事件,triggerEvent:觸發自定義事件)
window.onload = function(){
var demo = document.getElementById("demo");
demo.addEvent("test",function(){console.log("handler1")});
demo.addEvent("test",function(){console.log("handler2")});
demo.onclick = function(){
this.triggerEvent("test");
}
}
Element.prototype.addEvent = function(en,fn){
this.pools = this.pools || {};
if(en in this.pools){
this.pools[en].push(fn);
}else{
this.pools[en] = [];
this.pools[en].push(fn);
}
}
Element.prototype.triggerEvent = function(en){
if(en in this.pools){
var fns = this.pools[en];
for(var i=0,il=fns.length;i<il;i++){
fns[i]();
}
}else{
return;
}
}
#6 前後端路由差別
- 後端每次路由請求都是重新訪問服務器
- 前端路由實際上只是
JS
根據URL
來操作DOM
元素,根據每個頁面需要的去服務端請求數據,返回數據後和模板進行組合
#十、綜合
#1 談談你對重構的理解
- 網站重構:在不改變外部行爲的前提下,簡化結構、添加可讀性,而在網站前端保持一致的行爲。也就是說是在不改變UI的情況下,對網站進行優化, 在擴展的同時保持一致的UI
- 對於傳統的網站來說重構通常是:
- 表格(
table
)佈局改爲DIV+CSS
- 使網站前端兼容於現代瀏覽器(針對於不合規範的
CSS
、如對IE6有效的) - 對於移動平臺的優化
- 針對於
SEO
進行優化
- 表格(
#2 什麼樣的前端代碼是好的
- 高複用低耦合,這樣文件小,好維護,而且好擴展。
- 具有可用性、健壯性、可靠性、寬容性等特點
- 遵循設計模式的六大原則
#3 對前端工程師這個職位是怎麼樣理解的?它的前景會怎麼樣
- 前端是最貼近用戶的程序員,比後端、數據庫、產品經理、運營、安全都近
- 實現界面交互
- 提升用戶體驗
- 基於NodeJS,可跨平臺開發
- 前端是最貼近用戶的程序員,前端的能力就是能讓產品從 90分進化到 100 分,甚至更好,
- 與團隊成員,
UI
設計,產品經理的溝通; - 做好的頁面結構,頁面重構和用戶體驗;
#4 你覺得前端工程的價值體現在哪
- 爲簡化用戶使用提供技術支持(交互部分)
- 爲多個瀏覽器兼容性提供支持
- 爲提高用戶瀏覽速度(瀏覽器性能)提供支持
- 爲跨平臺或者其他基於webkit或其他渲染引擎的應用提供支持
- 爲展示數據提供支持(數據接口)
#5 平時如何管理你的項目
- 先期團隊必須確定好全局樣式(
globe.css
),編碼模式(utf-8
) 等; - 編寫習慣必須一致(例如都是採用繼承式的寫法,單樣式都寫成一行);
- 標註樣式編寫人,各模塊都及時標註(標註關鍵樣式調用的地方);
- 頁面進行標註(例如 頁面 模塊 開始和結束);
CSS
跟HTML
分文件夾並行存放,命名都得統一(例如style.css
);JS
分文件夾存放 命名以該JS
功能爲準的英文翻譯。- 圖片採用整合的
images.png png8
格式文件使用 - 儘量整合在一起使用方便將來的管理
#6 組件封裝
目的:爲了重用,提高開發效率和代碼質量 注意:低耦合,單一職責,可複用性,可維護性 常用操作
- 分析佈局
- 初步開發
- 化繁爲簡
- 組件抽象
#十一、一些常見問題
- 自我介紹
- 面試完你還有什麼問題要問的嗎
- 你有什麼愛好?
- 你最大的優點和缺點是什麼?
- 你爲什麼會選擇這個行業,職位?
- 你覺得你適合從事這個崗位嗎?
- 你有什麼職業規劃?
- 你對工資有什麼要求?
- 如何看待前端開發?
- 未來三到五年的規劃是怎樣的?
- 你的項目中技術難點是什麼?遇到了什麼問題?你是怎麼解決的?
- 你們部門的開發流程是怎樣的
- 你認爲哪個項目做得最好?
- 說下工作中你做過的一些性能優化處理
- 最近在看哪些前端方面的書?
- 平時是如何學習前端開發的?
- 你最有成就感的一件事
- 你爲什麼要離開前一家公司?
- 你對加班的看法
- 你希望通過這份工作獲得什麼?