本文是在GitHub上看到一個大牛總結的前端常見面試題,不少問題問的都很好,很經典、頗有表明性。上面沒有答案,我就整理了一下,從網上找了一些相關問題的答案。裏面有一部分問題的答案我也沒有進行考證,很多答案都來源於網絡,或許會有疏漏之處,僅供你們參考哦!(還有一部分問題答案還未整理,你們也能夠本身搜索一下答案)javascript
參考文章:優雅降級和漸進加強的區別css
優雅降級:Web站點在全部新式瀏覽器中都能正常工做,若是用戶使用的是老式瀏覽器,則代碼會檢查以確認它們是否能正常工做。因爲IE獨特的盒模型佈局問題,針對不一樣版本的IE的hack實踐過優雅降級了,爲那些沒法支持功能的瀏覽器增長候選方案,使之在舊式瀏覽器上以某種形式降級體驗卻不至於徹底失效。html
漸進加強:從被全部瀏覽器支持的基本功能開始,逐步地添加那些只有新式瀏覽器才支持的功能,向頁面增長無害於基礎瀏覽器的額外樣式和功能的。當瀏覽器支持時,它們會自動地呈現出來併發揮做用。前端
一個程序至少有一個進程,一個進程至少有一個線程。線程的劃分尺度小於進程,使得多線程程序的併發性高。html5
另外,進程在執行過程當中擁有獨立的內存單元,而多個線程共享內存,從而極大地提升了程序的運行效率。java
線程在執行過程當中與進程仍是有區別的。每一個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。可是線程不可以獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。node
從邏輯角度來看,多線程的意義在於一個應用程序中,有多個執行部分能夠同時執行。但操做系統並無將多個線程看作多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。jquery
去掉或樣式丟失的時候能讓頁面呈現清晰的結構:html自己是沒有表現的,例如<h1>是粗體,字體大小2em,加粗;<strong>是加粗的,不要認爲這是html的表現,這些實際上是 html 默認的css樣式在起做用,因此去掉或樣式丟失的時候,依然能讓頁面呈現清晰的結構。默認樣式的目的也是爲了更好的表達html的語義,能夠說瀏覽器的默認樣式和語義化的HTML結構是不可分割的。css3
屏幕閱讀器(若是訪客有視障)會徹底根據你的標記來「讀」你的網頁。git
PDA、手機等設備可能沒法像普通電腦的瀏覽器同樣來渲染網頁(一般是由於這些設備對CSS的支持較弱)。
有利於SEO:和搜索引擎創建良好溝通,有助於爬蟲抓取更多的有效信息:爬蟲依賴於標籤來肯定上下文和各個關鍵字的權重。
便於團隊開發和維護,語義化更具可讀性,是下一步把握網頁的重要動向,遵循W3C標準的團隊都遵循這個標準,能夠減小差別化。
期待的解決方案包括:文件合併文件最小化/文件壓縮使用CDN託管緩存的使用(多個域名來提供緩存)等。
CDN緩存更方便
突破瀏覽器併發限制(通常每一個域名創建的連接不超過6個)
Cookieless,節省帶寬,尤爲是上行帶寬通常比下行要慢
對於UGC的內容和主站隔離,防止沒必要要的安全問題(上傳js竊取主站cookie之類的)。正是這個緣由要求用戶內容的域名必須不是本身主站的子域名,而是一個徹底獨立的第三方域名。
數據作了劃分,甚至切到了不一樣的物理集羣,經過子域名來分流比較省事。這個可能被用的很少。
PS:關於Cookie的問題,帶寬是次要的,安全隔離纔是主要的。關於多域名,也不是越多越好,雖然服務器端能夠作泛解釋,瀏覽器作dns解釋也是耗時間的,並且太多域名,若是要走https的話,還有要多買證書和部署的問題。
優化圖片
圖像格式的選擇(GIF:提供的顏色較少,可用在一些對顏色要求不高的地方)
優化CSS(壓縮合並css,如margin-top,margin-left...)
網址後加斜槓(如www.campr.com/目錄,會判斷這個「目錄是什麼文件類型,或者是目錄。)
標明高度和寬度(若是瀏覽器沒有找到這兩個參數,它須要一邊下載圖片一邊計算大小,若是圖片不少,瀏覽器須要不斷地調整頁面。這不但影響速度,也影響瀏覽體驗。當瀏覽器知道了高度和寬度參數後,即便圖片暫時沒法顯示,頁面上也會騰出圖片的空位,而後繼續加載後面的內容。從而加載時間快了,瀏覽體驗也更好了。)
減小http請求(合併文件,合併圖片)。
建議這個項目使用像EditorConfig(http://editorconfig.org/)之類的規範
爲了保持一致性,接受項目原有的風格
直接使用VIM的retab命令
若是不使用JS來完成,能夠加分。(如:純CSS實現的幻燈片效果)
Profiler,JSPerf(http://jsperf.com/nexttick-vs-setzerotimeout-vs-settimeout),Dromaeo。
nodejs,html5,css3,less等。
w3c存在的意義就是讓瀏覽器兼容性問題儘可能小,首先是他們對瀏覽器開發者的約束,而後是對開發者的約束。
FOUC(Flash Of Unstyled Content)--文檔樣式閃爍
1
2
3
|
<
style
type
=
"text/css"
media
=
"all"
>
@import"../fouc.css";
</
style
>
|
而引用CSS文件的@import就是形成這個問題的罪魁禍首。IE會先加載整個HTML文檔的DOM,而後再去導入外部的CSS文件,所以,在頁面DOM加載完成到CSS導入完成中間會有一段時間頁面上的內容是沒有樣式的,這段時間的長短跟網速,電腦速度都有關係。解決方法簡單的出奇,只要在<head>之間加入一個<link>或者<script>元素就能夠了。
此標籤可告知瀏覽器文檔使用哪一種HTML或XHTML規範。該標籤可聲明三種DTD類型,分別表示嚴格版本、過渡版本以及基於框架的HTML文檔。
HTML 4.01規定了三種文檔類型:Strict、Transitional 以及 Frameset。
XHTML 1.0規定了三種XML文檔類型:Strict、Transitional 以及 Frameset。
Standards(標準)模式(也就是嚴格呈現模式)用於呈現遵循最新標準的網頁,而Quirks(包容)模式(也就是鬆散呈現模式或者兼容模式)用於呈現爲傳統瀏覽器而設計的網頁。
若是有對web前端感興趣前端程序員,,可加入咱們的web前端技術學習羣的61852,2268,裏面免費送前端的零基礎教程噢!
寫在最後:
不少人都知道我是學全棧的,都天真的覺得我有全套的前端、網頁製做等視頻學習資料。我想說大家是對的,個人確有前端的全套視頻資料。
下圖就是:
W3C標準推出之後,瀏覽器都開始採納新標準,但存在一個問題就是如何保證舊的網頁還能繼續瀏覽,在標準出來之前,不少頁面都是根據舊的渲染方法編寫的,若是用新的標準來渲染,將致使頁面顯示異常。爲保持瀏覽器渲染的兼容性,使之前的頁面可以正常瀏覽,瀏覽器都保留了舊的渲染方法(如:微軟的IE)。這樣瀏覽器渲染上就產生了Quircks mode和Standars mode,兩種渲染方法共存在一個瀏覽器上。IE盒子模型和標準W3C盒子模型:ie的width包括:padding\border。標準的width不包括:padding\border
在js中如何判斷當前瀏覽器正在以何種方式解析?
document對象有個屬性compatMode,它有兩個值:BackCompat對應quirks mode,CSS1Compat對應strict mode。
XHTML 與HTML的區別爲:
XHTML 元素必須被正確地嵌套。
XHTML 元素必須被關閉。
標籤名必須用小寫字母。
XHTML 文檔必須擁有根元素。
侷限:
全部的 XHTML 元素都必須被正確地嵌套,XHTML 必須擁有良好的結構,全部的標籤必須小寫,而且全部的 XHTML 元素必須被關閉。全部的 XHTML 文檔必須擁有 DOCTYPE 聲明,而且 html、head、title 和 body 元素必須存在。雖然代碼更加的優雅,但缺乏容錯性,不利於快速開發。
下面這些問題須要考慮:
應用字符集的選擇,選擇UTF-8編碼
語言書寫習慣 & 導航結構
數據庫驅動型網站
data-* 屬性用於存儲頁面或應用程序的私有自定義數據。data-* 屬性賦予咱們在全部 HTML 元素上嵌入自定義 data 屬性的能力。存儲的(自定義)數據可以被頁面的 JavaScript 中利用,以建立更好的用戶體驗(不進行 Ajax 調用或服務器端數據庫查詢)。
data-* 屬性包括兩部分:
屬性名不該該包含任何大寫字母,而且在前綴 "data-" 以後必須有至少一個字符
屬性值能夠是任意字符串
1
2
3
4
|
<
nav
></
nav
>
<
header
></
header
>
<
section
></
section
>
<
footer
></
footer
>
|
等。
sessionStorage和localStorage是HTML5 Web Storage API提供的,能夠方便的在web請求之間保存數據。有了本地數據,就能夠避免數據在瀏覽器和服務器間沒必要要地來回傳遞。sessionStorage、localStorage、cookie都是在瀏覽器端存儲的數據,其中sessionStorage的概念很特別,引入了一個「瀏覽器窗口」的概念。sessionStorage是在同源的同學口(或tab)中,始終存在的數據。也就是說只要這個瀏覽器窗口沒有關閉,即便刷新頁面或進入同源另外一頁面,數據仍然存在。關閉窗口後,sessionStorage即被銷燬。同時「獨立」打開的不一樣窗口,即便是同一頁面,sessionStorage對象也是不一樣的cookies會發送到服務器端。其他兩個不會。Microsoft指出InternetExplorer8增長cookie限制爲每一個域名50個,但IE7彷佛也容許每一個域名50個cookie。
Firefox每一個域名cookie限制爲50個。
Opera每一個域名cookie限制爲30個。
Firefox和Safari容許cookie多達4097個字節,包括名(name)、值(value)和等號。
Opera容許cookie多達4096個字節,包括:名(name)、值(value)和等號。
InternetExplorer容許cookie多達4095個字節,包括:名(name)、值(value)和等號。
由於瀏覽器的品種不少,每一個瀏覽器的默認樣式也是不一樣的,因此定義一個css reset能夠使各瀏覽器的默認樣式統一,還原頁面時能夠更加精準。
關於浮動咱們須要瞭解,浮動的框能夠向左或向右移動,直到它的外邊緣碰到包含框或另外一個浮動框的邊框爲止。要想使元素浮動,必須爲元素設置一個寬度(width)。雖然浮動元素不是文檔流之中,可是它浮動後所處的位置依然是在浮動以前的水平方向上。因爲浮動框不在文檔的普通流中,因此文檔的普通流中的塊框表現得就像浮動框不存在同樣,下面的元素填補原來的位置。有些元素會在浮動元素的下方,可是這些元素的內容並不必定會被浮動的元素所遮蓋,對內聯元素進行定位時,這些元素會考慮浮動元素的邊界,會圍繞着浮動元素放置。也能夠把浮動元素想象成是被塊元素忽略的元素,而內聯元素會關注浮動元素的。
使用空標籤清除浮動。這種方法是在全部浮動標籤後面添加一個空標籤訂義css clear:both.弊端就是增長了無心義標籤。
使用overflow。給包含浮動元素的父標籤添加css屬性overflow:auto;zoom:1;zoom:1用於兼容IE6。
使用after僞對象清除浮動。該方法只適用於非IE瀏覽器。具體寫法可參照如下示例。使用中需注意如下幾點。1、該方法中必須爲須要清除浮動元素的僞對象中設置height:0,不然該元素會比實際高出若干像素;2、content屬性是必須的,但其值能夠爲空,content屬性的值設爲」.」,空亦是能夠的。
浮動外部元素
此三種方法各有利弊,使用時應擇優選擇,比較之下第二種方法更爲可取。
CSS Sprites其實就是把網頁中一些背景圖片整合到一張圖片文件中,再利用CSS的「background-image」,「background-repeat」,「background-position」的組合進行背景定位,background-position能夠用數字能精確的定位出背景圖片的位置。
1
|
<
h2
><
span
>圖片丟這裏</
span
>Hello World</
h2
>
|
把span背景設成文字內容,這樣又能夠保證seo,也有圖片的效果在上面。通常都是:alt,title,onerror。
各個瀏覽器都認識,這裏給firefox用;
1
2
3
4
5
6
7
8
9
10
|
\9全部的ie瀏覽器可識別;
\0是留給ie8的+background-color:pink;+ie7定了;
_ _專門留給神奇的ie6;
:root#test{} :root是給ie9的,
@media all and (min-width:0px){
#test{} 這個是總是跟ie搶着認\0的神奇的opera,必須加個\0,否則firefox,chrome,safari也都認識。
}
@media screen and (-webkit-min-device-pixel-ratio:0){ 最後這個是瀏覽器新貴chrome和safari的。
#test{}
}
|
你會使用哪些技術和處理方法?
display:none; 的缺陷搜索引擎可能認爲被隱藏的文字屬於垃圾信息而被忽略屏幕閱讀器(是爲視覺上有障礙的人設計的讀取屏幕內容的程序)會忽略被隱藏的文字。
visibility:hidden; 的缺陷就是內容雖然隱藏了,但物理空間依然會佔據
一個比較合理的方法,利用 overflow:hidden
1
2
3
4
5
6
|
.texthidden{
display:block; /*統一轉化爲塊級元素*/
overflow:hidden;
width:0;
height:0;
}
|
就像上面的一段CSS所展現的方法,將寬度和高度設定爲0,而後超過部分隱藏,就會彌補上述1、二方法中的缺陷,也達到了隱藏內容的目的。
好比:Bootstrap,流式柵格系統,http://960.gs/,柵格系統延續美學。
媒體查詢,就是響應式佈局。經過不一樣的媒介類型和條件定義樣式表規則。媒介查詢讓CSS能夠更精確做用於不一樣的媒介類型和同一媒介的不一樣條件。
語法結構及用法:@media 設備名 only (選取條件) not (選取條件) and(設備選取條件),設備二{sRules}。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/* 當瀏覽器的可視區域小於980px */
@media
screen
and (
max-width
:
980px
){
#wrap {width:
90%
;
margin
:
0
auto
;}
#content {
width
:
60%
;
padding
:
5%
;}
#sidebar {
width
:
30%
;}
#footer {
padding
:
8%
5%
;
margin-bottom
:
10px
;}
}
/* 當瀏覽器的可視區域小於650px */
@media
screen
and (
max-width
:
650px
){
#header {
height
:
auto
;}
#searchform {
position
:
absolute
;
top
:
5px
;
right
:
0
;}
#content {
width
:
auto
;
float
:
none
;
margin
:
20px
0
;}
#sidebar {
width
:
100%
;
float
:
none
;
margin
:
0
;}
}
|
SVG 意爲可縮放矢量圖形(Scalable Vector Graphics)。
SVG 指可伸縮矢量圖形 (Scalable Vector Graphics)
SVG 用來定義用於網絡的基於矢量的圖形
SVG 使用 XML 格式定義圖形
SVG 圖像在放大或改變尺寸的狀況下其圖形質量不會有所損失
SVG 是萬維網聯盟的標準
SVG 與諸如 DOM 和 XSL 之類的 W3C 標準是一個總體
書寫示例以下:
1
2
3
4
5
|
<?
xml
version
=
"1.0"
standalone
=
"no"
?>2
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<
svg
width
=
"100%"
height
=
"100%"
version
=
"1.1"
xmlns
=
"http://www.w3.org/2000/svg"
>
<
circle
cx
=
"100"
cy
=
"50"
r
=
"40"
stroke
=
"black"
stroke-width
=
"2"
fill
=
"red"
/>
</
svg
>
|
1
|
<
link
rel
=
"stylesheet"
media
=
"screen"
href
=
"xxx.css"
/>
|
其中media指定的屬性就是設備,顯示器上就是screen,打印機則是print,電視是tv,投影儀是projection。
打印樣式示例以下:
1
|
<
link
rel
=
"stylesheet"
media
=
"print"
href
=
"yyy.css"
/>
|
但打印樣式表也應注意如下事項:
打印樣式表中最好不要用背景圖片,由於打印機不能打印CSS中的背景。如要顯示圖片,請使用html插入到頁面中。
最好不要使用像素做爲單位,由於打印樣式表要打印出來的會是實物,因此建議使用pt和cm。
隱藏掉沒必要要的內容。(@print div{display:none;})
打印樣式表中最好少用浮動屬性,由於它們會消失。若是想要知道打印樣式表的效果如何,直接在瀏覽器上選擇打印預覽就能夠了。
樣式是:從右向左的解析一個選擇器;
ID最快,Universal最慢有四種類型的key selector,解析速度由快到慢依次是:ID、class、tag和universal ;
不要tag-qualify(永遠不要這樣作ul#main-navigation{}ID已是惟一的,不須要Tag來標識,這樣作會讓選擇器變慢。);
後代選擇器最糟糕(換句話說,下面這個選擇器是很低效的:html body ul li a{});
想清楚你爲何這樣寫;
CSS3的效率問題(CSS3選擇器(好比:nth-child)可以漂亮的定位咱們想要的元素,又能保證咱們的CSS整潔易讀。可是這些神奇的選擇器會浪費不少的瀏覽器資源。);
咱們知道#ID速度是最快的,那麼咱們都用ID,是否是很快。可是咱們不該該爲了效率而犧牲可讀性和可維護性。
LESS&Sass
LESS是受Sass啓發而開發的工具,它列出了以下開發的理由:
爲何要開發一個Sass的替代品呢?緣由很簡單:首先是語法。Sass的一個關鍵特性是縮進式的語法,這種語法能夠產生柱式外觀的代碼。可是你須要花費時間學習一門新的語法以及從新構建你如今的樣式表。LESS給CSS帶來了不少特性,使得LESS可以和CSS無縫地緊密結合在一塊兒。所以,你能夠平滑地由CSS遷移到LESS,若是你只是對使用變量或者操做感興趣的話,你不須要學習一整門全新的語言。
StylusStylus相對前二者較新,能夠看官方文檔介紹的功能。
來自NodeJS社區,因此和NodeJS走得很近,與JavaScript聯繫很是緊密。還有專門JavaScript API:http://learnboost.github.io/stylus/docs/js.html;
支持Ruby之類等等框架;
更多更強大的支持和功能總結:Sass看起來在提供的特性上佔有優點,可是LESS可以讓開發者平滑地從現存CSS文件過渡到LESS,而不須要像Sass那樣須要將CSS文件轉換成Sass格式。Stylus功能上更爲強壯,和js聯繫更加緊密。
特殊字體使用方法不是很清楚的同窗能夠看看這篇文章:CSS教程 @font-face 網頁中嵌入特殊字體方法
所謂的標準字體是多數機器上都會有的,或者即便沒有也能夠由默認字體替代的字體。
方法:
用圖片代替
web fonts在線字庫,如Google Webfonts,Typekit等等;http://www.chinaz.com/free/2012/0815/269267.shtml;
@font-face,Webfonts(字體服務例如:Google Webfonts,Typekit等等。)
從後往前判斷。瀏覽器先產生一個元素集合,這個集合每每由最後一個部分的索引產生(若是沒有索引就是全部元素的集合)。而後向上匹配,若是不符合上一個部分,就把元素從集合中刪除,直到真個選擇器都匹配完,還在集合中的元素就匹配這個選擇器了。
舉個例子,有選擇器:
1
|
body.ready#wrapper>.lol
233
|
先把全部class中有lol233的元素拿出來組成一個集合,而後上一層,對每個集合中的元素,若是元素的parent id不爲#wrapper則把元素從集合中刪去。再向上,從這個元素的父元素開始向上找,沒有找到一個tagName爲body且class中有ready的元素,就把原來的元素從集合中刪去。至此這個選擇器匹配結束,全部還在集合中的元素知足。大致就是這樣,不過瀏覽器還會有一些奇怪的優化。爲何從後往前匹配由於效率和文檔流的解析方向。效率沒必要說,找元素的父親和以前的兄弟比遍歷所喲兒子快並且方便。關於文檔流的解析方向,是由於如今的CSS,一個元素只要肯定了這個元素在文檔流以前出現過的全部元素,就能肯定他的匹配狀況。應用在即便html沒有載入完成,瀏覽器也能根據已經載入的這一部分信息徹底肯定出現過的元素的屬性。爲何是用集合主要也仍是效率。基於CSS Rule數量遠遠小於元素數量的假設和索引的運用,遍歷每一條CSS Rule經過集合篩選,比遍歷每個元素再遍歷每一條Rule匹配要快得多。
關於盒模型請看文章CSS基礎(四):盒模型
請解釋一下*{box-sizing:border-box;} 的做用,而且說明使用它有什麼好處?
說到IE的bug,在IE6之前的版本中,IE對盒模型的解析出現一些問題,跟其它瀏覽器不一樣,將border與padding都包含在width以內。而另一些瀏覽器則與它相反,是不包括border和padding的。
在咱們開發的過程當中會發現,有時候,若是對頁面中的大區域進行設置時,將border、padding計算到width和height以內,反而更靈活。但W3C的CSS2.1規範卻規定了他們並不能被包含其中。考慮到這個問題,css3中引入了一個新的屬性:box-sizing,它具備「content-box」和」border-box「兩個值。
具體文章:CSS3盒模型——box-sizing
1
|
box-sizing:content-box
|
當咱們設置box-sizing:content-box;時,瀏覽器對盒模型的解釋聽從咱們以前認識到的W3C標準,當它定義width和height時,它的寬度不包括border和padding。
1
|
box-sizing:border-box
|
當咱們設置box-sizing:border-box;時,瀏覽器對盒模型的解釋與IE6以前的版本相同,當它定義width和height時,border和padding則是被包含在寬高以內的。內容的寬和高能夠經過定義的「width」和「height」減去相應方向的「padding」和「border」的寬度獲得。內容的寬和高必須保證不能爲負,必要時將自動增大該元素border box的尺寸以使其內容的寬或高最小爲0。
display屬性的值列表以下:
參考文章:CSS基礎(五):定位技術
inline:此元素會被顯示爲內聯元素,元素先後沒有換行符。
inline-block:行內塊元素。
若是有,請問是哪一套?若是能夠,你如何改善CSS框架?
請問你有使用過CSS Flexbox或者Grid specs嗎?若是有,請問在性能和效率的方面你是怎麼看的?
JavaScript事件代理則是一種簡單的技巧,經過它你能夠把事件處理器添加到一個父級元素上,這樣就避免了把事件處理器添加到多個子級元素上。當咱們須要對不少元素添加事件的時候,能夠經過將事件添加到它們的父節點而將事件委託給父節點來觸發處理函數。這主要得益於瀏覽器的事件冒泡機制。事件代理用到了兩個在JavaSciprt事件中常被忽略的特性:事件冒泡以及目標元素。
1
2
3
4
|
function
getEventTarget(e) {
e=e||window.event;
return
e.target||e.srcElement;
}
|
this永遠指向函數運行時所在的對象,而不是函數被建立時所在的對象。匿名函數或不處於任何對象中的函數指向window 。
1.若是是call,apply,with,指定的this是誰,就是誰。
2.普通的函數調用,函數被誰調用,this就是誰。
如下代碼展現了JS引擎如何查找屬性:
1
2
3
4
5
6
7
8
9
|
function
getProperty(obj,prop) {
if
(obj.hasOwnProperty(prop)) {
return
obj[prop];
}
else
if
(obj.__proto__!==
null
) {
return
getProperty(obj.__proto__,prop);
}
else
{
return
undefined;
}
}
|
結合本身的項目經驗進行講述。(chrome使用技巧)
請看文章JavaScript之模塊化編程
散列表(也叫哈希表),是根據關鍵碼值直接進行訪問的數據結構。也就是說,它經過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫作散列函數,存放記錄的數組叫作散列表。
要作哪些改動使它變成IIFE?
由於在解析器解析全局的function或者function內部function關鍵字的時候,默認是認爲function聲明,而不是function表達式,若是你不顯示告訴編譯器,它默認會聲明成一個缺乏名字的function,而且拋出一個語法錯誤信息,由於function聲明須要一個名字。
1
2
3
4
5
|
var
foo =
function
() {
// doSomeThing.
};
foo();
|
JavaScript的最第一版本是這樣區分的:null是一個表示"無"的對象,轉爲數值時爲0;undefined是一個表示"無"的原始值,轉爲數值時爲NaN。
可是,上面這樣的區分,在實踐中很快就被證實不可行。目前,null和undefined基本是同義的,只有一些細微的差異。
null表示"沒有對象",即該處不該該有值。典型用法是:
用來初始化一個變量,這個變量可能被賦值爲一個對象。
用來和一個已經初始化的變量比較,這個變量能夠是也能夠不是一個對象。
當函數的參數指望是對象時,被用做參數傳入。
當函數的返回值指望是對象時,被用做返回值傳出。
做爲對象原型鏈的終點。
undefined表示"缺乏值",就是此處應該有一個值,可是尚未定義。典型用法是:
變量被聲明瞭,但沒有賦值時,就等於undefined。
調用函數時,應該提供的參數沒有提供,該參數等於undefined。
對象沒有賦值的屬性,該屬性的值爲undefined。
函數沒有返回值時,默認返回undefined。
null:表示無值;undefined:表示一個未聲明的變量,或已聲明但沒有賦值的變量,或一個並不存在的對象屬性。
==運算符將二者看做相等。若是要區分二者,要使用===或typeof運算符。
如下是不正確的用法:
1
2
3
4
|
var
exp = undefined;
if
(exp == undefined){
alert(
"undefined"
);
}
|
exp爲null時,也會獲得與undefined相同的結果,雖然null和undefined不同。注意:要同時判斷undefined和null時可以使用本法。
typeof返回的是字符串,有六種可能:"number"、"string"、"boolean"、"object"、"function"、"undefined"。
如下是正確的用法:
1
2
3
4
|
var
exp = undefined;
if
(
typeof
(exp) == undefined){
alert(
"undefined"
);
}
|
JS中如何判斷null?
如下是不正確的用法:
1
2
3
4
|
var
exp =
null
;
if
(exp ==
null
){
alert(
"is null"
);
}
|
exp爲undefined時,也會獲得與null相同的結果,雖然null和undefined不同。注意:要同時判斷null和undefined時可以使用本法。
1
2
3
4
|
var
exp=
null
;
if
(!exp){
alert(
"is null"
);
}
|
若是exp爲undefined或者數字零,也會獲得與null相同的結果,雖然null和兩者不同。注意:要同時判斷null、undefined和數字零時可以使用本法。
1
2
3
4
|
var
exp =
null
;
if
(
typeof
(exp) ==
"null"
){
alert(
"is null"
);
}
|
爲了向下兼容,exp爲null時,typeof總返回object。這種方式也不太好。
如下是正確的用法:
1
2
3
4
|
var
exp =
null
;
if
(!exp&&
typeof
(exp) !=
"undefined"
&& exp != 0){
alert(
"is null"
);
}
|
包就是可以讀取其餘函數內部變量的函數。因爲在Javascript語言中,只有函數內部的子函數才能讀取局部變量,所以能夠把閉包簡單理解成「定義在一個函數內部的函數」。
因此,在本質上,閉包就是將函數內部和函數外部鏈接起來的一座橋樑。閉包能夠用在許多地方。它的最大用處有兩個,一個是前面提到的能夠讀取函數內部的變量,另外一個就是讓這些變量的值始終保持在內存中。
使用閉包的注意點:
因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露。解決方法是,在退出函數以前,將不使用的局部變量所有刪除。
閉包會在父函數外部,改變父函數內部變量的值。因此,若是你把父函數看成對象(object)使用,把閉包看成它的公用方法(Public Method),把內部變量看成它的私有屬性(private value),這時必定要當心,不要隨便改變父函數內部變量的值。
關於閉包,參考文章:
自執行函數,用閉包模擬私有變量、特權函數等。
若是有提到無污染的命名空間,能夠考慮加分。
若是你的模塊沒有本身的命名空間會怎麼樣?
請看文章-JavaScript之模塊化編程 和JavaScript之命名空間模式 淺析
請看文章-JavaScript之模塊化編程和Javascript之對象的繼承
ECMA-262 把本地對象(native object)定義爲「獨立於宿主環境的 ECMAScript 實現提供的對象」。
「本地對象」包含哪些內容:Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError。
由此能夠看出,簡單來講,本地對象就是 ECMA-262 定義的類(引用類型)。
ECMA-262 把內置對象(built-in object)定義爲「由 ECMAScript 實現提供的、獨立於宿主環境的全部對象,在 ECMAScript 程序開始執行時出現」。這意味着開發者沒必要明確實例化內置對象,它已被實例化了。
一樣是「獨立於宿主環境」。根據定義咱們彷佛很難分清「內置對象」與「本地對象」的區別。而ECMA-262 只定義了兩個內置對象,即 Global 和 Math (它們也是本地對象,根據定義,每一個內置對象都是本地對象)。如此就能夠理解了。內置對象是本地對象的一種。
何爲「宿主對象」?主要在這個「宿主」的概念上,ECMAScript中的「宿主」固然就是咱們網頁的運行環境,即「操做系統」和「瀏覽器」。
全部非本地對象都是宿主對象(host object),即由 ECMAScript 實現的宿主環境提供的對象。全部的BOM和DOM都是宿主對象。由於其對於不一樣的「宿主」環境所展現的內容不一樣。其實說白了就是,ECMAScript官方未定義的對象都屬於宿主對象,由於其未定義的對象大多數是本身經過ECMAScript程序建立的對象。
call方法:
語法:call(thisObj,Object)
定義:調用一個對象的一個方法,以另外一個對象替換當前對象。
說明:call 方法能夠用來代替另外一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變爲由 thisObj 指定的新對象。 若是沒有提供 thisObj 參數,那麼 Global 對象被用做 thisObj。
apply方法:
語法:apply(thisObj,[argArray])
定義:應用某一對象的一個方法,用另外一個對象替換當前對象。
說明:若是 argArray 不是一個有效的數組或者不是 arguments 對象,那麼將致使一個 TypeError。若是沒有提供 argArray 和 thisObj 任何一個參數,那麼 Global 對象將被用做 thisObj, 而且沒法被傳遞任何參數。
對於apply和call二者在做用上是相同的,但二者在參數上有如下區別:
對於第一個參數意義都同樣,但對第二個參數:apply傳入的是一個參數數組,也就是將多個參數組合成爲一個數組傳入,而call則做爲call的參數傳入(從第二個參數開始)。如 func.call(func1,var1,var2,var3)對應的apply寫法爲:func.apply(func1,[var1,var2,var3])同時使用apply的好處是能夠直接將當前函數的arguments對象做爲apply的第二個參數傳入。
請看文章JavaScript之高效編程 及JavaScript編碼風格指南。
原型鏈等。
大多數生成的廣告代碼依舊使用document.write(),雖然這種用法會讓人很不爽。
特性檢測:爲特定瀏覽器的特性進行測試,並僅當特性存在時便可應用特性。
User-Agent檢測:最先的瀏覽器嗅探即用戶代理檢測,服務端(以及後來的客戶端)根據UA字符串屏蔽某些特定的瀏覽器查看網站內容。
特性推斷:嘗試使用多個特性但僅驗證了其中之一。根據一個特性的存在推斷另外一個特性是否存在。問題是,推斷是假設並不是事實,並且可能致使可維護性的問題。
請參考文章AJAX工做原理。
JSONP (JSON with Padding)是一個簡單高效的跨域方式,HTML中的script標籤能夠加載並執行其餘域的javascript,因而咱們能夠經過script標記來動態加載其餘域的資源。例如我要從域A的頁面pageA加載域B的數據,那麼在域B的頁面pageB中我以JavaScript的形式聲明pageA須要的數據,而後在 pageA中用script標籤把pageB加載進來,那麼pageB中的腳本就會得以執行。JSONP在此基礎上加入了回調函數,pageB加載完以後會執行pageA中定義的函數,所須要的數據會以參數的形式傳遞給該函數。JSONP易於實現,可是也會存在一些安全隱患,若是第三方的腳本隨意地執行,那麼它就能夠篡改頁面內容,截獲敏感數據。可是在受信任的雙方傳遞數據,JSONP是很是合適的選擇。
AJAX是不跨域的,而JSONP是一個是跨域的,還有就是兩者接收參數形式不同!
若有使用過,請談談你都使用過哪些庫,好比Mustache.js,Handlebars等等。
在JS裏定義的變量,存在於做用域鏈裏,而在函數執行時會先把變量的聲明進行提高,僅僅是把聲明進行了提高,而其值的定義還在原來位置。示例以下:
1
2
3
4
5
6
7
|
var
test =
function
() {
console.log(name);
// 輸出:undefined
var
name =
"jeri"
;
console.log(name);
// 輸出:jeri
}
test();
|
上面代碼與下面代碼等價
1
2
3
4
5
6
7
8
|
var
test =
function
() {
var
name;
console.log(name);
// 輸出:undefined
name =
"jeri"
;
console.log(name);
// 輸出:jeri
}
test();
|
由以上代碼可知,在函數執行時,把變量的聲明提高到了函數頂部,而其值定義依然在原來位置。
冒泡型事件:事件按照從最特定的事件目標到最不特定的事件目標(document對象)的順序觸發。
捕獲型事件:事件從最不精確的對象(document 對象)開始觸發,而後到最精確(也能夠在窗口級別捕獲事件,不過必須由開發人員特別指定)。
支持W3C標準的瀏覽器在添加事件時用addEventListener(event,fn,useCapture)方法,基中第3個參數useCapture是一個Boolean值,用來設置事件是在事件捕獲時執行,仍是事件冒泡時執行。
而不兼容W3C的瀏覽器(IE)用attachEvent()方法,此方法沒有相關設置,不過IE的事件模型默認是在事件冒泡時執行的,也就是在useCapture等於false的時候執行,因此把在處理事件時把useCapture設置爲false是比較安全,也實現兼容瀏覽器的效果。
Property:屬性,全部的HTML元素都由HTMLElement類型表示,HTMLElement類型直接繼承自Element並添加了一些屬性,添加的這些屬性分別對應於每一個HTML元素都有下面的這5個標準特性: id,title,lang,dir,className。DOM節點是一個對象,所以,他能夠和其餘的JavaScript對象同樣添加自定義的屬性以及方法。property的值能夠是任何的數據類型,對大小寫敏感,自定義的property不會出如今html代碼中,只存在js中。
Attribute:特性,區別於property,attribute只能是字符串,大小寫不敏感,出如今innerHTML中,經過類數組attributes能夠羅列全部的attribute。
標準的 DOM properties 與 attributes 是同步的。公認的(非自定義的)特性會被以屬性的形式添加到DOM對象中。如,id,align,style等,這時候操做property或者使用操做特性的DOM方法如getAttribute()均可以操做屬性。不過傳遞給getAttribute()的特性名與實際的特性名相同。所以對於class的特性值獲取的時候要傳入「class」。
1).對於有些標準的特性的操做,getAttribute與點號(.)獲取的值存在差別性。如href,src,value,style,onclick等事件處理程序。
2).href:getAttribute獲取的是href的實際值,而點號獲取的是完整的url,存在瀏覽器差別。
頁面加載完成有兩種事件,一是ready,表示文檔結構已經加載完成(不包含圖片等非文字媒體文件),二是onload,指示頁面包含圖片等文件在內的全部元素都加載完成。
首先,== equality 等同,=== identity 恆等。 ==, 兩邊值類型不一樣的時候,要先進行類型轉換,再比較。 ===,不作類型轉換,類型不一樣的必定不等。
先說 ===,這個比較簡單。下面的規則用來判斷兩個值是否===相等:
若是類型不一樣,就[不相等]
若是兩個都是數值,而且是同一個值,那麼[相等];(!例外)的是,若是其中至少一個是NaN,那麼[不相等]。(判斷一個值是不是NaN,只能用isNaN()來判斷)
若是兩個都是字符串,每一個位置的字符都同樣,那麼[相等];不然[不相等]。
若是兩個值都是true,或者都是false,那麼[相等]。
若是兩個值都引用同一個對象或函數,那麼[相等];不然[不相等]。
若是兩個值都是null,或者都是undefined,那麼[相等]。
再說 ==,根據如下規則:
若是兩個值類型相同,進行 === 比較。
若是兩個值類型不一樣,他們可能相等。根據下面規則進行類型轉換再比較:
若是一個是null、一個是undefined,那麼[相等]。
若是一個是字符串,一個是數值,把字符串轉換成數值再進行比較。
若是任一值是 true,把它轉換成 1 再比較;若是任一值是 false,把它轉換成 0 再比較。
若是一個是對象,另外一個是數值或字符串,把對象轉換成基礎類型的值再比較。對象轉換成基礎類型,利用它的toString或者valueOf方法。js核心內置類,會嘗試valueOf先於toString;例外的是Date,Date利用的是toString轉換。非js核心的對象,令說(比較麻煩,我也不大懂)
任何其餘組合,都[不相等]。
如下函數把獲取一個key的參數。
1
2
3
4
5
6
7
8
9
10
11
12
|
function
parseQueryString ( name ){
name = name.replace(/[\[]/,
"\\\["
);
var
regexS =
"[\\?&]"
+name+
"=([^&#]*)"
;
var
regex =
new
RegExp( regexS );
var
results = regex.exec( window.location.href );
if
(results ==
null
) {
return
""
;
}
else
{
return
results[1];
}
}
|
在客戶端編程語言中,如javascript和 ActionScript,同源策略是一個很重要的安全理念,它在保證數據的安全性方面有着重要的意義。同源策略規定跨域之間的腳本是隔離的,一個域的腳本不能訪問和操做另一個域的絕大部分屬性和方法。那麼什麼叫相同域,什麼叫不一樣的域呢?當兩個域具備相同的協議, 相同的端口,相同的host,那麼咱們就能夠認爲它們是相同的域。同源策略還應該對一些特殊狀況作處理,好比限制file協議下腳本的訪問權限。本地的HTML文件在瀏覽器中是經過file協議打開的,若是腳本能經過file協議訪問到硬盤上其它任意文件,就會出現安全隱患,目前IE8還有這樣的隱患。
關於繼承請看文章JavaScript之對象的繼承。
三元表達式:? :。三元--三個操做對象。
在表達式boolean-exp ? value0 : value1 中,若是「布爾表達式」的結果爲true,就計算「value0」,並且這個計算結果也就是操做符最終產生的值。若是「布爾表達式」的結果爲false,就計算「value1」,一樣,它的結果也就成爲了操做符最終產生的值。
在函數代碼中,使用特殊對象 arguments,開發者無需明確指出參數名,經過使用下標就能夠訪問相應的參數。
arguments雖然有一些數組的性質,但其並不是真正的數組,只是一個類數組對象。其並無數組的不少方法,不能像真正的數組那樣調用.jion(),.concat(),.pop()等方法。
在代碼中出現表達式-"use strict"; 意味着代碼按照嚴格模式解析,這種模式使得Javascript在更嚴格的條件下運行。
好處:
消除Javascript語法的一些不合理、不嚴謹之處,減小一些怪異行爲;
消除代碼運行的一些不安全之處,保證代碼運行的安全;
提升編譯器效率,增長運行速度;
爲將來新版本的Javascript作好鋪墊。
壞處:
一樣的代碼,在"嚴格模式"中,可能會有不同的運行結果;一些在"正常模式"下能夠運行的語句,在"嚴格模式"下將不能運行。
jQuery方法連接。直到如今,咱們都是一次寫一條jQuery語句(一條接着另外一條)。不過,有一種名爲連接(chaining)的技術,容許咱們在相同的元素上運行多條jQuery命令,一條接着另外一條。
提示:這樣的話,瀏覽器就沒必要屢次查找相同的元素。
如需連接一個動做,您只需簡單地把該動做追加到以前的動做上。
開發網站的過程當中,咱們常常遇到某些耗時很長的javascript操做。其中,既有異步的操做(好比ajax讀取服務器數據),也有同步的操做(好比遍歷一個大型數組),它們都不是當即能獲得結果的。
一般的作法是,爲它們指定回調函數(callback)。即事先規定,一旦它們運行結束,應該調用哪些函數。
可是,在回調函數方面,jQuery的功能很是弱。爲了改變這一點,jQuery開發團隊就設計了deferred對象。
簡單說,deferred對象就是jQuery的回調函數解決方案。在英語中,defer的意思是"延遲",因此deferred對象的含義就是"延遲"到將來某個點再執行。
例若有一段HTML代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<
div
id
=
"content"
>
<
form
method
=
"post"
action
=
"#"
>
<
h2
>交通訊號燈</
h2
>
<
ul
id
=
"traffic_light"
>
<
li
>
<
input
type
=
"radio"
class
=
"on"
name
=
"light"
value
=
"red"
/>紅色
</
li
>
<
li
>
<
input
type
=
"radio"
class
=
"off"
name
=
"light"
value
=
"yellow"
/>黃色
</
li
>
<
li
>
<
input
type
=
"radio"
class
=
"off"
name
=
"light"
value
=
"green"
/>綠色
</
li
>
</
ul
>
<
input
class
=
"button"
id
=
"traffic_button"
type
=
"submit"
value
=
"Go"
/>
</
form
>
</
div
>
|
好比須要選擇紅綠單選框,那麼能夠使用一個tag name來限制(修飾)class,以下所示:var active_light=$(「input.on」);固然也能夠結合就近的ID,以下所示:var active_light=$(「#traffic_light input.on」); 若是採用下面的選擇器,那麼效率是低效的。var traffic_button=$(「#content.button」);由於button已經有ID了,咱們能夠直接使用ID選擇器。以下所示:var traffic_button=$(「#traffic_button」);固然這只是對於單一的元素來說。若是你須要選擇多個元素,這必然會涉及到DOM遍歷和循環,爲了提升性能,建議從最近的ID開始繼承。以下所示:var traffic_lights=$(「#traffic_light input」);
跟ID選擇器累時,由於它來自原生的getElementsByTagName()方法。繼續看剛纔那段HTML代碼:
在使用tag來修飾class的時候,咱們須要注意如下幾點:(1)不要使用tag來修飾ID,以下所示:var content=$(「div#content」);這樣一來,選擇器會先遍歷全部的div元素,而後匹配#content。(好像jQuery從1.3.1開始改變了選擇器核心後,不存在這個問題了。暫時沒法考證。)(2)不要多此一舉的使用ID來修飾ID,以下所示:var traffic_light=$(「#content#traffic_light」);
下面是一個jQuery新手寫的一段代碼:
1
2
3
4
|
$(
"#traffic_light input.on"
).bind(
"click"
,
function
(){});
$(
"#traffic_light input.on"
).css(
"border"
,
"1px dashed yellow"
);
$(
"#traffic_light input.on"
).css(
"background-color"
,
"orange"
);
$(
"#traffic_light input.on"
).fadeIn(
"slow"
);
|
但切記不要這麼作。咱們應該先將對象緩存進一個變量而後再操做,以下所示:
記住,永遠不要讓相同的選擇器在你的代碼裏出現屢次.注:(1)爲了區分普通的JavaScript對象和jQuery對象,能夠在變量首字母前加上$符號。(2)上面代碼能夠使用jQuery的鏈式操做加以改善。以下所示:
1
2
3
4
5
6
|
var
$active_light = $(
"#traffic_light input.on"
);
$active_light.bind(
"click"
,
function
(){})
.css(
"border"
,
"1px dashed yellow"
)
.css(
"background-color"
,
"orange"
)
.fadeIn(
"slow"
);
|
以下代碼所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// 在全局範圍定義一個對象(例如:window對象)
window.$my = {
head:$(
"head"
),
trafficLight:$(
"#trafficLight"
),
trafficButton:$(
"#trafficButton"
)
};
function
doSomething(){
// 如今你能夠引用存儲的結果並操做它們
var
script=document.createElement(
"script"
);
$my.head.append(script);
// 當你在函數內部操做是,能夠繼續將查詢存入全局對象中去.
$my.coolResults=$(
"#some_ul li"
);
$my.otherResults=$(
"#some_table td"
);
// 將全局函數做爲一個普通的jquery對象去使用.
$my.otherResults.css(
"border-color"
,
"red"
);
$my.trafficLight.css(
"border-color"
,
"green"
);
}
// 你也能夠在其餘函數中使用它.
|
這裏的基本思想是在內存中創建你確實想要的東西,而後更新DOM。這並非一個jQuery最佳實踐,但必須進行有效的JavaScript操做。直接的DOM操做速度很慢。例如,你想動態的建立一組列表元素,千萬不要這樣作,以下所示:對直接的DOM操做進行限制。
1
2
3
4
5
6
|
var
top_100_list = [];
// 假設這裏是100個獨一無二的字符串
var
$mylist = $(
"#mylist"
);
// jQuery選擇到<ul>元素
for
(
var
i=0,l=top_100_list.length;i<l;i++) {
$mylist.append(
"<li>"
+ top_100_list[i] +
"</li>"
);
}
|
咱們應該將整套元素字符串在插入進dom中以前先所有建立好,以下所示:
1
2
3
4
5
|
$(
"#entryform input"
).bind(
"focus"
,
function
() {
$(
this
).addClass(
"selected"
);
}).bind(
"blur"
,
function
(){
$(
this
).removeClass(
"selected"
);
});
|
當咱們須要給多個元素調用同個函數時這點會頗有用。代替這種效率不好的多元素事件監聽的方法就是,你只需向它們的父節點綁定一次。好比,咱們要爲一個擁有不少輸入框的表單綁定這樣的行爲:當輸入框被選中時爲它添加一個class傳統的作法是,直接選中input,而後綁定focus等,以下所示:
1
2
3
4
5
6
7
|
$(
"#entryform"
).bind(
"focus"
,
function
(e) {
var
$cell = $(e.target);
// e.target捕捉到觸發的目標元素
$cell.addClass(
"selected"
);
}).bind(
"blur"
,
function
(e) {
var
$cell = $(e.target);
$cell.removeClass(
"selected"
);
});
|
固然上面代碼能幫咱們完成相應的任務,但若是你要尋求更高效的方法,請使用以下代碼:
經過在父級監聽獲取焦點和失去焦點的事件,對目標元素進行操做。在上面代碼中,父級元素扮演了一個調度員的角色,它能夠基於目標元素綁定事件。若是你發現你給不少元素綁定了同一個事件監聽,那麼如今的你確定知道哪裏作錯了。
jQuery對於開發者來講有一個很誘人的東西,能夠把任何東西掛到$(document).ready下。儘管$(document).rady確實頗有用,它能夠在頁面渲染時,其它元素還沒下載完成就執行。若是你發現你的頁面一直是載入中的狀態,頗有可能就是$(document).ready函數引發的。你能夠經過將jQuery函數綁定到$(window).load事件的方法來減小頁面載入時的cpu使用率。它會在全部的html(包括iframe)被下載完成後執行。一些特效的功能,例如拖放,視覺特效和動畫,預載入隱藏圖像等等,都是適合這種技術的場合。
在線壓縮地址:http://dean.edwards.name/packer/壓縮以前,請保證你的代碼的規範性,不然可能失敗,致使Js錯誤。
前面性能優化已經說過,ID選擇器的速度是最快的。因此在HTML代碼中,能使用ID的儘可能使用ID來代替class。看下面的一個例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// 建立一個list
var
$myList = $(
'#myList'
);
var
myListItems =
'<ul>'
;
for
(
var
i = 0; i < 1000; i ++) {
myListItems +=
'<li class = "listItem'
+i+
'">This is a list item</li>'
;
// 這裏使用的是class
}
myListItems +=
'</ul>'
;
$myList.html(myListItems);
// 選擇每個li
for
(
var
i = 0; i<1000; i++) {
var
selectedItem = $(
'.listItem'
+ i);
}
|
在上段代碼中,選擇每一個li總共只用了61毫秒,相比class的方式,將近快了100倍。 在代碼最後,選擇每一個li的過程當中,總共用了5066毫秒,超過5秒了。接着咱們作一個對比,用ID代替class:
jQuery選擇器中有一個這樣的選擇器,它能指定上下文。jQuery(expression,context);經過它,能縮小選擇器在DOM中搜索的範圍,達到節省時間,提升效率。普通方式:$(‘.myDiv’)改進方式:$(‘.myDiv’,$(「#listItem」))。
這是jQuery1.3.1版本以後增長的方法,這個方法的功能就是爲新增的DOM元素動態綁定事件。但對於效率來講,這個方法比較佔用資源。因此請儘可能不要使用它。例若有這麼一段代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<
script
type
=
"text/javascript"
>
$(function(){
$("p").click(function(){
alert($(this).text());
});
$("button").click(function(){
$("<
p
>this is second p</
p
>").appendTo("body");
});
})
</
script
>
<
body
>
<
p
>this is first p</
p
>
<
button
>add</
button
>
</
body
>
|
運行後,你會發現新增的p元素,並沒用被綁定click事件。你能夠改爲.live(「click」)方式解決此問題,代碼以下:
1
2
3
4
5
6
7
8
9
10
|
$(
function
() {
$(
"p"
).live(
"click"
,
function
() {
// 改爲live方式
alert($(
this
).text());
});
$(
"button"
).click(
function
() {
$(
"<p>this is second p</p>"
).appendTo(
"body"
);
});
})
|
但我並不建議你們這麼作,我想用另外一種方式去解決這個問題,代碼以下:
1
2
3
4
5
6
7
8
9
10
11
12
|
$(
function
() {
$(
"p"
).click(
function
() {
alert($(
this
).text());
});
$(
"button"
).click(
function
() {
$(
"<p>this is second p</p>"
).click(
function
() {
// 爲新增的元素從新綁定一次
alert($(
this
).text());
}).appendTo(
"body"
);
});
})
|
雖然我把綁定事件從新寫了一次,代碼多了點,但這種方式的效率明顯高於live()方式,特別是在頻繁的DOM操做中,這點很是明顯。
在官方的API上是這樣描述end()方法的:「回到最近的一個"破壞性"操做以前。即,將匹配的元素列表變爲前一次的狀態。」;看樣子好像是找到最後一次操做的元素的上一元素,在以下的例子中:html代碼:
複製代碼代碼以下:
1
2
|
<
div
>測試內容1</
div
>
<
div
>測試內容2</
div
>
|
jQuery代碼:
複製代碼代碼以下:
1
|
$(
'<p>新增內容</p>'
).appendTo(
'div'
).addClass(
'c1'
).end().addClass(
'c2'
);
|
複製代碼代碼以下:
1
2
3
4
5
6
|
<
div
>測試內容1
<
p
class
=
"c1 c2"
>新增內容</
p
>
</
div
>
<
div
>測試內容2
<
p
class
=
"c1"
>新增內容</
p
>
</
div
>
|
這裏我就有一點不太明白了,怎麼只有第一個<p>標籤有兩個樣式,end()方法後返回的是什麼,在火狐裏添加了監控,
獲得以下結果:
$('<p>新增內容</p>').appendTo('div')返回的是:[p,p]對象數組,即新增後的兩個p標籤;
$('<p>新增內容</p>').appendTo('div').addClass('c1')返回的是:[p.c1,p.c1]對象數組,即添加了c1類樣式後的p對象數組;
$('<p>新增內容</p>').appendTo('div').addClass('c1').end()返回的是[p.c1],是第1個<div>中的<p>,在2操做中,最後「破壞」的是第2個<div>中的<p>,因此他的前一次操做的對象是第1個<div>中的<p>,返回的就是它;
$('<p>新增內容</p>').appendTo('div').addClass('c1').end().addClass('c2')返回的仍然是第1個<div>中的<p>;
如今算是有點明白了,關鍵是要搞清楚最後一次操做的元素的上一元素是什麼。
任何做爲type參數的字符串都是合法的;若是一個字符串不是原生的JavaScript事件名,那麼這個事件處理函數會綁定到一個自定義事件上。這些自定義事件絕對不會由瀏覽器觸發,但能夠經過使用.trigger()或者.triggerHandler()在其餘代碼中手動觸發。若是type參數的字符串中包含一個點(.)字符,那麼這個事件就看作是有命名空間的了。這個點字符就用來分隔事件和他的命名空間。舉例來講,若是執行.bind('click.name',handler),那麼字符串中的click是事件類型,而字符串name就是命名空間。命名空間容許咱們取消綁定或者觸發一些特定類型的事件,而不用觸發別的事件。參考unbind()來獲取更多信息。
jQuery的bind/unbind方法應該說使用很簡單,並且大多數時候可能並不會用到,取而代之的是直接用click/keydown之類的事件名風格的方法來作事件綁定操做。
但假設以下狀況:須要在運行時根據用戶交互的結果進行不一樣click事件處理邏輯的綁定,於是理論上會無數次對某一個事件進行bind/unbind操做。但又但願unbind的時候只把本身綁上去的處理邏輯給釋放掉而不是全部其餘地方有可能的額外的同一事件綁定邏輯。這時候若是直接用.click()/.bind('click')加上.unbind('click')來進行重複綁定的話,被unbind掉的將是全部綁定在元素上的click處理邏輯,潛在會影響到該元素其餘第三方的行爲。
固然若是在bind的時候是顯示定義了function變量的話,能夠在unbind的時候提供function做爲第二個參數來指定只unbind其中一個處理邏輯,但實際應用中極可能會碰到各類進行匿名函數綁定的狀況。對於這種問題,jQuery的解決方案是使用事件綁定的命名空間。即在事件名稱後添加.something來區分本身這部分行爲邏輯範圍。
好比用.bind('click.myCustomRoutine',function(){...});一樣是把匿名函數綁定到click事件(你能夠用本身的命名空間屢次綁定不一樣的行爲方法上去),當unbind的時候用.unbind('click.myCustomRoutine')便可釋放全部綁定到.myCustomRoutine命名空間的click事件,而不會解除其餘經過.bind('click')或另外的命名空間所綁定的事件行爲。同時,使用命令空間還可讓你一次性unbind全部此命名空間下的自定義事件綁定,經過.unbind('.myCustomRoutine')便可。要注意的是,jQuery的命名空間並不支持多級空間。
由於在jQuery裏面,若是用.unbind('click.myCustomRoutine.myCustomSubone'),解除的是命名空間分別爲myCustomRoutine和myCustomSubone的兩個並列命名空間下的全部click事件,而不是"myCustomRoutine下的myCustomSubone子空間"。
選擇器(字符串),HTML(字符串),回調函數,HTML元素,對象,數組,元素數組,jQuery對象等。
jQuery中有個動畫隊列的機制。當咱們對一個對象添加屢次動畫效果時後添加的動做就會被放入這個動畫隊列中,等前面的動畫完成後再開始執行。但是用戶的操做每每都比動畫快,若是用戶對一個對象頻繁操做時不處理動畫隊列就會形成隊列堆積,影響到效果。jQuery中有stop這個方法能夠中止當前執行的動畫,而且它有兩個布爾參數,默認值都爲false。第一個參數爲true時會清空動畫隊列,第二個參數爲true時會瞬間完成掉當前動畫。因此,咱們常用obj.stop(true,true)來中止動畫。可是這還不夠!正如jQuery文檔中的說法,即便第二個參數爲true,也僅僅是把當前在執行的動畫跳轉到完成狀態。這時第一個參數若是也爲true,後面的隊列就會被清空。若是一個效果須要多個動畫同時處理,咱們僅完成其中的一個而把後面的隊列丟棄了,這就會出現意料以外的結果。
eq:返回是一個jquery對象做用是將匹配的元素集合縮減爲一個元素。這個元素在匹配元素集合中的位置變爲0,而集合長度變成1。
get:是一個html對象數組做用是取得其中一個匹配的元素。num表示取得第幾個匹配的元素。
在操縱DOM的語境中,document是根節點。如今咱們能夠較容易地說明.bind()、.live()和.delegate()的不一樣之處了。
.bind()
1
|
$(
'a'
).bind(
'click'
,
function
() {alert(
"That tickles!"
)});
|
這是最簡單的綁定方法了。JQuery掃描文檔找出全部的$(‘a’)元素,並把alert函數綁定到每一個元素的click事件上。
.live()
1
|
$(
'a'
).live(
'click'
,
function
() {alert(
"That tickles!"
)});
|
JQuery把alert函數綁定到$(document)元素上,並使用’click’和’a’做爲參數。任什麼時候候只要有事件冒泡到document節點上,它就查看該事件是不是一個click事件,以及該事件的目標元素與’a’這一CSS選擇器是否匹配,若是都是的話,則執行函數。
live方法還能夠被綁定到具體的元素(或context)而不是document上,像這樣:
1
|
$(
'a'
, $(
'#container'
)[0]).live(...);
|
.delegate()
1
|
$(
'#container'
).delegate(
'a'
,
'click'
,
function
() {alert(
"That tickles!"
)});
|
JQuery掃描文檔查找$(‘#container’),並使用click事件和’a’這一CSS選擇器做爲參數把alert函數綁定到$(‘#container’)上。任什麼時候候只要有事件冒泡到$(‘#container’)上,它就查看該事件是不是click事件,以及該事件的目標元素是否與CCS選擇器相匹配。若是兩種檢查的結果都爲真的話,它就執行函數。
能夠注意到,這一過程與.live()相似,可是其把處理程序綁定到具體的元素而非document這一根上。精明的JS’er們可能會作出這樣的結論,即$('a').live()==$(document).delegate('a'),是這樣嗎?嗯,不,不徹底是。
爲何.delegate()要比.live()好用?
基於幾個緣由,人們一般更願意選用jQuery的delegate方法而不是live方法。考慮下面的例子:
1
2
|
$(
'a'
).live(
'click'
,
function
(){blah()});
// 或者
$(document).delegate(
'a'
,
'click'
,
function
(){blah()});
|
速度
後者實際上要快過前者,由於前者首先要掃描整個的文檔查找全部的$(‘a’)元素,把它們存成jQuery對象。儘管live函數僅須要把’a’做爲串參數傳遞以用作以後的判斷,可是$()函數並未知道被連接的方法將會是.live()。而另外一方面,delegate方法僅須要查找並存儲$(document)元素。
一種尋求避開這一問題的方法是調用在$(document).ready()以外綁定的live,這樣它就會當即執行。在這種方式下,其會在DOM得到填充以前運行,所以就不會查找元素或是建立jQuery對象了。
靈活性和鏈能力
live函數也挺使人費解的。想一想看,它被鏈到$(‘a’)對象集上,但其其實是在$(document)對象上發生做用。因爲這個緣由,它可以試圖以一種嚇死人的方式來把方法鏈到自身上。實際上,我想說的是,以$.live(‘a’,…)這一形式做爲一種全局性的jQuery方法,live方法會更具意義一些。
僅支持CSS選擇器
最後一點,live方法有一個很是大的缺點,那就是它僅能針對直接的CSS選擇器作操做,這使得它變得很是的不靈活。
爲何選擇.live()或.delegate()而不是.bind()?
畢竟,bind看起來彷佛更加的明確和直接,難道不是嗎?嗯,有兩個緣由讓咱們更願意選擇delegate或live而不是bind:
爲了把處理程序附加到可能還未存在於DOM中的DOM元素之上。由於bind是直接把處理程序綁定到各個元素上,它不能把處理程序綁定到還未存在於頁面中的元素之上。
若是你運行了$(‘a’).bind(…),然後新的連接經由AJAX加入到了頁面中,則你的bind處理程序對於這些新加入的連接來講是無效的。而另外一方面live和delegate則是被綁定到另外一個祖先節點上,所以其對於任何目前或是未來存在於該祖先元素以內的元素都是有效的。
或者爲了把處理程序附加到單個元素上或是一小組元素之上,監聽後代元素上的事件而不是循環遍歷並把同一個函數逐個附加到DOM中的100個元素上。把處理程序附加到一個(或是一小組)祖先元素上而不是直接把處理程序附加到頁面中的全部元素上,這種作法帶來了性能上的好處。
中止傳播
最後一個我想作的提醒與事件傳播有關。一般狀況下,咱們能夠經過使用這樣的事件方法來終止處理函數的執行:
1
2
3
4
|
$(
'a'
).bind(
'click'
,
function
(e) {
e.preventDefault();
// 或者 e.stopPropagation();
});
|
不過,當咱們使用live或是delegate方法的時候,處理函數實際上並無在運行,須要等到事件冒泡處處理程序實際綁定的元素上時函數纔會運行。而到此時爲止,咱們的其餘的來自.bind()的處理函數早已運行了。
Jquery爲開發插件提供了兩個方法,分別是:
1
2
|
$.extend(obj);
$.fn.extend(obj);
|
1.那麼這兩個分別是什麼意思?
$.extend(obj);是爲了擴展jquery自己,爲類添加新的方法。
$.fn.extend(obj);給JQUERY對象添加方法。
2.$.fn中的fn是什麼意思,實際上是prototype,即$.fn=$.prototype;
具體用法請看下面的例子:
1
2
3
4
5
6
7
8
|
$.extend({
add:
function
(a, b) {
return
a+b;
}
})
$.add(5,8);
// return 13
|
注意沒有,這邊的調用直接調用,前面不用任何對象。直接$.+方法名
$.fn.extend(obj);對prototype進行擴展,爲jquery類添加成員函數,jquery類的實例能夠使用這個成員函數。
1
2
3
4
5
6
7
8
9
10
11
|
$.fn.extend({
clickwhile:
function
(){
$(
this
).click(
function
(){
alert($(
this
).val())
})
}
})
$(
'input'
).clickwhile();
// 當點擊輸入框會彈出該對象的Value值
|
注意調用時候前面是有對象的。即$('input')這麼個東西。
使用循環、遞歸都能寫出函數。
當N取值很大時,應該考慮把數值轉化爲字符串再進行運算。大數乘法再轉化爲大數加法運算,其具體算法應該有很多C語言實現,能夠參考一下。
答案:"goh angasal a m'i";
答案:"bar"只有window.foo爲假時的纔是上面答案,不然就是它自己的值。
1
2
3
4
5
6
|
var
foo=
"Hello"
;
(
function
(){
var
bar=
"World"
;
alert(foo+bar);
})();
alert(foo+bar);
|
答案:"Hello World"和ReferenceError:bar is not defined
答案:2
若是有對web前端感興趣前端程序員,,可加入咱們的web前端技術學習羣的61852,2268,裏面免費送前端的零基礎教程噢!
寫在最後:
不少人都知道我是學全棧的,都天真的覺得我有全套的前端、網頁製做等視頻學習資料。我想說大家是對的,個人確有前端的全套視頻資料。
下圖就是:
有趣的問題: