web面試題大全


FE-interview

個人收集的前端知識點、面試題和答案,參考答案僅代表個人觀點,方便復習,目錄如下,通過文檔內搜索目錄可快速定位章節

$HTML, HTTP,web綜合問題

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

排序算法比較

前端需要注意哪些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>titlealt有什么區別

  1. titleglobal attributes之一,用於為元素提供附加的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或者W3C HTML global-attributes

  • 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通過添加符合規則的class描述信息 為什么需要語義化:

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

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. 瀏覽器查看緩存,如果請求資源在緩存中並且新鮮,跳轉到轉碼步驟
    1. 如果資源未緩存,發起新請求
    2. 如果已緩存,檢驗是否足夠新鮮,足夠新鮮直接提供給客戶端,否則與服務器進行驗證。
    3. 檢驗新鮮通常有兩個HTTP頭進行控制ExpiresCache-Control
      • HTTP1.0提供Expires,值為一個絕對時間表示緩存新鮮日期
      • HTTP1.1增加了Cache-Control: max-age=,值為以秒為單位的最大新鮮時間
  3. 瀏覽器解析URL獲取協議,主機,端口,path
  4. 瀏覽器組裝一個HTTP(GET)請求報文
  5. 瀏覽器獲取主機ip地址,過程如下:
    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樹構建渲染樹:
    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 request報文結構是怎樣的

rfc2616中進行了定義:

  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中進行了定義:

  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

  • 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. 使用不使用@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

  • 1XX:信息狀態碼
    • 100 Continue:客戶端應當繼續發送請求。這個臨時相應是用來通知客戶端它的部分請求已經被服務器接收,且仍未被拒絕。客戶端應當繼續發送請求的剩余部分,或者如果請求已經完成,忽略這個響應。服務器必須在請求萬仇向客戶端發送一個最終響應
    • 101 Switching Protocols:服務器已經理解力客戶端的請求,並將通過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]常見格式如下
<!--[if IE 6]>
Special instructions for IE 6 here
<![endif]-->
  • 選擇器hack:不同瀏覽器對選擇器的支持不一樣
/***** 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
  3. link可以通過rel="alternate stylesheet"指定候選樣式
  4. 瀏覽器對link支持早於@import,可以使用@import對老瀏覽器隱藏樣式
  5. @import必須在樣式規則之前,可以在css文件中引用其他文件
  6. 總體來說:link優於@import

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.浮動或絕對定位時會轉換為block7.vertical-align屬性生效

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

參考資料: 選擇正確的圖片格式 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下內容高度超過會自動擴展高度
}
  • olli的序號全為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. 設置容器元素偽元素進行清理推薦的清理浮動方法
/**
* 在標准瀏覽器下使用
* 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取值為absolutefixed
  4. display取值為inline-block,table-celltable-caption,flexinline-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轉換規則

外邊距折疊(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. positionrelative或者static的元素,它的包含塊由最近的塊級(displayblock,list-itemtable)祖先元素的內容框組成
  3. 如果元素positionfixed。對於連續媒體,它的包含塊為viewport;對於paged media,包含塊為page area
  4. 如果元素positionabsolute,它的包含塊由祖先元素中最近一個positionrelative,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。 盤點8種CSS實現垂直居中

  • 需要居中元素為單行文本,為包含文本的元素設置大於font-sizeline-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
  • <a href="../index.html">link</a>中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

元素尺寸

XMLHttpRequest通用屬性和方法

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

六種基本數據類型

  • undefined
  • null
  • string
  • boolean
  • number
  • symbol(ES6)

一種引用類型

  • Object

什么閉包,閉包有什么用

閉包是在某個作用域內定義的函數,它可以訪問這個作用域內的所有變量。閉包作用域鏈通常包括三個部分:

  1. 函數本身作用域。
  2. 閉包定義時的作用域。
  3. 全局作用域。

閉包常見用途:

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

javascript有哪幾種方法定義函數

  1. 函數聲明表達式
  2. function操作符
  3. Function 構造函數
  4. ES6:arrow function

重要參考資料:MDN:Functions_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:自己寫的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. 如果類型不同,使用如下規則進行比較
    1. 如果其中一個值是null,另一個是undefined,它們相等
    2. 如果一個值是數字另一個是字符串,將字符串轉換為數字進行比較
    3. 如果有布爾類型,將true轉換為1,false轉換為0,然后用==規則繼續比較
    4. 如果一個值是對象,另一個是數字或字符串,將對象轉換為原始值然后用==規則繼續比較
    5. 其他所有情況都認為不相等

對象到字符串的轉換步驟

  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+及各主流瀏覽器,遮罩層效果如下圖所示:

遮罩效果

<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

編寫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);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM