FE Interview

轉載請註明出處: [https://github.com/qiu-deqing...](https://github.com/qiu-deqing...javascript

FE-interview

我的收集的前端知識點、面試題和答案,參考答案僅表明我的觀點,方便複習,目錄以下,經過文檔內搜索目錄可快速定位章節css

$HTML, HTTP,web 綜合問題

常見排序算法的時間複雜度,空間複雜度

![排序算法比較](img/sort-compare.png)html

前端須要注意哪些 SEO

  1. 合理的 title、description、keywords:搜索對着三項的權重逐個減少,title 值強調重點便可,重要關鍵詞出現不要超過 2 次,並且要靠前,不一樣頁面 title 要有所不一樣;description 把頁面內容高度歸納,長度合適,不可過度堆砌關鍵詞,不一樣頁面 description 有所不一樣;keywords 列舉出重要關鍵詞便可
  2. 語義化的 HTML 代碼,符合 W3C 規範:語義化代碼讓搜索引擎容易理解網頁
  3. 重要內容 HTML 代碼放在最前:搜索引擎抓取 HTML 順序是從上到下,有的搜索引擎對抓取長度有限制,保證重要內容必定會被抓取
  4. 重要內容不要用 js 輸出:爬蟲不會執行 js 獲取內容
  5. 少用 iframe:搜索引擎不會抓取 iframe 中的內容
  6. 非裝飾性圖片必須加 alt
  7. 提升網站速度:網站速度是搜索引擎排序的一個重要指標

web 開發中會話跟蹤的方法有哪些

  1. cookie
  2. session
  3. url 重寫
  4. 隱藏 input
  5. ip 地址

`<img>`的`title`和`alt`有什麼區別

  1. `title`是[global attributes](http://www.w3.org/TR/html-mar...,用於爲元素提供附加的 advisory information。一般當鼠標滑動到元素上的時候顯示。
  2. `alt`是`<img>`的特有屬性,是圖片內容的等價描述,用於圖片沒法加載時顯示、讀屏器閱讀圖片。可提圖片高可訪問性,除了純裝飾圖片外都必須設置有意義的值,搜索引擎會重點分析。

doctype 是什麼,舉例常見 doctype 及特色

  1. `<!doctype>`聲明必須處於 HTML 文檔的頭部,在`<html>`標籤以前,HTML5 中不區分大小寫
  2. `<!doctype>`聲明不是一個 HTML 標籤,是一個用於告訴瀏覽器當前 HTMl 版本的指令
  3. 現代瀏覽器的 html 佈局引擎經過檢查 doctype 決定使用兼容模式仍是標準模式對文檔進行渲染,一些瀏覽器有一個接近標準模型。
  4. 在 HTML4.01 中`<!doctype>`聲明指向一個 DTD,因爲 HTML4.01 基於 SGML,因此 DTD 指定了標記規則以保證瀏覽器正確渲染內容
  5. HTML5 不基於 SGML,因此不用指定 DTD

常見 dotype:前端

  1. **HTML4.01 strict**:不容許使用表現性、廢棄元素(如 font)以及 frameset。聲明:`<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">`
  2. **HTML4.01 Transitional**:容許使用表現性、廢棄元素(如 font),不容許使用 frameset。聲明:`<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">`
  3. **HTML4.01 Frameset**:容許表現性元素,廢氣元素以及 frameset。聲明:`<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">`
  4. **XHTML1.0 Strict**:不使用容許表現性、廢棄元素以及 frameset。文檔必須是結構良好的 XML 文檔。聲明:`<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">`
  5. **XHTML1.0 Transitional**:容許使用表現性、廢棄元素,不容許 frameset,文檔必須是結構良好的 XMl 文檔。聲明: `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">`
  6. **XHTML 1.0 Frameset**:容許使用表現性、廢棄元素以及 frameset,文檔必須是結構良好的 XML 文檔。聲明:`<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">`
  7. **HTML 5**: `<!doctype html>`

HTML 全局屬性(global attribute)有哪些

參考資料:[MDN: html global attribute](https://developer.mozilla.org..._attributes)或者[W3C HTML global-attributes](http://www.w3.org/TR/html-mar...java

  • `accesskey`:設置快捷鍵,提供快速訪問元素如aaa在 windows 下的 firefox 中按`alt + shift + a`可激活元素
  • `class`:爲元素設置類標識,多個類名用空格分開,CSS 和 javascript 可經過 class 屬性獲取元素
  • `contenteditable`: 指定元素內容是否可編輯
  • `contextmenu`: 自定義鼠標右鍵彈出菜單內容
  • `data-*`: 爲元素增長自定義屬性
  • `dir`: 設置元素文本方向
  • `draggable`: 設置元素是否可拖拽
  • `dropzone`: 設置元素拖放類型: copy, move, link
  • `hidden`: 表示一個元素是否與文檔。樣式上會致使元素不顯示,可是不能用這個屬性實現樣式效果
  • `id`: 元素 id,文檔內惟一
  • `lang`: 元素內容的的語言
  • `spellcheck`: 是否啓動拼寫和語法檢查
  • `style`: 行內 css 樣式
  • `tabindex`: 設置元素能夠得到焦點,經過 tab 能夠導航
  • `title`: 元素相關的建議信息
  • `translate`: 元素和子孫節點內容是否須要本地化

什麼是 web 語義化,有什麼好處

web 語義化是指經過 HTML 標記表示頁面包含的信息,包含了 HTML 標籤的語義化和 css 命名的語義化。
HTML 標籤的語義化是指:經過使用包含語義的標籤(如 h1-h6)恰當地表示文檔結構
css 命名的語義化是指:爲 html 標籤添加有意義的 class,id 補充未表達的語義,如[Microformat](http://en.wikipedia.org/wiki/... class 描述信息
爲何須要語義化:node

  • 去掉樣式後頁面呈現清晰的結構
  • 盲人使用讀屏器更好地閱讀
  • 搜索引擎更好地理解頁面,有利於收錄
  • 便團隊項目的可持續運做及維護

HTTP method

  1. 一臺服務器要與 HTTP1.1 兼容,只要爲資源實現**GET**和**HEAD**方法便可
  2. **GET**是最經常使用的方法,一般用於**請求服務器發送某個資源**。
  3. **HEAD**與 GET 相似,但**服務器在響應中值返回首部,不返回實體的主體部分**
  4. **PUT**讓服務器**用請求的主體部分來建立一個由所請求的 URL 命名的新文檔,或者,若是那個 URL 已經存在的話,就用幹這個主體替代它**
  5. **POST**起初是用來向服務器輸入數據的。實際上,一般會用它來支持 HTML 的表單。表單中填好的數據一般會被送給服務器,而後由服務器將其發送到要去的地方。
  6. **TRACE**會在目的服務器端發起一個環回診斷,最後一站的服務器會彈回一個 TRACE 響應並在響應主體中攜帶它收到的原始請求報文。TRACE 方法主要用於診斷,用於驗證請求是否如願穿過了請求/響應鏈。
  7. **OPTIONS**方法請求 web 服務器告知其支持的各類功能。能夠查詢服務器支持哪些方法或者對某些特殊資源支持哪些方法。
  8. **DELETE**請求服務器刪除請求 URL 指定的資源

從瀏覽器地址欄輸入 url 到顯示頁面的步驟(以 HTTP 爲例)

  1. 在瀏覽器地址欄輸入 URL
  2. 瀏覽器查看**緩存**,若是請求資源在緩存中而且新鮮,跳轉到轉碼步驟git

    1. 若是資源未緩存,發起新請求
    2. 若是已緩存,檢驗是否足夠新鮮,足夠新鮮直接提供給客戶端,不然與服務器進行驗證。
    3. 檢驗新鮮一般有兩個 HTTP 頭進行控制`Expires`和`Cache-Control`:github

      • HTTP1.0 提供 Expires,值爲一個絕對時間表示緩存新鮮日期
      • HTTP1.1 增長了 Cache-Control: max-age=,值爲以秒爲單位的最大新鮮時間
  3. 瀏覽器**解析 URL**獲取協議,主機,端口,path
  4. 瀏覽器**組裝一個 HTTP(GET)請求報文**
  5. 瀏覽器**獲取主機 ip 地址**,過程以下:web

    1. 瀏覽器緩存
    2. 本機緩存
    3. hosts 文件
    4. 路由器緩存
    5. ISP DNS 緩存
    6. DNS 遞歸查詢(可能存在負載均衡致使每次 IP 不同)
  6. **打開一個 socket 與目標 IP 地址,端口創建 TCP 連接**,三次握手以下:面試

    1. 客戶端發送一個 TCP 的**SYN=1,Seq=X**的包到服務器端口
    2. 服務器發回**SYN=1, ACK=X+1, Seq=Y**的響應包
    3. 客戶端發送**ACK=Y+1, Seq=Z**
  7. TCP 連接創建後**發送 HTTP 請求**
  8. 服務器接受請求並解析,將請求轉發到服務程序,如虛擬主機使用 HTTP Host 頭部判斷請求的服務程序
  9. 服務器檢查**HTTP 請求頭是否包含緩存驗證信息**若是驗證緩存新鮮,返回**304**等對應狀態碼
  10. 處理程序讀取完整請求並準備 HTTP 響應,可能須要查詢數據庫等操做
  11. 服務器將**響應報文經過 TCP 鏈接發送回瀏覽器**
  12. 瀏覽器接收 HTTP 響應,而後根據狀況選擇**關閉 TCP 鏈接或者保留重用,關閉 TCP 鏈接的四次握手以下**:

    1. 主動方發送**Fin=1, Ack=Z, Seq= X**報文
    2. 被動方發送**ACK=X+1, Seq=Z**報文
    3. 被動方發送**Fin=1, ACK=X, Seq=Y**報文
    4. 主動方發送**ACK=Y, Seq=X**報文
  13. 瀏覽器檢查響應狀態嗎:是否爲 1XX,3XX, 4XX, 5XX,這些狀況處理與 2XX 不一樣
  14. 若是資源可緩存,**進行緩存**
  15. 對響應進行**解碼**(例如 gzip 壓縮)
  16. 根據資源類型決定如何處理(假設資源爲 HTML 文檔)
  17. **解析 HTML 文檔,構件 DOM 樹,下載資源,構造 CSSOM 樹,執行 js 腳本**,這些操做沒有嚴格的前後順序,如下分別解釋
  18. **構建 DOM 樹**:

    1. **Tokenizing**:根據 HTML 規範將字符流解析爲標記
    2. **Lexing**:詞法分析將標記轉換爲對象並定義屬性和規則
    3. **DOM construction**:根據 HTML 標記關係將對象組成 DOM 樹
  19. 解析過程當中遇到圖片、樣式表、js 文件,**啓動下載**
  20. 構建**CSSOM 樹**:

    1. **Tokenizing**:字符流轉換爲標記流
    2. **Node**:根據標記建立節點
    3. **CSSOM**:節點建立 CSSOM 樹
  21. **[根據 DOM 樹和 CSSOM 樹構建渲染樹](https://developers.google.com...**:

    1. 從 DOM 樹的根節點遍歷全部**可見節點**,不可見節點包括:1)`script`,`meta`這樣自己不可見的標籤。2)被 css 隱藏的節點,如`display: none`
    2. 對每個可見節點,找到恰當的 CSSOM 規則並應用
    3. 發佈可視節點的內容和計算樣式
  22. **js 解析以下**:

    1. 瀏覽器建立 Document 對象並解析 HTML,將解析到的元素和文本節點添加到文檔中,此時**document.readystate 爲 loading**
    2. HTML 解析器遇到**沒有 async 和 defer 的 script 時**,將他們添加到文檔中,而後執行行內或外部腳本。這些腳本會同步執行,而且在腳本下載和執行時解析器會暫停。這樣就能夠用 document.write()把文本插入到輸入流中。**同步腳本常常簡單定義函數和註冊事件處理程序,他們能夠遍歷和操做 script 和他們以前的文檔內容**
    3. 當解析器遇到設置了**async**屬性的 script 時,開始下載腳本並繼續解析文檔。腳本會在它**下載完成後儘快執行**,可是**解析器不會停下來等它下載**。異步腳本**禁止使用 document.write()**,它們能夠訪問本身 script 和以前的文檔元素
    4. 當文檔完成解析,document.readState 變成 interactive
    5. 全部**defer**腳本會**按照在文檔出現的順序執行**,延遲腳本**能訪問完整文檔樹**,禁止使用 document.write()
    6. 瀏覽器**在 Document 對象上觸發 DOMContentLoaded 事件**
    7. 此時文檔徹底解析完成,瀏覽器可能還在等待如圖片等內容加載,等這些**內容完成載入而且全部異步腳本完成載入和執行**,document.readState 變爲 complete,window 觸發 load 事件
  23. **顯示頁面**(HTML 解析過程當中會逐步顯示頁面)

![HTTP訪問過程](./img/visit.svg)

HTTP request 報文結構是怎樣的

[rfc2616](http://www.w3.org/Protocols/r...

  1. 首行是**Request-Line**包括:**請求方法**,**請求 URI**,**協議版本**,**CRLF**
  2. 首行以後是若干行**請求頭**,包括**general-header**,**request-header**或者**entity-header**,每一個一行以 CRLF 結束
  3. 請求頭和消息實體之間有一個**CRLF 分隔**
  4. 根據實際請求須要可能包含一個**消息實體**
    一個請求報文例子以下:

```
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
```

HTTP response 報文結構是怎樣的

[rfc2616](http://www.w3.org/Protocols/r...

  1. 首行是狀態行包括:**HTTP 版本,狀態碼,狀態描述**,後面跟一個 CRLF
  2. 首行以後是**若干行響應頭**,包括:**通用頭部,響應頭部,實體頭部**
  3. 響應頭部和響應實體之間用**一個 CRLF 空行**分隔
  4. 最後是一個可能的**消息實體**
    響應報文例子以下:

```
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}
```

如何進行網站性能優化

[雅虎 Best Practices for Speeding Up Your Web Site](https://developer.yahoo.com/p...

  • content 方面

    1. 減小 HTTP 請求:合併文件、CSS 精靈、inline Image
    2. 減小 DNS 查詢:DNS 查詢完成以前瀏覽器不能從這個主機下載任何任何文件。方法:DNS 緩存、將資源分佈到恰當數量的主機名,平衡並行下載和 DNS 查詢
    3. 避免重定向:多餘的中間訪問
    4. 使 Ajax 可緩存
    5. 非必須組件延遲加載
    6. 將來所需組件預加載
    7. 減小 DOM 元素數量
    8. 將資源放到不一樣的域下:瀏覽器同時從一個域下載資源的數目有限,增長域能夠提升並行下載量
    9. 減小 iframe 數量
    10. 不要 404
  • Server 方面

    1. 使用 CDN
    2. 添加 Expires 或者 Cache-Control 響應頭
    3. 對組件使用 Gzip 壓縮
    4. 配置 ETag
    5. Flush Buffer Early
    6. Ajax 使用 GET 進行請求
    7. 避免空 src 的 img 標籤
  • Cookie 方面

    1. 減少 cookie 大小
    2. 引入資源的域名不要包含 cookie
  • css 方面

    1. 將樣式表放到頁面頂部
    2. 不使用 CSS 表達式
    3. 使用<link>不使用@import
    4. 不使用 IE 的 Filter
  • Javascript 方面

    1. 將腳本放到頁面底部
    2. 將 javascript 和 css 從外部引入
    3. 壓縮 javascript 和 css
    4. 刪除不須要的腳本
    5. 減小 DOM 訪問
    6. 合理設計事件監聽器
  • 圖片方面

    1. 優化圖片:根據實際顏色須要選擇色深、壓縮
    2. 優化 css 精靈
    3. 不要在 HTML 中拉伸圖片
    4. 保證 favicon.ico 小而且可緩存
  • 移動方面

    1. 保證組件小於 25k
    2. Pack Components into a Multipart Document

什麼是漸進加強

漸進加強是指在 web 設計時強調可訪問性、語義化 HTML 標籤、外部樣式表和腳本。保證全部人都能訪問頁面的基本內容和功能同時爲高級瀏覽器和高帶寬用戶提供更好的用戶體驗。核心原則以下:

  • 全部瀏覽器都必須能訪問基本內容
  • 全部瀏覽器都必須能使用基本功能
  • 全部內容都包含在語義化標籤中
  • 經過外部 CSS 提供加強的佈局
  • 經過非侵入式、外部 javascript 提供加強功能
  • end-user web browser preferences are respected

HTTP 狀態碼及其含義

參考[RFC 2616](http://www.w3.org/Protocols/r...

  • 1XX:信息狀態碼

    • **100 Continue**:客戶端應當繼續發送請求。這個臨時相應是用來通知客戶端它的部分請求已經被服務器接收,且仍未被拒絕。客戶端應當繼續發送請求的剩餘部分,或者若是請求已經完成,忽略這個響應。服務器必須在請求完成後向客戶端發送一個最終響應
    • **101 Switching Protocols**:服務器已經理解 le 客戶端的請求,並將經過 Upgrade 消息頭通知客戶端採用不一樣的協議來完成這個請求。在發送完這個響應最後的空行後,服務器將會切換到 Upgrade 消息頭中定義的那些協議。
  • 2XX:成功狀態碼

    • **200 OK**:請求成功,請求所但願的響應頭或數據體將隨此響應返回
    • **201 Created**:
    • **202 Accepted**:
    • **203 Non-Authoritative Information**:
    • **204 No Content**:
    • **205 Reset Content**:
    • **206 Partial Content**:
  • 3XX:重定向

    • **300 Multiple Choices**:
    • **301 Moved Permanently**:
    • **302 Found**:
    • **303 See Other**:
    • **304 Not Modified**:
    • **305 Use Proxy**:
    • **306 (unused)**:
    • **307 Temporary Redirect**:
  • 4XX:客戶端錯誤

    • **400 Bad Request**:
    • **401 Unauthorized**:
    • **402 Payment Required**:
    • **403 Forbidden**:
    • **404 Not Found**:
    • **405 Method Not Allowed**:
    • **406 Not Acceptable**:
    • **407 Proxy Authentication Required**:
    • **408 Request Timeout**:
    • **409 Conflict**:
    • **410 Gone**:
    • **411 Length Required**:
    • **412 Precondition Failed**:
    • **413 Request Entity Too Large**:
    • **414 Request-URI Too Long**:
    • **415 Unsupported Media Type**:
    • **416 Requested Range Not Satisfiable**:
    • **417 Expectation Failed**:
  • 5XX: 服務器錯誤

    • **500 Internal Server Error**:
    • **501 Not Implemented**:
    • **502 Bad Gateway**:
    • **503 Service Unavailable**:
    • **504 Gateway Timeout**:
    • **505 HTTP Version Not Supported**:

$CSS 部分

CSS 選擇器有哪些

  1. **\*通用選擇器**:選擇全部元素,**不參與計算優先級**,兼容性 IE6+
  2. **#X id 選擇器**:選擇 id 值爲 X 的元素,兼容性:IE6+
  3. **.X 類選擇器**: 選擇 class 包含 X 的元素,兼容性:IE6+
  4. **X Y 後代選擇器**: 選擇知足 X 選擇器的後代節點中知足 Y 選擇器的元素,兼容性:IE6+
  5. **X 元素選擇器**: 選擇標全部籤爲 X 的元素,兼容性:IE6+
  6. **:link,:visited,:focus,:hover,:active 連接狀態**: 選擇特定狀態的連接元素,順序 LoVe HAte,兼容性: IE4+
  7. **X + Y 直接兄弟選擇器**:在**X 以後第一個兄弟節點**中選擇知足 Y 選擇器的元素,兼容性: IE7+
  8. **X > Y 子選擇器**: 選擇 X 的子元素中知足 Y 選擇器的元素,兼容性: IE7+
  9. **X ~ Y 兄弟**: 選擇**X 以後全部兄弟節點**中知足 Y 選擇器的元素,兼容性: IE7+
  10. **[attr]**:選擇全部設置了 attr 屬性的元素,兼容性 IE7+
  11. **[attr=value]**:選擇屬性值恰好爲 value 的元素
  12. **[attr~=value]**:選擇屬性值爲空白符分隔,其中一個的值恰好是 value 的元素
  13. **[attr|=value]**:選擇屬性值恰好爲 value 或者 value-開頭的元素
  14. **[attr^=value]**:選擇屬性值以 value 開頭的元素
  15. **[attr$=value]**:選擇屬性值以 value 結尾的元素
  16. **[attr*=value]**:選擇屬性值中包含 value 的元素
  17. **[:checked]**:選擇單選框,複選框,下拉框中選中狀態下的元素,兼容性:IE9+
  18. **X:after, X::after**:after 僞元素,選擇元素虛擬子元素(元素的最後一個子元素),CSS3 中::表示僞元素。兼容性:after 爲 IE8+,::after 爲 IE9+
  19. **:hover**:鼠標移入狀態的元素,兼容性 a 標籤 IE4+, 全部元素 IE7+
  20. **:not(selector)**:選擇不符合 selector 的元素。**不參與計算優先級**,兼容性:IE9+
  21. **::first-letter**:僞元素,選擇塊元素第一行的第一個字母,兼容性 IE5.5+
  22. **::first-line**:僞元素,選擇塊元素的第一行,兼容性 IE5.5+
  23. **:nth-child(an + b)**:僞類,選擇前面有 an + b - 1 個兄弟節點的元素,其中 n
    >= 0, 兼容性 IE9+
  24. **:nth-last-child(an + b)**:僞類,選擇後面有 an + b - 1 個兄弟節點的元素
    其中 n >= 0,兼容性 IE9+
  25. **X:nth-of-type(an+b)**:僞類,X 爲選擇器,**解析獲得元素標籤**,選擇**前面**有 an + b - 1 個**相同標籤**兄弟節點的元素。兼容性 IE9+
  26. **X:nth-last-of-type(an+b)**:僞類,X 爲選擇器,解析獲得元素標籤,選擇**後面**有 an+b-1 個相同**標籤**兄弟節點的元素。兼容性 IE9+
  27. **X:first-child**:僞類,選擇知足 X 選擇器的元素,且這個元素是其父節點的第一個子元素。兼容性 IE7+
  28. **X:last-child**:僞類,選擇知足 X 選擇器的元素,且這個元素是其父節點的最後一個子元素。兼容性 IE9+
  29. **X:only-child**:僞類,選擇知足 X 選擇器的元素,且這個元素是其父元素的惟一子元素。兼容性 IE9+
  30. **X:only-of-type**:僞類,選擇 X 選擇的元素,**解析獲得元素標籤**,若是該元素沒有相同類型的兄弟節點時選中它。兼容性 IE9+
  31. **X:first-of-type**:僞類,選擇 X 選擇的元素,**解析獲得元素標籤**,若是該元素
    是此此類型元素的第一個兄弟。選中它。兼容性 IE9+

css sprite 是什麼,有什麼優缺點

概念:將多個小圖片拼接到一個圖片中。經過 background-position 和元素尺寸調節須要顯示的背景圖案。

優勢:

  1. 減小 HTTP 請求數,極大地提升頁面加載速度
  2. 增長圖片信息重複度,提升壓縮比,減小圖片大小
  3. 更換風格方便,只需在一張或幾張圖片上修改顏色或樣式便可實現

缺點:

  1. 圖片合併麻煩
  2. 維護麻煩,修改一個圖片可能須要從新佈局整個圖片,樣式

`display: none;`與`visibility: hidden;`的區別

聯繫:它們都能讓元素不可見

區別:

  1. display:none;會讓元素徹底從渲染樹中消失,渲染的時候不佔據任何空間;visibility: hidden;不會讓元素從渲染樹消失,渲染時元素繼續佔據空間,只是內容不可見。
  2. display: none;是非繼承屬性,子孫節點消失因爲元素從渲染樹消失形成,經過修改子孫節點屬性沒法顯示;visibility: hidden;是繼承屬性,子孫節點因爲繼承了 hidden 而消失,經過設置 visibility: visible,可讓子孫節點顯示。
  3. 修改常規流中元素的 display 一般會形成文檔重排。修改 visibility 屬性只會形成本元素的重繪。
  4. 讀屏器不會讀取 display: none;元素內容;會讀取 visibility: hidden;元素內容。

css hack 原理及經常使用 hack

原理:利用**不一樣瀏覽器對 CSS 的支持和解析結果不同**編寫針對特定瀏覽器樣式。常見的 hack 有 1)屬性 hack。2)選擇器 hack。3)IE 條件註釋

  • IE 條件註釋:適用於[IE5, IE9]常見格式以下

```js
<!--[if IE 6]>
Special instructions for IE 6 here
<![endif]-->
```

  • 選擇器 hack:不一樣瀏覽器對選擇器的支持不同

```css
/***** Selector Hacks ******/

/* IE6 and below */
* html #uno {
color: red;
}

/* IE7 */
*:first-child + html #dos {
color: red;
}

/* IE7, FF, Saf, Opera */
html > body #tres {
color: red;
}

/* IE8, FF, Saf, Opera (Everything but IE 6,7) */
html>/**/body #cuatro {
color: red;
}

/* Opera 9.27 and below, safari 2 */
html:first-child #cinco {
color: red;
}

/* Safari 2-3 */
html[xmlns*=''] body:last-child #seis {
color: red;
}

/* safari 3+, chrome 1+, opera9+, ff 3.5+ */
body:nth-of-type(1) #siete {
color: red;
}

/* safari 3+, chrome 1+, opera9+, ff 3.5+ */
body:first-of-type #ocho {
color: red;
}

/* saf3+, chrome1+ */
@media screen and (-webkit-min-device-pixel-ratio: 0) {
#diez {

color: red;

}
}

/* iPhone / mobile webkit */
@media screen and (max-device-width: 480px) {
#veintiseis {

color: red;

}
}

/* Safari 2 - 3.1 */
html[xmlns*='']:root #trece {
color: red;
}

/* Safari 2 - 3.1, Opera 9.25 */
*|html[xmlns*=''] #catorce {
color: red;
}

/* Everything but IE6-8 */
:root * > #quince {
color: red;
}

/* IE7 */
* + html #dieciocho {
color: red;
}

/* Firefox only. 1+ */

veinticuatro,

x:-moz-any-link {
color: red;
}

/* Firefox 3.0+ */

veinticinco,

x:-moz-any-link,
x:default {
color: red;
}
```

  • 屬性 hack:不一樣瀏覽器解析 bug 或方法

```
/* IE6 */

once { _color: blue }

/* IE6, IE7 */

doce { *color: blue; /* or #color: blue */ }

/* Everything but IE6 */

diecisiete { color/**/: blue }

/* IE6, IE7, IE8 */

diecinueve { color: blue\9; }

/* IE7, IE8 */

veinte { color/*\**/: blue\9; }

/* IE6, IE7 -- acts as an !important */

veintesiete { color: blue !ie; } /* string after ! can be anything */

```

specified value,computed value,used value 計算方法

  • specified value: 計算方法以下:

    1. 若是樣式表設置了一個值,使用這個值
    2. 若是沒有設值,且這個屬性是繼承屬性,從父元素繼承
    3. 若是沒有設值,而且不是繼承屬性,則使用 css 規範指定的初始值
  • computed value: 以 specified value 根據規範定義的行爲進行計算,一般將相對值計算爲絕對值,例如 em 根據 font-size 進行計算。一些使用百分數而且須要佈局來決定最終值的屬性,如 width,margin。百分數就直接做爲 computed value。line-height 的無單位值也直接做爲 computed value。這些值將在計算 used value 時獲得絕對值。**computed value 的主要做用是用於繼承**
  • used value:屬性計算後的最終值,對於大多數屬性能夠經過 window.getComputedStyle 得到,尺寸值單位爲像素。如下屬性依賴於佈局,

    • background-position
    • bottom, left, right, top
    • height, width
    • margin-bottom, margin-left, margin-right, margin-top
    • min-height, min-width
    • padding-bottom, padding-left, padding-right, padding-top
    • text-indent

`link`與`@import`的區別

  1. `link`是 HTML 方式, `@import`是 CSS 方式
  2. `link`最大限度支持並行下載,`@import`過多嵌套致使串行下載,出現[FOUC](http://www.bluerobot.com/web/...
  3. `link`能夠經過`rel="alternate stylesheet"`指定候選樣式
  4. 瀏覽器對`link`支持早於`@import`,可使用`@import`對老瀏覽器隱藏樣式
  5. `@import`必須在樣式規則以前,能夠在 css 文件中引用其餘文件
  6. 整體來講:**[link 優於@import](http://www.stevesouders.com/b...**

`display: block;`和`display: inline;`的區別

`block`元素特色:

1.處於常規流中時,若是`width`沒有設置,會自動填充滿父容器 2.能夠應用`margin/padding` 3.在沒有設置高度的狀況下會擴展高度以包含常規流中的子元素 4.處於常規流中時佈局時在先後元素位置之間(獨佔一個水平空間) 5.忽略`vertical-align`

`inline`元素特色

1.水平方向上根據`direction`依次佈局 2.不會在元素先後進行換行 3.受`white-space`控制 4.`margin/padding`在豎直方向上無效,水平方向上有效 5.`width/height`屬性對非替換行內元素無效,寬度由元素內容決定 6.非替換行內元素的行框高由`line-height`肯定,替換行內元素的行框高由`height`,`margin`,`padding`,`border`決定 6.浮動或絕對定位時會轉換爲`block` 7.`vertical-align`屬性生效

PNG,GIF,JPG 的區別及如何選

參考資料: [選擇正確的圖片格式](http://www.yuiblog.com/blog/2...
**GIF**:

  1. 8 位像素,256 色
  2. 無損壓縮
  3. 支持簡單動畫
  4. 支持 boolean 透明
  5. 適合簡單動畫

**JPEG**:

  1. 顏色限於 256
  2. 有損壓縮
  3. 可控制壓縮質量
  4. 不支持透明
  5. 適合照片

**PNG**:

  1. 有 PNG8 和 truecolor PNG
  2. PNG8 相似 GIF 顏色上限爲 256,文件小,支持 alpha 透明度,無動畫
  3. 適合圖標、背景、按鈕

CSS 有哪些繼承屬性

IE6 瀏覽器有哪些常見的 bug,缺陷或者與標準不一致的地方,如何解決

  • IE6 不支持 min-height,解決辦法使用 css hack:

```
.target {

min-height: 100px;
height: auto !important;
height: 100px;   // IE6下內容高度超過會自動擴展高度

}
```

  • `ol`內`li`的序號全爲 1,不遞增。解決方法:爲 li 設置樣式`display: list-item;`
  • 未定位父元素`overflow: auto;`,包含`position: relative;`子元素,子元素高於父元素時會溢出。解決辦法:1)子元素去掉`position: relative;`; 2)不能爲子元素去掉定位時,父元素`position: relative;`

```
<style type="text/css">
.outer {

width: 215px;
height: 100px;
border: 1px solid red;
overflow: auto;
position: relative;  /\* 修復bug \*/

}
.inner {

width: 100px;
height: 200px;
background-color: purple;
position: relative;

}
</style>

<div class="outer">

<div class="inner"></div>

</div>
```

  • IE6 只支持`a`標籤的`:hover`僞類,解決方法:使用 js 爲元素監聽 mouseenter,mouseleave 事件,添加類實現效果:

```
<style type="text/css">
.p:hover,
.hover {

background: purple;

}
</style>

<p class="p" id="target">aaaa bbbbb<span>DDDDDDDDDDDd</span> aaaa lkjlkjdf j</p>

<script type="text/javascript">
function addClass(elem, cls) {

if (elem.className) {
    elem.className += ' ' + cls;
} else {
    elem.className = cls;
}

}
function removeClass(elem, cls) {

var className = ' ' + elem.className + ' ';
var reg = new RegExp(' +' + cls + ' +', 'g');
elem.className = className.replace(reg, ' ').replace(/^ +| +$/, '');

}

var target = document.getElementById('target');
if (target.attachEvent) {

target.attachEvent('onmouseenter', function () {
    addClass(target, 'hover');
});
target.attachEvent('onmouseleave', function () {
    removeClass(target, 'hover');
})

}
</script>
```

  • IE5-8 不支持`opacity`,解決辦法:

```
.opacity {

opacity: 0.4
filter: alpha(opacity=60); /\* for IE5-7 \*/
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; /\* for IE 8\*/

}
```

  • IE6 在設置`height`小於`font-size`時高度值爲`font-size`,解決辦法:`font-size: 0;`
  • IE6 不支持 PNG 透明背景,解決辦法: **IE6 下使用 gif 圖片**
  • IE6-7 不支持`display: inline-block`解決辦法:設置 inline 並觸發 hasLayout

```

display: inline-block;
\*display: inline;
\*zoom: 1;

```

  • IE6 下浮動元素在浮動方向上與父元素邊界接觸元素的外邊距會加倍。解決辦法:
    1)使用 padding 控制間距。
    2)浮動元素`display: inline;`這樣解決問題且無任何反作用:css 標準規定浮動元素 display:inline 會自動調整爲 block
  • 經過爲塊級元素設置寬度和左右 margin 爲 auto 時,IE6 不能實現水平居中,解決方法:爲父元素設置`text-align: center;`

容器包含若干浮動元素時如何清理(包含)浮動

  1. 容器元素閉合標籤前添加額外元素並設置`clear: both`
  2. 父元素觸發塊級格式化上下文(見塊級可視化上下文部分)
  3. 設置容器元素僞元素進行清理[推薦的清理浮動方法](http://nicolasgallagher.com/m...

```
/**
* 在標準瀏覽器下使用
* 1 content內容爲空格用於修復opera下文檔中出現
* contenteditable屬性時在清理浮動元素上下的空白
* 2 使用display使用table而不是block:能夠防止容器和
* 子元素top-margin摺疊,這樣能使清理效果與BFC,IE6/7
* zoom: 1;一致
**/

.clearfix:before,
.clearfix:after {

content: " "; /\* 1 \*/
display: table; /\* 2 \*/

}

.clearfix:after {

clear: both;

}

/**
* IE 6/7下使用
* 經過觸發hasLayout實現包含浮動
**/
.clearfix {

\*zoom: 1;

}
```

什麼是 FOUC?如何避免

Flash Of Unstyled Content:用戶定義樣式表加載以前瀏覽器使用默認樣式顯示文檔,用戶樣式加載渲染以後再重新顯示文檔,形成頁面閃爍。**解決方法**:把樣式表放到文檔的`head`

如何建立塊級格式化上下文(block formatting context),BFC 有什麼用

建立規則:

  1. 根元素
  2. 浮動元素(`float`不是`none`)
  3. 絕對定位元素(`position`取值爲`absolute`或`fixed`)
  4. `display`取值爲`inline-block`,`table-cell`, `table-caption`,`flex`, `inline-flex`之一的元素
  5. `overflow`不是`visible`的元素

做用:

  1. 能夠包含浮動元素
  2. 不被浮動元素覆蓋
  3. 阻止父子元素的 margin 摺疊

display,float,position 的關係

  1. 若是`display`爲 none,那麼 position 和 float 都不起做用,這種狀況下元素不產生框
  2. 不然,若是 position 值爲 absolute 或者 fixed,框就是絕對定位的,float 的計算值爲 none,display 根據下面的表格進行調整。
  3. 不然,若是 float 不是 none,框是浮動的,display 根據下表進行調整
  4. 不然,若是元素是根元素,display 根據下表進行調整
  5. 其餘狀況下 display 的值爲指定值
    總結起來:**絕對定位、浮動、根元素都須要調整`display`**
    ![display轉換規則](img/display-adjust.png)

外邊距摺疊(collapsing margins)

毗鄰的兩個或多個`margin`會合併成一個 margin,叫作外邊距摺疊。規則以下:

  1. 兩個或多個毗鄰的普通流中的塊元素垂直方向上的 margin 會摺疊
  2. 浮動元素/inline-block 元素/絕對定位元素的 margin 不會和垂直方向上的其餘元素的 margin 摺疊
  3. 建立了塊級格式化上下文的元素,不會和它的子元素髮生 margin 摺疊
  4. 元素自身的 margin-bottom 和 margin-top 相鄰時也會摺疊

如何肯定一個元素的包含塊(containing block)

  1. 根元素的包含塊叫作初始包含塊,在連續媒體中他的尺寸與 viewport 相同而且 anchored at the canvas origin;對於 paged media,它的尺寸等於 page area。初始包含塊的 direction 屬性與根元素相同。
  2. `position`爲`relative`或者`static`的元素,它的包含塊由最近的塊級(`display`爲`block`,`list-item`, `table`)祖先元素的**內容框**組成
  3. 若是元素`position`爲`fixed`。對於連續媒體,它的包含塊爲 viewport;對於 paged media,包含塊爲 page area
  4. 若是元素`position`爲`absolute`,它的包含塊由祖先元素中最近一個`position`爲`relative`,`absolute`或者`fixed`的元素產生,規則以下:

    • 若是祖先元素爲行內元素,the containing block is the bounding box around the **padding boxes** of the first and the last inline boxes generated for that element.
    • 其餘狀況下包含塊由祖先節點的**padding edge**組成

若是找不到定位的祖先元素,包含塊爲**初始包含塊**

stacking context,佈局規則

z 軸上的默認層疊順序以下(從下到上):

  1. 根元素的邊界和背景
  2. 常規流中的元素按照 html 中順序
  3. 浮動塊
  4. positioned 元素按照 html 中出現順序

如何建立 stacking context:

  1. 根元素
  2. z-index 不爲 auto 的定位元素
  3. a flex item with a z-index value other than 'auto'
  4. opacity 小於 1 的元素
  5. 在移動端 webkit 和 chrome22+,z-index 爲 auto,position: fixed 也將建立新的 stacking context

如何水平居中一個元素

  • 若是須要居中的元素爲**常規流中 inline 元素**,爲父元素設置`text-align: center;`便可實現
  • 若是須要居中的元素爲**常規流中 block 元素**,1)爲元素設置寬度,2)設置左右 margin 爲 auto。3)IE6 下需在父元素上設置`text-align: center;`,再給子元素恢復須要的值

```
<body>

<div class="content">
aaaaaa aaaaaa a a a a a a a a
</div>

</body>

<style>

body {
    background: #DDD;
    text-align: center; /\* 3 \*/
}
.content {
    width: 500px;      /\* 1 \*/
    text-align: left;  /\* 3 \*/
    margin: 0 auto;    /\* 2 \*/

    background: purple;
}

</style>
```

  • 若是須要居中的元素爲**浮動元素**,1)爲元素設置寬度,2)`position: relative;`,3)浮動方向偏移量(left 或者 right)設置爲 50%,4)浮動方向上的 margin 設置爲元素寬度一半乘以-1

```
<body>

<div class="content">
aaaaaa aaaaaa a a a a a a a a
</div>

</body>

<style>

body {
    background: #DDD;
}
.content {
    width: 500px;         /\* 1 \*/
    float: left;

    position: relative;   /\* 2 \*/
    left: 50%;            /\* 3 \*/
    margin-left: -250px;  /\* 4 \*/

    background-color: purple;
}

</style>
```

  • 若是須要居中的元素爲**絕對定位元素**,1)爲元素設置寬度,2)偏移量設置爲 50%,3)偏移方向外邊距設置爲元素寬度一半乘以-1

```
<body>

<div class="content">
aaaaaa aaaaaa a a a a a a a a
</div>

</body>

<style>

body {
    background: #DDD;
    position: relative;
}
.content {
    width: 800px;

    position: absolute;
    left: 50%;
    margin-left: -400px;

    background-color: purple;
}

</style>
```

  • 若是須要居中的元素爲**絕對定位元素**,1)爲元素設置寬度,2)設置左右偏移量都爲 0,3)設置左右外邊距都爲 auto

```
<body>

<div class="content">
aaaaaa aaaaaa a a a a a a a a
</div>

</body>

<style>

body {
    background: #DDD;
    position: relative;
}
.content {
    width: 800px;

    position: absolute;
    margin: 0 auto;
    left: 0;
    right: 0;

    background-color: purple;
}

</style>
```

如何豎直居中一個元素

參考資料:[6 Methods For Vertical Centering With CSS](http://www.vanseodesign.com/c...。 [盤點 8 種 CSS 實現垂直居中](http://blog.csdn.net/freshlov...

  • 須要居中元素爲**單行文本**,爲包含文本的元素設置大於`font-size`的`line-height`:

```
<p class="text">center text</p>

<style>
.text {

line-height: 200px;

}
</style>
```

$javascript 概念部分

DOM 元素 e 的 e.getAttribute(propName)和 e.propName 有什麼區別和聯繫

  • e.getAttribute(),是標準 DOM 操做文檔元素屬性的方法,具備通用性可在任意文檔上使用,返回元素在源文件中**設置的屬性**
  • e.propName 一般是在 HTML 文檔中訪問特定元素的**特性**,瀏覽器解析元素後生成對應對象(如 a 標籤生成 HTMLAnchorElement),這些對象的特性會根據特定規則結合屬性設置獲得,對於沒有對應特性的屬性,只能使用 getAttribute 進行訪問
  • e.getAttribute()返回值是源文件中設置的值,類型是字符串或者 null(有的實現返回"")
  • e.propName 返回值多是字符串、布爾值、對象、undefined 等
  • 大部分 attribute 與 property 是一一對應關係,修改其中一個會影響另外一個,如 id,title 等屬性
  • 一些布爾屬性`<input hidden/>`的檢測設置須要 hasAttribute 和 removeAttribute 來完成,或者設置對應 property
  • 像`link`中 href 屬性,轉換成 property 的時候須要經過轉換獲得完整 URL
  • 一些 attribute 和 property 不是一一對應如:form 控件中`<input value="hello"/>`對應的是 defaultValue,修改或設置 value property 修改的是控件當前值,setAttribute 修改 value 屬性不會改變 value property

offsetWidth/offsetHeight,clientWidth/clientHeight 與 scrollWidth/scrollHeight 的區別

  • offsetWidth/offsetHeight 返回值包含**content + padding + border**,效果與 e.getBoundingClientRect()相同
  • clientWidth/clientHeight 返回值只包含**content + padding**,若是有滾動條,也**不包含滾動條**
  • scrollWidth/scrollHeight 返回值包含**content + padding + 溢出內容的尺寸**

[Measuring Element Dimension and Location with CSSOM in Windows Internet Explorer 9](http://msdn.microsoft.com/en-...)

![元素尺寸](img/element-size.png)

XMLHttpRequest 通用屬性和方法

  1. `readyState`:表示請求狀態的整數,取值:
  • UNSENT(0):對象已建立
  • OPENED(1):open()成功調用,在這個狀態下,能夠爲 xhr 設置請求頭,或者使用 send()發送請求
  • HEADERS_RECEIVED(2):全部重定向已經自動完成訪問,而且最終響應的 HTTP 頭已經收到
  • LOADING(3):響應體正在接收
  • DONE(4):數據傳輸完成或者傳輸產生錯誤
  1. `onreadystatechange`:readyState 改變時調用的函數
  2. `status`:服務器返回的 HTTP 狀態碼(如,200, 404)
  3. `statusText`:服務器返回的 HTTP 狀態信息(如,OK,No Content)
  4. `responseText`:做爲字符串形式的來自服務器的完整響應
  5. `responseXML`: Document 對象,表示服務器的響應解析成的 XML 文檔
  6. `abort()`:取消異步 HTTP 請求
  7. `getAllResponseHeaders()`: 返回一個字符串,包含響應中服務器發送的所有 HTTP 報頭。每一個報頭都是一個用冒號分隔開的名/值對,而且使用一個回車/換行來分隔報頭行
  8. `getResponseHeader(headerName)`:返回 headName 對應的報頭值
  9. `open(method, url, asynchronous [, user, password])`:初始化準備發送到服務器上的請求。method 是 HTTP 方法,不區分大小寫;url 是請求發送的相對或絕對 URL;asynchronous 表示請求是否異步;user 和 password 提供身份驗證
  10. `setRequestHeader(name, value)`:設置 HTTP 報頭
  11. `send(body)`:對服務器請求進行初始化。參數 body 包含請求的主體部分,對於 POST 請求爲鍵值對字符串;對於 GET 請求,爲 null

focus/blur 與 focusin/focusout 的區別與聯繫

  1. focus/blur 不冒泡,focusin/focusout 冒泡
  2. focus/blur 兼容性好,focusin/focusout 在除 FireFox 外的瀏覽器下都保持良好兼容性,如需使用事件託管,可考慮在 FireFox 下使用事件捕獲 elem.addEventListener('focus', handler, true)
  3. 可得到焦點的元素:

    1. window
    2. 連接被點擊或鍵盤操做
    3. 表單空間被點擊或鍵盤操做
    4. 設置`tabindex`屬性的元素被點擊或鍵盤操做

mouseover/mouseout 與 mouseenter/mouseleave 的區別與聯繫

  1. mouseover/mouseout 是標準事件,**全部瀏覽器都支持**;mouseenter/mouseleave 是 IE5.5 引入的特有事件後來被 DOM3 標準採納,現代標準瀏覽器也支持
  2. mouseover/mouseout 是**冒泡**事件;mouseenter/mouseleave**不冒泡**。須要爲**多個元素監聽鼠標移入/出事件時,推薦 mouseover/mouseout 託管,提升性能**
  3. 標準事件模型中 event.target 表示發生移入/出的元素,**vent.relatedTarget**對應移出/如元素;在老 IE 中 event.srcElement 表示發生移入/出的元素,**event.toElement**表示移出的目標元素,**event.fromElement**表示移入時的來源元素

例子:鼠標從 div#target 元素移出時進行處理,判斷邏輯以下:

<div id="target"><span>test</span></div>

<script type="text/javascript">
var target = document.getElementById('target');
if (target.addEventListener) {
  target.addEventListener('mouseout', mouseoutHandler, false);
} else if (target.attachEvent) {
  target.attachEvent('onmouseout', mouseoutHandler);
}

function mouseoutHandler(e) {
  e = e || window.event;
  var target = e.target || e.srcElement;

  // 判斷移出鼠標的元素是否爲目標元素
  if (target.id !== 'target') {
    return;
  }

  // 判斷鼠標是移出元素仍是移到子元素
  var relatedTarget = event.relatedTarget || e.toElement;
  while (relatedTarget !== target
    && relatedTarget.nodeName.toUpperCase() !== 'BODY') {
    relatedTarget = relatedTarget.parentNode;
  }

  // 若是相等,說明鼠標在元素內部移動
  if (relatedTarget === target) {
    return;
  }

  // 執行須要操做
  //alert('鼠標移出');

}
</script>

sessionStorage,localStorage,cookie 區別

  1. 都會在瀏覽器端保存,有大小限制,同源限制
  2. cookie 會在請求時發送到服務器,做爲會話標識,服務器可修改 cookie;web storage 不會發送到服務器
  3. cookie 有 path 概念,子路徑能夠訪問父路徑 cookie,父路徑不能訪問子路徑 cookie
  4. 有效期:cookie 在設置的有效期內有效,默認爲瀏覽器關閉;sessionStorage 在窗口關閉前有效,localStorage 長期有效,直到用戶刪除
  5. 共享:sessionStorage 不能共享,localStorage 在同源文檔之間共享,cookie 在同源且符合 path 規則的文檔之間共享
  6. localStorage 的修改會促發其餘文檔窗口的 update 事件
  7. cookie 有 secure 屬性要求 HTTPS 傳輸
  8. 瀏覽器不能保存超過 300 個 cookie,單個服務器不能超過 20 個,每一個 cookie 不能超過 4k。web storage 大小支持能達到 5M

javascript 跨域通訊

同源:兩個文檔同源需知足

  1. 協議相同
  2. 域名相同
  3. 端口相同

跨域通訊:js 進行 DOM 操做、通訊時若是目標與當前窗口不知足同源條件,瀏覽器爲了安全會阻止跨域操做。跨域通訊一般有如下方法

  • 若是是 log 之類的簡單**單項通訊**,新建`<img>`,`<script>`,`<link>`,`<iframe>`元素,經過 src,href 屬性設置爲目標 url。實現跨域請求
  • 若是請求**json 數據**,使用`<script>`進行 jsonp 請求
  • 現代瀏覽器中**多窗口通訊**使用 HTML5 規範的 targetWindow.postMessage(data, origin);其中 data 是須要發送的對象,origin 是目標窗口的 origin。window.addEventListener('message', handler, false);handler 的 event.data 是 postMessage 發送來的數據,event.origin 是發送窗口的 origin,event.source 是發送消息的窗口引用
  • 內部服務器代理請求跨域 url,而後返回數據
  • 跨域請求數據,現代瀏覽器可以使用 HTML5 規範的 CORS 功能,只要目標服務器返回 HTTP 頭部**`Access-Control-Allow-Origin: *`**便可像普通 ajax 同樣訪問跨域資源

javascript 有哪幾種數據類型

六種基本數據類型

一種引用類型

  • Object

什麼閉包,閉包有什麼用

**閉包是在某個做用域內定義的函數,它能夠訪問這個做用域內的全部變量**。閉包做用域鏈一般包括三個部分:

  1. 函數自己做用域。
  2. 閉包定義時的做用域。
  3. 全局做用域。

閉包常見用途:

  1. 建立特權方法用於訪問控制
  2. 事件處理程序及回調

javascript 有哪幾種方法定義函數

  1. [函數聲明表達式](https://developer.mozilla.org...
  2. [function 操做符](https://developer.mozilla.org...
  3. [Function 構造函數](https://developer.mozilla.org..._Objects/Function)
  4. [ES6:arrow function](https://developer.mozilla.org..._functions)

重要參考資料:[MDN:Functions_and_function_scope](https://developer.mozilla.org..._and_function_scope)

應用程序存儲和離線 web 應用

HTML5 新增應用程序緩存,容許 web 應用將應用程序自身保存到用戶瀏覽器中,用戶離線狀態也能訪問。 1.爲 html 元素設置 manifest 屬性:`<html manifest="myapp.appcache">`,其中後綴名只是一個約定,真正識別方式是經過`text/cache-manifest`做爲 MIME 類型。因此須要配置服務器保證設置正確
2.manifest 文件首行爲`CACHE MANIFEST`,其他就是要緩存的 URL 列表,每一個一行,相對路徑都相對於 manifest 文件的 url。註釋以#開頭
3.url 分爲三種類型:`CACHE`:爲默認類型。`NETWORK`:表示資源從不緩存。 `FALLBACK`:每行包含兩個 url,第二個 URL 是指須要加載和存儲在緩存中的資源, 第一個 URL 是一個前綴。任何匹配該前綴的 URL 都不會緩存,若是從網絡中載入這樣的 URL 失敗的話,就會用第二個 URL 指定的緩存資源來替代。如下是一個文件例子:

```
CACHE MANIFEST

CACHE:
myapp.html
myapp.css
myapp.js

FALLBACK:
videos/ offline_help.html

NETWORK:
cgi/
```

客戶端存儲 localStorage 和 sessionStorage

  • localStorage 有效期爲永久,sessionStorage 有效期爲頂層窗口關閉前
  • 同源文檔能夠讀取並修改 localStorage 數據,sessionStorage 只容許同一個窗口下的文檔訪問,如經過 iframe 引入的同源文檔。
  • Storage 對象一般被當作普通 javascript 對象使用:**經過設置屬性來存取字符串值**,也能夠經過**setItem(key, value)設置**,**getItem(key)讀取**,**removeItem(key)刪除**,**clear()刪除全部數據**,**length 表示已存儲的數據項數目**,**key(index)返回對應索引的 key**

```
localStorage.setItem('x', 1); // storge x->1
localStorage.getItem('x); // return value of x

// 枚舉全部存儲的鍵值對
for (var i = 0, len = localStorage.length; i < len; ++i ) {

var name = localStorage.key(i);
var value = localStorage.getItem(name);

}

localStorage.removeItem('x'); // remove x
localStorage.clear(); // remove all data
```

cookie 及其操做

  • cookie 是 web 瀏覽器存儲的少許數據,最先設計爲服務器端使用,做爲 HTTP 協議的擴展實現。cookie 數據會自動在瀏覽器和服務器之間傳輸。
  • 經過讀寫 cookie 檢測是否支持
  • cookie 屬性有**名**,**值**,**max-age**,**path**, **domain**,**secure**;
  • cookie 默認有效期爲瀏覽器會話,一旦用戶關閉瀏覽器,數據就丟失,經過設置**max-age=seconds**屬性告訴瀏覽器 cookie 有效期
  • cookie 做用域經過**文檔源**和**文檔路徑**來肯定,經過**path**和**domain**進行配置,web 頁面同目錄或子目錄文檔均可訪問
  • 經過 cookie 保存數據的方法爲:爲 document.cookie 設置一個符合目標的字符串以下
  • 讀取 document.cookie 得到'; '分隔的字符串,key=value,解析獲得結果

```
document.cookie = 'name=qiu; max-age=9999; path=/; domain=domain; secure';

document.cookie = 'name=aaa; path=/; domain=domain; secure';
// 要改變cookie的值,須要使用相同的名字、路徑和域,新的值
// 來設置cookie,一樣的方法能夠用來改變有效期

// 設置max-age爲0能夠刪除指定cookie

//讀取cookie,訪問document.cookie返回鍵值對組成的字符串,
//不一樣鍵值對之間用'; '分隔。經過解析得到須要的值
```

[cookieUtil.js](https://github.com/qiu-deqing...:本身寫的 cookie 操做工具

javascript 有哪些方法定義對象

  1. 對象字面量: `var obj = {};`
  2. 構造函數: `var obj = new Object();`
  3. Object.create(): `var obj = Object.create(Object.prototype);`

===運算符判斷相等的流程是怎樣的

  1. 若是兩個值不是相同類型,它們不相等
  2. 若是兩個值都是 null 或者都是 undefined,它們相等
  3. 若是兩個值都是布爾類型 true 或者都是 false,它們相等
  4. 若是其中有一個是**NaN**,它們不相等
  5. 若是都是數值型而且數值相等,他們相等, -0 等於 0
  6. 若是他們都是字符串而且在相同位置包含相同的 16 位值,他它們相等;若是在長度或者內容上不等,它們不相等;兩個字符串顯示結果相同可是編碼不一樣==和===都認爲他們不相等
  7. 若是他們指向相同對象、數組、函數,它們相等;若是指向不一樣對象,他們不相等

==運算符判斷相等的流程是怎樣的

  1. 若是兩個值類型相同,按照===比較方法進行比較
  2. 若是類型不一樣,使用以下規則進行比較
  3. 若是其中一個值是 null,另外一個是 undefined,它們相等
  4. 若是一個值是**數字**另外一個是**字符串**,將**字符串轉換爲數字**進行比較
  5. 若是有布爾類型,將**true 轉換爲 1,false 轉換爲 0**,而後用==規則繼續比較
  6. 若是一個值是對象,另外一個是數字或字符串,將對象轉換爲原始值而後用==規則繼續比較
  7. **其餘全部狀況都認爲不相等**

對象到字符串的轉換步驟

  1. 若是對象有 toString()方法,javascript 調用它。若是返回一個原始值(primitive value 如:string number boolean),將這個值轉換爲字符串做爲結果
  2. 若是對象沒有 toString()方法或者返回值不是原始值,javascript 尋找對象的 valueOf()方法,若是存在就調用它,返回結果是原始值則轉爲字符串做爲結果
  3. 不然,javascript 不能從 toString()或者 valueOf()得到一個原始值,此時 throws a TypeError

對象到數字的轉換步驟

1. 若是對象有valueOf()方法而且返回元素值,javascript將返回值轉換爲數字做爲結果
2. 不然,若是對象有toString()而且返回原始值,javascript將返回結果轉換爲數字做爲結果
3. 不然,throws a TypeError

<,>,<=,>=的比較規則

全部比較運算符都支持任意類型,可是**比較只支持數字和字符串**,因此須要執行必要的轉換而後進行比較,轉換規則以下:

  1. 若是操做數是對象,轉換爲原始值:若是 valueOf 方法返回原始值,則使用這個值,不然使用 toString 方法的結果,若是轉換失敗則報錯
  2. 通過必要的對象到原始值的轉換後,若是兩個操做數都是字符串,按照字母順序進行比較(他們的 16 位 unicode 值的大小)
  3. 不然,若是有一個操做數不是字符串,**將兩個操做數轉換爲數字**進行比較

+運算符工做流程

  1. 若是有操做數是對象,轉換爲原始值
  2. 此時若是有**一個操做數是字符串**,其餘的操做數都轉換爲字符串並執行鏈接
  3. 不然:**全部操做數都轉換爲數字並執行加法**

函數內部 arguments 變量有哪些特性,有哪些屬性,如何將它轉換爲數組

  • arguments 全部函數中都包含的一個局部變量,是一個類數組對象,對應函數調用時的實參。若是函數定義同名參數會在調用時覆蓋默認對象
  • arguments[index]分別對應函數調用時的實參,而且經過 arguments 修改實參時會同時修改實參
  • arguments.length 爲實參的個數(Function.length 表示形參長度)
  • arguments.callee 爲當前正在執行的函數自己,使用這個屬性進行遞歸調用時需注意 this 的變化
  • arguments.caller 爲調用當前函數的函數(已被遺棄)
  • 轉換爲數組:var args = Array.prototype.slice.call(arguments, 0);

DOM 事件模型是如何的,編寫一個 EventUtil 工具類實現事件管理兼容

  • DOM 事件包含捕獲(capture)和冒泡(bubble)兩個階段:捕獲階段事件從 window 開始觸發事件而後經過祖先節點一次傳遞到觸發事件的 DOM 元素上;冒泡階段事件從初始元素依次向祖先節點傳遞直到 window
  • 標準事件監聽 elem.addEventListener(type, handler, capture)/elem.removeEventListener(type, handler, capture):handler 接收保存事件信息的 event 對象做爲參數,event.target 爲觸發事件的對象,handler 調用上下文 this 爲綁定監聽器的對象,event.preventDefault()取消事件默認行爲,event.stopPropagation()/event.stopImmediatePropagation()取消事件傳遞
  • 老版本 IE 事件監聽 elem.attachEvent('on'+type, handler)/elem.detachEvent('on'+type, handler):handler 不接收 event 做爲參數,事件信息保存在 window.event 中,觸發事件的對象爲 event.srcElement,handler 執行上下文 this 爲 window 使用閉包中調用 handler.call(elem, event)可模仿標準模型,而後返回閉包,保證了監聽器的移除。event.returnValue 爲 false 時取消事件默認行爲,event.cancleBubble 爲 true 時取消時間傳播
  • 一般利用事件冒泡機制託管事件處理程序提升程序性能。

```
/**
* 跨瀏覽器事件處理工具。只支持冒泡。不支持捕獲
* @author (qiu_deqing@126.com)
*/

var EventUtil = {

getEvent: function (event) {
    return event || window.event;
},
getTarget: function (event) {
    return event.target || event.srcElement;
},
// 返回註冊成功的監聽器,IE中須要使用返回值來移除監聽器
on: function (elem, type, handler) {
    if (elem.addEventListener) {
        elem.addEventListener(type, handler, false);
        return handler;
    } else if (elem.attachEvent) {
        var wrapper = function () {
          var event = window.event;
          event.target = event.srcElement;
          handler.call(elem, event);
        };
        elem.attachEvent('on' + type, wrapper);
        return wrapper;
    }
},
off: function (elem, type, handler) {
    if (elem.removeEventListener) {
        elem.removeEventListener(type, handler, false);
    } else if (elem.detachEvent) {
        elem.detachEvent('on' + type, handler);
    }
},
preventDefault: function (event) {
    if (event.preventDefault) {
        event.preventDefault();
    } else if ('returnValue' in event) {
        event.returnValue = false;
    }
},
stopPropagation: function (event) {
    if (event.stopPropagation) {
        event.stopPropagation();
    } else if ('cancelBubble' in event) {
        event.cancelBubble = true;
    }
},
/\*\*
 \* keypress事件跨瀏覽器獲取輸入字符
 \* 某些瀏覽器在一些特殊鍵上也觸發keypress,此時返回null
 \*\*/
 getChar: function (event) {
    if (event.which == null) {
        return String.fromCharCode(event.keyCode);  // IE
    }
    else if (event.which != 0 && event.charCode != 0) {
        return String.fromCharCode(event.which);    // the rest
    }
    else {
        return null;    // special key
    }
 }

};
```

評價一下三種方法實現繼承的優缺點,並改進

```
function Shape() {}

function Rect() {}

// 方法1
Rect.prototype = new Shape();

// 方法2
Rect.prototype = Shape.prototype;

// 方法3
Rect.prototype = Object.create(Shape.prototype);

Rect.prototype.area = function () {
// do something
};
```

方法 1:

  1. 優勢:正確設置原型鏈實現繼承
  2. 優勢:父類實例屬性獲得繼承,原型鏈查找效率提升,也能爲一些屬性提供合理的默認值
  3. 缺點:父類實例屬性爲引用類型時,不恰當地修改會致使全部子類被修改
  4. 缺點:建立父類實例做爲子類原型時,可能沒法肯定構造函數須要的合理參數,這樣提供的參數繼承給子類沒有實際意義,當子類須要這些參數時應該在構造函數中進行初始化和設置
  5. 總結:繼承應該是繼承方法而不是屬性,爲子類設置父類實例屬性應該是經過在子類構造函數中調用父類構造函數進行初始化

方法 2:

  1. 優勢:正確設置原型鏈實現繼承
  2. 缺點:父類構造函數原型與子類相同。修改子類原型添加方法會修改父類

方法 3:

  1. 優勢:正確設置原型鏈且避免方法 1.2 中的缺點
  2. 缺點:ES5 方法須要注意兼容性

改進:

  1. 全部三種方法應該在子類構造函數中調用父類構造函數實現實例屬性初始化

```
function Rect() {

Shape.call(this);

}
```

  1. 用新建立的對象替代子類默認原型,設置`Rect.prototype.constructor = Rect;`保證一致性
  2. 第三種方法的 polyfill:

```
function create(obj) {

if (Object.create) {
    return Object.create(obj);
}

function f() {};
f.prototype = obj;
return new f();

}
```

$javascript 編程部分

請用原生 js 實現一個函數,給頁面制定的任意一個元素添加一個透明遮罩(透明度可變,默認 0.2),使這個區域點擊無效,要求兼容 IE8+及各主流瀏覽器,遮罩層效果以下圖所示:

![遮罩效果](img/element-mask.jpg)

```
<style>

target {

width: 200px;
height: 300px;
margin: 40px;
background-color: tomato;

}
</style>

<div id="target"></div>

<script>
function addMask(elem, opacity) {

opacity = opacity || 0.2;

var rect = elem.getBoundingClientRect();
var style = getComputedStyle(elem, null);

var mask = document.createElement('div');
mask.style.position = 'absolute';
var marginLeft = parseFloat(style.marginLeft);
mask.style.left = (elem.offsetLeft - marginLeft) + 'px';
var marginTop = parseFloat(style.marginTop);
mask.style.top = (elem.offsetTop - marginTop) + 'px';
mask.style.zIndex = 9999;
mask.style.opacity = '' + opacity;
mask.style.backgroundColor = '#000';

mask.style.width = (parseFloat(style.marginLeft) +
    parseFloat(style.marginRight) + rect.width) + 'px';
mask.style.height = (parseFloat(style.marginTop) +
    parseFloat(style.marginBottom) + rect.height) + 'px';

elem.parentNode.appendChild(mask);

}

var target = document.getElementById('target');
addMask(target);

target.addEventListener('click', function () {

console.log('click');

}, false);
</script>
```

請用代碼寫出(今天是星期 x)其中 x 表示當天是星期幾,若是當天是星期一,輸出應該是"今天是星期一"

```
var days = ['日','一','二','三','四','五','六'];
var date = new Date();

console.log('今天是星期' + days[date.getDay()]);
```

下面這段代碼想要循環延時輸出結果 0 1 2 3 4,請問輸出結果是否正確,若是不正確,請說明爲何,並修改循環內的代碼使其輸出正確結果

```
for (var i = 0; i < 5; ++i) {
setTimeout(function () {

console.log(i + ' ');

}, 100);
}
```

不能輸出正確結果,由於循環中 setTimeout 接受的參數函數經過閉包訪問變量 i。javascript 運行環境爲單線程,setTimeout 註冊的函數須要等待線程空閒才能執行,此時 for 循環已經結束,i 值爲 5.五個定時輸出都是 5
修改方法:將 setTimeout 放在函數當即調用表達式中,將 i 值做爲參數傳遞給包裹函數,建立新閉包

```
for (var i = 0; i < 5; ++i) {
(function (i) {

setTimeout(function () {
  console.log(i + ' ');
}, 100);

}(i));
}
```

現有一個 Page 類,其原型對象上有許多以 post 開頭的方法(如 postMsg);另有一攔截函數 chekc,只返回 ture 或 false.請設計一個函數,該函數應批量改造原 Page 的 postXXX 方法,在保留其原有功能的同時,爲每一個 postXXX 方法增長攔截驗證功能,當 chekc 返回 true 時繼續執行原 postXXX 方法,返回 false 時再也不執行原 postXXX 方法

```
function Page() {}

Page.prototype = {
constructor: Page,

postA: function (a) {

console.log('a:' + a);

},
postB: function (b) {

console.log('b:' + b);

},
postC: function (c) {

console.log('c:' + c);

},
check: function () {

return Math.random() > 0.5;

}
}

function checkfy(obj) {
for (var key in obj) {

if (key.indexOf('post') === 0 && typeof obj\[key\] === 'function') {
  (function (key) {
    var fn = obj\[key\];
    obj\[key\] = function () {
      if (obj.check()) {
        fn.apply(obj, arguments);
      }
    };
  }(key));
}

}
} // end checkfy()

checkfy(Page.prototype);

var obj = new Page();

obj.postA('checkfy');
obj.postB('checkfy');
obj.postC('checkfy');
```

完成下面的 tool-tip

![xxx](img/tip-box.jpg)

編寫 javascript 深度克隆函數 deepClone

function deepClone(obj) {
    var \_toString = Object.prototype.toString;

    // null, undefined, non-object, function
    if (!obj || typeof obj !== 'object') {
        return obj;
    }

    // DOM Node
    if (obj.nodeType && 'cloneNode' in obj) {
        return obj.cloneNode(true);
    }

    // Date
    if (\_toString.call(obj) === '\[object Date\]') {
        return new Date(obj.getTime());
    }

    // RegExp
    if (\_toString.call(obj) === '\[object RegExp\]') {
        var flags = \[\];
        if (obj.global) { flags.push('g'); }
        if (obj.multiline) { flags.push('m'); }
        if (obj.ignoreCase) { flags.push('i'); }

        return new RegExp(obj.source, flags.join(''));
    }

    var result = Array.isArray(obj) ? \[\] :
        obj.constructor ? new obj.constructor() : {};

    for (var key in obj ) {
        result\[key\] = deepClone(obj\[key\]);
    }

    return result;
}

function A() {
    this.a = a;
}

var a = {
    name: 'qiu',
    birth: new Date(),
    pattern: /qiu/gim,
    container: document.body,
    hobbys: \['book', new Date(), /aaa/gim, 111\]
};

var c = new A();
var b = deepClone(c);
console.log(c.a === b.a);
console.log(c, b);

補充代碼,鼠標單擊 Button1 後將 Button1 移動到 Button2 的後面

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>TEst</title>
</head>
<body>

<div>
   <input type="button" id ="button1" value="1" />
   <input type="button" id ="button2" value="2" />
</div>

<script type="text/javascript">
    var btn1 = document.getElementById('button1');
    var btn2 = document.getElementById('button2');

    addListener(btn1, 'click', function (event) {
        btn1.parentNode.insertBefore(btn2, btn1);
    });

    function addListener(elem, type, handler) {
        if (elem.addEventListener) {
            elem.addEventListener(type, handler, false);
            return handler;
        } else if (elem.attachEvent) {
            function wrapper() {
                var event = window.event;
                event.target = event.srcElement;
                handler.call(elem, event);
            }
            elem.attachEvent('on' + type, wrapper);
            return wrapper;
        }
    }

</script>
</body>
</html>

網頁中實現一個計算當年還剩多少時間的倒數計時程序,要求網頁上實時動態顯示"×× 年還剩 ×× 天 ×× 時 ×× 分 ×× 秒"

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>TEst</title>
</head>
<body>

    <span id="target"></span>


<script type="text/javascript">
    // 爲了簡化。每個月默認30天
    function getTimeString() {
        var start = new Date();
        var end = new Date(start.getFullYear() + 1, 0, 1);
        var elapse = Math.floor((end - start) / 1000);

        var seconds = elapse % 60 ;
        var minutes = Math.floor(elapse / 60) % 60;
        var hours = Math.floor(elapse / (60 \* 60)) % 24;
        var days = Math.floor(elapse / (60 \* 60 \* 24)) % 30;
        var months = Math.floor(elapse / (60 \* 60 \* 24 \* 30)) % 12;
        var years = Math.floor(elapse / (60 \* 60 \* 24 \* 30 \* 12));

        return start.getFullYear() + '年還剩' + years + '年' + months + '月' + days + '日'
            + hours + '小時' + minutes + '分' + seconds + '秒';
    }

    function domText(elem, text) {
        if (text == undefined) {

            if (elem.textContent) {
                return elem.textContent;
            } else if (elem.innerText) {
                return elem.innerText;
            }
        } else {
            if (elem.textContent) {
                elem.textContent = text;
            } else if (elem.innerText) {
                elem.innerText = text;
            } else {
                elem.innerHTML = text;
            }
        }
    }

    var target = document.getElementById('target');

    setInterval(function () {
        domText(target, getTimeString());
    }, 1000)
</script>

</body>
</html>

完成一個函數,接受數組做爲參數,數組元素爲整數或者數組,數組元素包含整數或數組,函數返回扁平化後的數組

如:[1, [2, [ [3, 4], 5], 6]] => [1, 2, 3, 4, 5, 6]

```

var data =  \[1, \[2, \[ \[3, 4\], 5\], 6\]\];

function flat(data, result) {
    var i, d, len;
    for (i = 0, len = data.length; i < len; ++i) {
        d = data\[i\];
        if (typeof d === 'number') {
            result.push(d);
        } else {
            flat(d, result);
        }
    }
}

var result = \[\];
flat(data, result);

console.log(result);

```

如何判斷一個對象是否爲數組

若是瀏覽器支持 Array.isArray()能夠直接判斷不然需進行必要判斷

```
/**
* 判斷一個對象是不是數組,參數不是對象或者不是數組,返回false
*
* @param {Object} arg 須要測試是否爲數組的對象
* @return {Boolean} 傳入參數是數組返回true,不然返回false
*/
function isArray(arg) {

if (typeof arg === 'object') {
    return Object.prototype.toString.call(arg) === '\[object Array\]';
}
return false;

}
```

請評價如下事件監聽器代碼並給出改進意見

```
if (window.addEventListener) {
var addListener = function (el, type, listener, useCapture) {

el.addEventListener(type, listener, useCapture);

};
}
else if (document.all) {
addListener = function (el, type, listener) {

el.attachEvent('on' + type, function () {
  listener.apply(el);
});

};
}
```

做用:瀏覽器功能檢測實現跨瀏覽器 DOM 事件綁定

優勢:

  1. 測試代碼只運行一次,根據瀏覽器肯定綁定方法
  2. 經過`listener.apply(el)`解決 IE 下監聽器 this 與標準不一致的地方
  3. 在瀏覽器不支持的狀況下提供簡單的功能,在標準瀏覽器中提供捕獲功能

缺點:

  1. document.all 做爲 IE 檢測不可靠,應該使用 if(el.attachEvent)
  2. addListener 在不一樣瀏覽器下 API 不同
  3. `listener.apply`使 this 與標準一致但監聽器沒法移除
  4. 未解決 IE 下 listener 參數 event。 target 問題

改進:

```
var addListener;

if (window.addEventListener) {
addListener = function (el, type, listener, useCapture) {

el.addEventListener(type, listener, useCapture);
return listener;

};
}
else if (window.attachEvent) {
addListener = function (el, type, listener) {

// 標準化this,event,target
var wrapper = function () {
  var event = window.event;
  event.target = event.srcElement;
  listener.call(el, event);
};

el.attachEvent('on' + type, wrapper);
return wrapper;
// 返回wrapper。調用者能夠保存,之後remove

};
}
```

如何判斷一個對象是否爲函數

```
/**
* 判斷對象是否爲函數,若是當前運行環境對可調用對象(如正則表達式)
* 的typeof返回'function',採用通用方法,不然採用優化方法
*
* @param {Any} arg 須要檢測是否爲函數的對象
* @return {boolean} 若是參數是函數,返回true,不然false
*/
function isFunction(arg) {

if (arg) {
    if (typeof (/./) !== 'function') {
        return typeof arg === 'function';
    } else {
        return Object.prototype.toString.call(arg) === '\[object Function\]';
    }
} // end if
return false;

}
```

編寫一個函數接受 url 中 query string 爲參數,返回解析後的 Object,query string 使用 application/x-www-form-urlencoded 編碼

```
/**
* 解析query string轉換爲對象,一個key有多個值時生成數組
*
* @param {String} query 須要解析的query字符串,開頭能夠是?,
* 按照application/x-www-form-urlencoded編碼
* @return {Object} 參數解析後的對象
*/
function parseQuery(query) {

var result = {};

// 若是不是字符串返回空對象
if (typeof query !== 'string') {
    return result;
}

// 去掉字符串開頭可能帶的?
if (query.charAt(0) === '?') {
    query = query.substring(1);
}

var pairs = query.split('&');
var pair;
var key, value;
var i, len;

for (i = 0, len = pairs.length; i < len; ++i) {
    pair = pairs\[i\].split('=');
    // application/x-www-form-urlencoded編碼會將' '轉換爲+
    key = decodeURIComponent(pair\[0\]).replace(/\\+/g, ' ');
    value = decodeURIComponent(pair\[1\]).replace(/\\+/g, ' ');

    // 若是是新key,直接添加
    if (!(key in result)) {
        result\[key\] = value;
    }
    // 若是key已經出現一次以上,直接向數組添加value
    else if (isArray(result\[key\])) {
        result\[key\].push(value);
    }
    // key第二次出現,將結果改成數組
    else {
        var arr = \[result\[key\]\];
        arr.push(value);
        result\[key\] = arr;
    } // end if-else
} // end for

return result;

}

function isArray(arg) {

if (arg && typeof arg === 'object') {
    return Object.prototype.toString.call(arg) === '\[object Array\]';
}
return false;

}
/**
console.log(parseQuery('sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8'));
*/
```

解析一個完整的 url,返回 Object 包含域與 window.location 相同

```
/**
* 解析一個url並生成window.location對象中包含的域
* location:
* {
* href: '包含完整的url',
* origin: '包含協議到pathname以前的內容',
* protocol: 'url使用的協議,包含末尾的:',
* username: '用戶名', // 暫時不支持
* password: '密碼', // 暫時不支持
* host: '完整主機名,包含:和端口',
* hostname: '主機名,不包含端口'
* port: '端口號',
* pathname: '服務器上訪問資源的路徑/開頭',
* search: 'query string,?開頭',
* hash: '#開頭的fragment identifier'
* }
*
* @param {string} url 須要解析的url
* @return {Object} 包含url信息的對象
*/
function parseUrl(url) {

var result = {};
var keys = \['href', 'origin', 'protocol', 'host',
            'hostname', 'port', 'pathname', 'search', 'hash'\];
var i, len;
var regexp = /((\[^:\]+:)\\/\\/((\[^:\\/\\?#\]+)(:\\d+)?))(\\/\[^?#\]\*)?(\\?\[^#\]\*)?(#.\*)?/;

var match = regexp.exec(url);

if (match) {
    for (i = keys.length - 1; i >= 0; --i) {
        result\[keys\[i\]\] = match\[i\] ? match\[i\] : '';
    }
}

return result;

}
```

完成函數 getViewportSize 返回指定窗口的視口尺寸

```
/**
* 查詢指定窗口的視口尺寸,若是不指定窗口,查詢當前窗口尺寸
**/
function getViewportSize(w) {

w = w || window;

// IE9及標準瀏覽器中可以使用此標準方法
if ('innerHeight' in w) {
    return {
        width: w.innerWidth,
        height: w.innerHeight
    };
}

var d = w.document;
// IE 8及如下瀏覽器在標準模式下
if (document.compatMode === 'CSS1Compat') {
    return {
        width: d.documentElement.clientWidth,
        height: d.documentElement.clientHeight
    };
}

// IE8及如下瀏覽器在怪癖模式下
return {
    width: d.body.clientWidth,
    height: d.body.clientHeight
};

}
```

完成函數 getScrollOffset 返回窗口滾動條偏移量

/\*\*
 \* 獲取指定window中滾動條的偏移量,如未指定則獲取當前window
 \* 滾動條偏移量
 \*
 \* @param {window} w 須要獲取滾動條偏移量的窗口
 \* @return {Object} obj.x爲水平滾動條偏移量,obj.y爲豎直滾動條偏移量
 \*/
function getScrollOffset(w) {
    w =  w || window;
    // 若是是標準瀏覽器
    if (w.pageXOffset != null) {
        return {
            x: w.pageXOffset,
            y: w.pageYOffset
        };
    }

    // 老版本IE,根據兼容性不一樣訪問不一樣元素
    var d = w.document;
    if (d.compatMode === 'CSS1Compat') {
        return {
            x: d.documentElement.scrollLeft,
            y: d.documentElement.scrollTop
        }
    }

    return {
        x: d.body.scrollLeft,
        y: d.body.scrollTop
    };
}

現有一個字符串 richText,是一段富文本,須要顯示在頁面上.有個要求,須要給其中只包含一個 img 元素的 p 標籤增長一個叫 pic 的 class.請編寫代碼實現.可使用 jQuery 或 KISSY.

function richText(text) {
    var div = document.createElement('div');
    div.innerHTML = text;
    var p = div.getElementsByTagName('p');
    var i, len;

    for (i = 0, len = p.length; i < len; ++i) {
        if (p\[i\].getElementsByTagName('img').length === 1) {
            p\[i\].classList.add('pic');
        }
    }

    return div.innerHTML;
}

請實現一個 Event 類,繼承自此類的對象都會擁有兩個方法 on,off,once 和 trigger

function Event() {
    if (!(this instanceof Event)) {
        return new Event();
    }
    this.\_callbacks = {};
}
Event.prototype.on = function (type, handler) {
    this\_callbacks = this.\_callbacks || {};
    this.\_callbacks\[type\] = this.callbacks\[type\] || \[\];
    this.\_callbacks\[type\].push(handler);

    return this;
};

Event.prototype.off = function (type, handler) {
    var list = this.\_callbacks\[type\];

    if (list) {
        for (var i = list.length; i >= 0; --i) {
            if (list\[i\] === handler) {
                list.splice(i, 1);
            }
        }
    }

    return this;
};

Event.prototype.trigger = function (type, data) {
    var list = this.\_callbacks\[type\];

    if (list) {
        for (var i = 0, len = list.length; i < len; ++i) {
            list\[i\].call(this, data);
        }
    }
};

Event.prototype.once = function (type, handler) {
    var self = this;

    function wrapper() {
        handler.apply(self, arguments);
        self.off(type, wrapper);
    }
    this.on(type, wrapper);
    return this;
};

編寫一個函數將列表子元素順序反轉

```
<ul id="target">

<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>

</ul>

<script>

var target = document.getElementById('target');
var i;
var frag = document.createDocumentFragment();

for (i = target.children.length - 1; i &gt;= 0; --i) {
    frag.appendChild(target.children\[i\]);
}
target.appendChild(frag);

</script>
```

如下函數的做用是?空白區域應該填寫什麼

```
// define
(function (window) {

function fn(str) {
    this.str = str;
}

fn.prototype.format = function () {
    var arg = \_\_1\_\_;
    return this.str.replace(\_\_2\_\_, function (a, b) {
        return arg\[b\] || '';
    });
};

window.fn = fn;

})(window);

// use
(function () {

var t = new fn('<p><a href="{0}">{1}</a><span>{2}</span></p>');
console.log(t.format('http://www.alibaba.com', 'Alibaba', 'Welcome'));

})();
```

define 部分定義一個簡單的模板類,使用{}做爲轉義標記,中間的數字表示替換目標,format 實參用來替換模板內標記
橫線處填:

  1. `Array.prototype.slice.call(arguments, 0)`
  2. `/\{\s*(\d+)\s*\}/g`

編寫一個函數實現 form 的序列化(即將一個表單中的鍵值序列化爲可提交的字符串)

<form id="target">
    <select name="age">
        <option value="aaa">aaa</option>
        <option value="bbb" selected>bbb</option>
    </select>
    <select name="friends" multiple>
        <option value="qiu" selected>qiu</option>
        <option value="de">de</option>
        <option value="qing" selected>qing</option>
    </select>
    <input name="name" value="qiudeqing">
    <input type="password" name="password" value="11111">
    <input type="hidden" name="salery" value="3333">
    <textarea name="description">description</textarea>
    <input type="checkbox" name="hobby" checked value="football">Football
    <input type="checkbox" name="hobby" value="basketball">Basketball
    <input type="radio" name="sex" checked value="Female">Female
    <input type="radio" name="sex" value="Male">Male
</form>


<script>

/\*\*
 \* 將一個表單元素序列化爲可提交的字符串
 \*
 \* @param {FormElement} form 須要序列化的表單元素
 \* @return {string} 表單序列化後的字符串
 \*/
function serializeForm(form) {
  if (!form || form.nodeName.toUpperCase() !== 'FORM') {
    return;
  }

  var result = \[\];

  var i, len;
  var field, fieldName, fieldType;

  for (i = 0, len = form.length; i < len; ++i) {
    field = form.elements\[i\];
    fieldName = field.name;
    fieldType = field.type;

    if (field.disabled || !fieldName) {
      continue;
    } // enf if

    switch (fieldType) {
      case 'text':
      case 'password':
      case 'hidden':
      case 'textarea':
        result.push(encodeURIComponent(fieldName) + '=' +
            encodeURIComponent(field.value));
        break;

      case 'radio':
      case 'checkbox':
        if (field.checked) {
          result.push(encodeURIComponent(fieldName) + '=' +
            encodeURIComponent(field.value));
        }
        break;

      case 'select-one':
      case 'select-multiple':
        for (var j = 0, jLen = field.options.length; j < jLen; ++j) {
          if (field.options\[j\].selected) {
            result.push(encodeURIComponent(fieldName) + '=' +
              encodeURIComponent(field.options\[j\].value || field.options\[j\].text));
          }
        } // end for
        break;

      case 'file':
      case 'submit':
        break; // 是否處理?

      default:
        break;
    } // end switch
  } // end for

    return result.join('&');
}

var form = document.getElementById('target');
console.log(serializeForm(form));
</script>

使用原生 javascript 給下面列表中的 li 節點綁定點擊事件,點擊時建立一個 Object 對象,兼容 IE 和標準瀏覽器

```
<ul id="nav">

<li><a href="http://11111">111</a></li>
<li><a href="http://2222">222</a></li>
<li><a href="http://333">333</a></li>
<li><a href="http://444">444</a></li>

</ul>

Object:
{

"index": 1,
"name": "111",
"link": "http://1111"

}
```

script:

```
var EventUtil = {

getEvent: function (event) {
    return event || window.event;
},
getTarget: function (event) {
    return event.target || event.srcElement;
},
// 返回註冊成功的監聽器,IE中須要使用返回值來移除監聽器
on: function (elem, type, handler) {
    if (elem.addEventListener) {
        elem.addEventListener(type, handler, false);
        return handler;
    } else if (elem.attachEvent) {
        function wrapper(event) {
            return handler.call(elem, event);
        };
        elem.attachEvent('on' + type, wrapper);
        return wrapper;
    }
},
off: function (elem, type, handler) {
    if (elem.removeEventListener) {
        elem.removeEventListener(type, handler, false);
    } else if (elem.detachEvent) {
        elem.detachEvent('on' + type, handler);
    }
},
preventDefault: function (event) {
    if (event.preventDefault) {
        event.preventDefault();
    } else if ('returnValue' in event) {
        event.returnValue = false;
    }
},
stopPropagation: function (event) {
    if (event.stopPropagation) {
        event.stopPropagation();
    } else if ('cancelBubble' in event) {
        event.cancelBubble = true;
    }
}

};
var DOMUtil = {

text: function (elem) {
    if ('textContent' in elem) {
        return elem.textContent;
    } else if ('innerText' in elem) {
        return elem.innerText;
    }
},
prop: function (elem, propName) {
    return elem.getAttribute(propName);
}

};

var nav = document.getElementById('nav');

EventUtil.on(nav, 'click', function (event) {

var event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);

var children = this.children;
var i, len;
var anchor;
var obj = {};

for (i = 0, len = children.length; i < len; ++i) {
    if (children\[i\] === target) {
        obj.index = i + 1;
        anchor = target.getElementsByTagName('a')\[0\];
        obj.name = DOMUtil.text(anchor);
        obj.link = DOMUtil.prop(anchor, 'href');
    }
}

alert('index: ' + obj.index + ' name: ' + obj.name +
    ' link: ' + obj.link);

});
```

有一個大數組,var a = ['1', '2', '3', ...];a 的長度是 100,內容填充隨機整數的字符串.請先構造此數組 a,而後設計一個算法將其內容去重

```

/\*\*
\* 數組去重
\*\*/
function normalize(arr) {
    if (arr && Array.isArray(arr)) {
        var i, len, map = {};
        for (i = arr.length; i >= 0; --i) {
            if (arr\[i\] in map) {
                arr.splice(i, 1);
            } else {
                map\[arr\[i\]\] = true;
            }
        }
    }
    return arr;
}

/\*\*
\* 用100個隨機整數對應的字符串填充數組。
\*\*/
function fillArray(arr, start, end) {
    start = start == undefined ? 1 : start;
    end = end == undefined ?  100 : end;

    if (end <= start) {
        end = start + 100;
    }

    var width = end - start;
    var i;
    for (i = 100; i >= 1; --i) {
        arr.push('' + (Math.floor(Math.random() \* width) + start));
    }
    return arr;
}

var input = \[\];
fillArray(input, 1, 100);
input.sort(function (a, b) {
    return a - b;
});
console.log(input);

normalize(input);
console.log(input);

```

相關文章
相關標籤/搜索