1. 程式人生 > >web前端高階工程師,面試題

web前端高階工程師,面試題

1:簡述前後端通訊的過程(三次握手,四次揮手)?

TCP(Transmission Control Protocol) 傳輸控制協議

1、TCP三次握手和四次揮手的過程圖

tcp的6種標誌位的分別代表:

SYN(synchronous建立聯機)

ACK(acknowledgement 確認)

PSH(push傳送)

FIN(finish結束)

RST(reset重置)

URG(urgent緊急)

Sequence number(順序號碼)

Acknowledge number(確認號碼)

客戶端TCP狀態遷移:
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
伺服器TCP狀態遷移:


CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

各個狀態的意義如下: 
LISTEN - 偵聽來自遠方TCP埠的連線請求; 
SYN-SENT -在傳送連線請求後等待匹配的連線請求; 
SYN-RECEIVED - 在收到和傳送一個連線請求後等待對連線請求的確認; 
ESTABLISHED- 代表一個開啟的連線,資料可以傳送給使用者; 
FIN-WAIT-1 - 等待遠端TCP的連線中斷請求,或先前的連線中斷請求的確認;
FIN-WAIT-2 - 從遠端TCP等待連線中斷請求; 
CLOSE-WAIT - 等待從本地使用者發來的連線中斷請求; 
CLOSING -等待遠端TCP對連線中斷的確認; 
LAST-ACK - 等待原來發向遠端TCP的連線中斷請求的確認; 
TIME-WAIT -等待足夠的時間以確保遠端TCP接收到連線中斷請求的確認; 
CLOSED - 沒有任何連線狀態;

下面具體說說三次握手和四次揮手過程:

1.1 三次握手

TCP是主機對主機層的傳輸控制協議,提供可靠的連線服務,採用三次握手確認建立一個連線:

TCP/IP協議中,TCP協議提供可靠的連線服務,採用三次握手建立一個連線,如圖1所示。

圖1 TCP三次握手建立連線

(1)第一次握手:建立連線時,客戶端A傳送SYN包(SYN=j)到伺服器B,並進入SYN_SEND狀態,等待伺服器B確認。

(2)第二次握手:伺服器B收到SYN包,必須確認客戶A的SYN(ACK=j+1),同時自己也傳送一個SYN包(SYN=k),即SYN+ACK包,此時伺服器B進入SYN_RECV狀態。

(3)第三次握手:客戶端A收到伺服器B的SYN+ACK包,向伺服器B傳送確認包ACK(ACK=k+1),此包傳送完畢,客戶端A和伺服器B進入ESTABLISHED狀態,完成三次握手。

完成三次握手,客戶端與伺服器開始傳送資料。

確認號:其數值等於傳送方的傳送序號 +1(即接收方期望接收的下一個序列號)。

TCP的包頭結構:
源埠 16位
目標埠 16位
序列號 32位
迴應序號 32位
TCP頭長度 4位
reserved 6位
控制程式碼 6位
視窗大小 16位
偏移量 16位
校驗和 16位
選項 32位(可選)
這樣我們得出了TCP包頭的最小長度,為20位元組

  • 第一次握手:
    客戶端傳送一個TCP的SYN標誌位置1的包指明客戶打算連線的伺服器的埠,以及初始序號X,儲存在包頭的序列號(Sequence Number)欄位裡。
  • 第二次握手:
    伺服器發回確認包(ACK)應答。即SYN標誌位和ACK標誌位均為1同時,將確認序號(Acknowledgement Number)設定為客戶的I S N加1以.即X+1。
  • 第三次握手.
    客戶端再次傳送確認包(ACK) SYN標誌位為0,ACK標誌位為1.並且把伺服器發來ACK的序號欄位+1,放在確定欄位中傳送給對方.並且在資料段放寫ISN的+1

下面是具體的例子截圖:

1.此圖包含兩部分資訊:TCP的三次握手(方框中的內容) (SYN, (SYN+ACK), ACK)

2. TCP的資料傳輸 ([TCP segment of a reassembled PUD])可以看出,server是將資料TCP層對訊息包進行分片傳輸

(1)Server端收到HTTP請求如GET之後,構造響應訊息,其中攜帶網頁內容,在server端的HTTP層傳送訊息200 OK->server端的TCP層; 
(2)server端的TCP層對訊息包進行分片傳輸; 
(3)client端的TCP層對接收到的各個訊息包分片回送響應; 
(4)client端的TCP層每次收到一部分都會用ACK確認,之後server繼續傳輸,client繼續確認,直到完成響應訊息的所有分片之後,Server傳送組合HTTP響應包 200 OK,此時在client端的訊息跟蹤中才可以顯示HTTP 200 OK的訊息包

1.2 四次揮手,關閉連線

由於TCP連線是全雙工的,因此每個方向都必須單獨進行關閉。這個原則是當一方完成它的資料傳送任務後就能傳送一個FIN來終止這個方向的連線。收到一個 FIN只意味著這一方向上沒有資料流動,一個TCP連線在收到一個FIN後仍能傳送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。

CP的連線的拆除需要傳送四個包,因此稱為四次揮手(four-way handshake)。客戶端或伺服器均可主動發起揮手動作,在socket程式設計中,任何一方執行close()操作即可產生揮手操作。

(1)客戶端A傳送一個FIN,用來關閉客戶A到伺服器B的資料傳送。

(2)伺服器B收到這個FIN,它發回一個ACK,確認序號為收到的序號加1。和SYN一樣,一個FIN將佔用一個序號。

(3)伺服器B關閉與客戶端A的連線,傳送一個FIN給客戶端A。

(4)客戶端A發回ACK報文確認,並將確認序號設定為收到序號加1。

TCP採用四次揮手關閉連線如圖2所示。

圖2 TCP四次揮手關閉連線

參見wireshark抓包,實測的抓包結果並沒有嚴格按揮手時序。我估計是時間間隔太短造成。

2、深入理解TCP

連線的釋放:

由於TCP連線是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的資料傳送任務後就能傳送一個FIN來終止這個方向的連線。收到一個 FIN只意味著這一方向上沒有資料流動,一個TCP連線在收到一個FIN後仍能傳送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
TCP協議的連線是全雙工連線,一個TCP連線存在雙向的讀寫通道。 
簡單說來是 “先關讀,後關寫”,一共需要四個階段。以客戶機發起關閉連線為例:
1.伺服器讀通道關閉
2.客戶機寫通道關閉
3.客戶機讀通道關閉
4.伺服器寫通道關閉
關閉行為是在發起方資料傳送完畢之後,給對方發出一個FIN(finish)資料段。直到接收到對方傳送的FIN,且對方收到了接收確認ACK之後,雙方的資料通訊完全結束,過程中每次接收都需要返回確認資料段ACK。
詳細過程:
第一階段 客戶機發送完資料之後,向伺服器傳送一個FIN資料段,序列號為i
1.伺服器收到FIN(i)後,返回確認段ACK,序列號為i+1關閉伺服器讀通道
2.客戶機收到ACK(i+1)後,關閉客戶機寫通道
(此時,客戶機仍能通過讀通道讀取伺服器的資料,伺服器仍能通過寫通道寫資料)
第二階段 伺服器傳送完資料之後,向客戶機發送一個FIN資料段,序列號為j;
3.客戶機收到FIN(j)後,返回確認段ACK,序列號為j+1關閉客戶機讀通道
4.伺服器收到ACK(j+1)後,關閉伺服器寫通道
這是標準的TCP關閉兩個階段,伺服器和客戶機都可以發起關閉,完全對稱。
FIN標識是通過傳送最後一塊資料時設定的,標準的例子中,伺服器還在傳送資料,所以要等到傳送完的時候,設定FIN(此時可稱為TCP連線處於半關閉狀態,因為資料仍可從被動關閉一方向主動關閉方傳送)。如果在伺服器收到FIN(i)時,已經沒有資料需要傳送,可以在返回ACK(i+1)的時候就設定FIN(j)標識,這樣就相當於可以合併第二步和第三步。讀《Linux網路程式設計》關閉TCP連線章節,作以下筆記:

3、TCP的TIME_WAIT和Close_Wait狀態

面試時看到應聘者簡歷中寫精通網路,TCP程式設計,我常問一個問題,TCP建立連線需要幾次握手?95%以上的應聘者都能答對是3次。問TCP斷開連線需要幾次握手,70%的應聘者能答對是4次通訊。再問CLOSE_WAIT,TIME_WAIT是什麼狀態,怎麼產生的,對服務有什麼影響,如何消除?有一部分同學就回答不上來。不是我扣細節,而是在通訊為主的前端伺服器上,必須有能力處理各種TCP狀態。比如統計在本廠的一臺前端機上高峰時間TCP連線的情況,統計命令:

Linux shell程式碼 收藏程式碼

  1. netstat -n | awk ’/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’

結果:

除了ESTABLISHED,可以看到連線數比較多的幾個狀態是:FIN_WAIT1, TIME_WAIT, CLOSE_WAIT, SYN_RECV和LAST_ACK;下面的文章就這幾個狀態的產生條件、對系統的影響以及處理方式進行簡單描述。

TCP狀態

TCP狀態如下圖所示:

可能有點眼花繚亂?再看看這個時序圖


4、三種TCP狀態

4.1 SYN_RECV

服務端收到建立連線的SYN沒有收到ACK包的時候處在SYN_RECV狀態。有兩個相關係統配置:

1,net.ipv4.tcp_synack_retries :INTEGER

預設值是5

對於遠端的連線請求SYN,核心會發送SYN + ACK資料報,以確認收到上一個 SYN連線請求包。這是所謂的三次握手( threeway handshake)機制的第二個步驟。這裡決定核心在放棄連線之前所送出的 SYN+ACK 數目。不應該大於255,預設值是5,對應於180秒左右時間。通常我們不對這個值進行修改,因為我們希望TCP連線不要因為偶爾的丟包而無法建立。

2,net.ipv4.tcp_syncookies

一般伺服器都會設定net.ipv4.tcp_syncookies=1來防止SYN Flood攻擊。假設一個使用者向伺服器傳送了SYN報文後突然宕機或掉線,那麼伺服器在發出SYN+ACK應答報文後是無法收到客戶端的ACK報文的(第三次握手無法完成),這種情況下伺服器端一般會重試(再次傳送SYN+ACK給客戶端)並等待一段時間後丟棄這個未完成的連線,這段時間的長度我們稱為SYN Timeout,一般來說這個時間是分鐘的數量級(大約為30秒-2分鐘)。

這些處在SYNC_RECV的TCP連線稱為半連線,並存儲在核心的半連線佇列中,在核心收到對端傳送的ack包時會查詢半連線佇列,並將符合的requst_sock資訊儲存到完成三次握手的連線的佇列中,然後刪除此半連線。大量SYNC_RECV的TCP連線會導致半連線佇列溢位,這樣後續的連線建立請求會被核心直接丟棄,這就是SYN Flood攻擊。

能夠有效防範SYN Flood攻擊的手段之一,就是SYN Cookie。SYN Cookie原理由D. J. Bernstain和 Eric Schenk發明。SYN Cookie是對TCP伺服器端的三次握手協議作一些修改,專門用來防範SYN Flood攻擊的一種手段。它的原理是,在TCP伺服器收到TCP SYN包並返回TCP SYN+ACK包時,不分配一個專門的資料區,而是根據這個SYN包計算出一個cookie值。在收到TCP ACK包時,TCP伺服器在根據那個cookie值檢查這個TCP ACK包的合法性。如果合法,再分配專門的資料區進行處理未來的TCP連線。

觀測服務上SYN_RECV連線個數為:7314,對於一個高併發連線的通訊伺服器,這個數字比較正常。

4.2 CLOSE_WAIT

發起TCP連線關閉的一方稱為client,被動關閉的一方稱為server。被動關閉的server收到FIN後,但未發出ACK的TCP狀態是CLOSE_WAIT。出現這種狀況一般都是由於server端程式碼的問題,如果你的伺服器上出現大量CLOSE_WAIT,應該要考慮檢查程式碼。

4.3 TIME_WAIT

根據TCP協議定義的3次握手斷開連線規定,發起socket主動關閉的一方 socket將進入TIME_WAIT狀態。TIME_WAIT狀態將持續2個MSL(Max Segment Lifetime),在Windows下預設為4分鐘,即240秒。TIME_WAIT狀態下的socket不能被回收使用. 具體現象是對於一個處理大量短連線的伺服器,如果是由伺服器主動關閉客戶端的連線,將導致伺服器端存在大量的處於TIME_WAIT狀態的socket, 甚至比處於Established狀態下的socket多的多,嚴重影響伺服器的處理能力,甚至耗盡可用的socket,停止服務。

5、 為什麼需要TIME_WAIT?

TIME_WAIT是TCP協議用以保證被重新分配的socket不會受到之前殘留的延遲重發報文影響的機制,是必要的邏輯保證。

和TIME_WAIT狀態有關的系統引數有一般由3個,本廠設定如下:

net.ipv4.tcp_tw_recycle = 1

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_fin_timeout = 30

net.ipv4.tcp_fin_timeout,預設60s,減小fin_timeout,減少TIME_WAIT連線數量。

net.ipv4.tcp_tw_reuse = 1表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連線,預設為0,表示關閉;

net.ipv4.tcp_tw_recycle = 1表示開啟TCP連線中TIME-WAIT sockets的快速回收,預設為0,表示關閉。

為了方便描述,我給這個TCP連線的一端起名為Client,給另外一端起名為Server。上圖描述的是Client主動關閉的過程,FTP協議中就這樣的。如果要描述Server主動關閉的過程,只要交換描述過程中的Server和Client就可以了,HTTP協議就是這樣的。

描述過程:
Client呼叫close()函式,給Server傳送FIN,請求關閉連線;Server收到FIN之後給Client返回確認ACK,同時關閉讀通道(不清楚就去看一下shutdown和close的差別),也就是說現在不能再從這個連線上讀取東西,現在read返回0。此時Server的TCP狀態轉化為CLOSE_WAIT狀態。
Client收到對自己的FIN確認後,關閉 寫通道,不再向連線中寫入任何資料。
接下來Server呼叫close()來關閉連線,給Client傳送FIN,Client收到後給Server回覆ACK確認,同時Client關閉讀通道,進入TIME_WAIT狀態。
Server接收到Client對自己的FIN的確認ACK,關閉寫通道,TCP連線轉化為CLOSED,也就是關閉連線。
Client在TIME_WAIT狀態下要等待最大資料段生存期的兩倍,然後才進入CLOSED狀態,TCP協議關閉連線過程徹底結束。

以上就是TCP協議關閉連線的過程,現在說一下TIME_WAIT狀態。
從上面可以看到,主動發起關閉連線的操作的一方將達到TIME_WAIT狀態,而且這個狀態要保持Maximum Segment Lifetime的兩倍時間。

原因有二:
一、保證TCP協議的全雙工連線能夠可靠關閉
二、保證這次連線的重複資料段從網路中消失

先說第一點,如果Client直接CLOSED了,那麼由於IP協議的不可靠性或者是其它網路原因,導致Server沒有收到Client最後回覆的ACK。那麼Server就會在超時之後繼續傳送FIN,此時由於Client已經CLOSED了,就找不到與重發的FIN對應的連線,最後Server就會收到RST而不是ACK,Server就會以為是連線錯誤把問題報告給高層。這樣的情況雖然不會造成資料丟失,但是卻導致TCP協議不符合可靠連線的要求。所以,Client不是直接進入CLOSED,而是要保持TIME_WAIT,當再次收到FIN的時候,能夠保證對方收到ACK,最後正確的關閉連線。

再說第二點,如果Client直接CLOSED,然後又再向Server發起一個新連線,我們不能保證這個新連線與剛關閉的連線的埠號是不同的。也就是說有可能新連線和老連線的埠號是相同的。一般來說不會發生什麼問題,但是還是有特殊情況出現:假設新連線和已經關閉的老連線埠號是一樣的,如果前一次連線的某些資料仍然滯留在網路中,這些延遲資料在建立新連線之後才到達Server,由於新連線和老連線的埠號是一樣的,又因為TCP協議判斷不同連線的依據是socket pair,於是,TCP協議就認為那個延遲的資料是屬於新連線的,這樣就和真正的新連線的資料包發生混淆了。所以TCP連線還要在TIME_WAIT狀態等待2倍MSL,這樣可以保證本次連線的所有資料都從網路中消失。

2:webpack 和 gulp 的區別

webpack是前端構建工具,稱為模組打包機,webpack支援模組化;構建前端開發過程中常用的檔案,如:js,css,html,img等;使用簡單方便,自動化構建。webpack是通過loader(載入器)和plugins(外掛)對資源進行處理的。

Glup側重於前端開發的整個過程的控制管理,我們可以通過給glup配置不同的task來讓glup實現不同的功能,從而構建整個前端開發流程。(通過gulp中的gulp.task()方法配置,比如server、sass/less預編譯、檔案的合併壓縮等等)

區別:

gulp嚴格上講,模組化不是他強調的東西,他旨在規範前端開發流程。

webpack更是明顯強調模組化開發,而那些檔案壓縮合並、預處理等功能,不過是他附帶的功能。

3:tup,udp的區別?

TCP協議與UDP協議的區別
    首先咱們弄清楚,TCP協議和UCP協議與TCP/IP協議的聯絡,很多人犯糊塗了,一直都是說TCP/IP協議與UDP協議的區別,我覺得這是沒有從本質上弄清楚網路通訊!
TCP/IP協議是一個協議簇。裡面包括很多協議的。UDP只是其中的一個。之所以命名為TCP/IP協議,因為TCP,IP協議是兩個很重要的協議,就用他兩命名了。
TCP/IP協議集包括應用層,傳輸層,網路層,網路訪問層。
其中應用層包括:
超文字傳輸協議(HTTP):全球資訊網的基本協議.   
檔案傳輸(TFTP簡單檔案傳輸協議):   
遠端登入(Telnet),提供遠端訪問其它主機功能,它允許使用者登入    
internet主機,並在這臺主機上執行命令.    
網路管理(SNMP簡單網路管理協議),該協議提供了監控網路裝置的方法,以及配置管理,統計資訊收集,效能管理及安全管理等.   
域名系統(DNS),該系統用於在internet中將域名及其公共廣播的網路節點轉換成IP地址. 
其次網路層包括:    
Internet協議(IP)     
Internet控制資訊協議(ICMP)    
地址解析協議(ARP)    
反向地址解析協議(RARP)  
最後說網路訪問層:網路訪問層又稱作主機到網路層(host-to-network).網路訪問層的功能包括IP地址與實體地址硬體的對映,以及將IP封裝成幀.基於不同硬體型別的網路介面,網路訪問層定義了和物理介質的連線.
當然我這裡說得不夠完善,TCP/IP協議本來就是一門學問,每一個分支都是一個很複雜的流程,但我相信每位學習軟體開發的同學都有必要去仔細瞭解一番。
下面我著重講解一下TCP協議和UDP協議的區別。
TCP(Transmission Control Protocol,傳輸控制協議)是面向連線的協議,也就是說,在收發資料前,必須和對方建立可靠的連線。一個TCP連線必須要經過三次“對話”才能建立起來,其中的過程非常複雜,只簡單的描述下這三次對話的簡單過程:主機A向主機B發出連線請求資料包:“我想給你發資料,可以嗎?”,這是第一次對話;主機B向主機A傳送同意連線和要求同步(同步就是兩臺主機一個在傳送,一個在接收,協調工作)的資料包:“可以,你什麼時候發?”,這是第二次對話;主機A再發出一個數據包確認主機B的要求同步:“我現在就發,你接著吧!”,這是第三次對話。三次“對話”的目的是使資料包的傳送和接收同步,經過三次“對話”之後,主機A才向主機B正式傳送資料。
詳細點說就是:(文章部分轉載http://zhangjiangxing-gmail-com.iteye.com,主要是這個人講解得很到位,的確很容易使人理解!)
TCP三次握手過程
1 主機A通過向主機B 傳送一個含有同步序列號的標誌位的資料段給主機B ,向主機B 請求建立連線,通過這個資料段,
主機A告訴主機B 兩件事:我想要和你通訊;你可以用哪個序列號作為起始資料段來回應我.
2 主機B 收到主機A的請求後,用一個帶有確認應答(ACK)和同步序列號(SYN)標誌位的資料段響應主機A,也告訴主機A兩件事:
我已經收到你的請求了,你可以傳輸資料了;你要用哪佧序列號作為起始資料段來回應我
3 主機A收到這個資料段後,再發送一個確認應答,確認已收到主機B 的資料段:"我已收到回覆,我現在要開始傳輸實際資料了
這樣3次握手就完成了,主機A和主機B 就可以傳輸資料了.
3次握手的特點
沒有應用層的資料
SYN這個標誌位只有在TCP建產連線時才會被置1
握手完成後SYN標誌位被置0

TCP建立連線要進行3次握手,而斷開連線要進行4次

1 當主機A完成資料傳輸後,將控制位FIN置1,提出停止TCP連線的請求
2  主機B收到FIN後對其作出響應,確認這一方向上的TCP連線將關閉,將ACK置1
3 由B 端再提出反方向的關閉請求,將FIN置1
4 主機A對主機B的請求進行確認,將ACK置1,雙方向的關閉結束.
由TCP的三次握手和四次斷開可以看出,TCP使用面向連線的通訊方式,大大提高了資料通訊的可靠性,使傳送資料端
和接收端在資料正式傳輸前就有了互動,為資料正式傳輸打下了可靠的基礎
名詞解釋
ACK  TCP報頭的控制位之一,對資料進行確認.確認由目的端發出,用它來告訴傳送端這個序列號之前的資料段
都收到了.比如,確認號為X,則表示前X-1個數據段都收到了,只有當ACK=1時,確認號才有效,當ACK=0時,確認號無效,這時會要求重傳資料,保證資料的完整性.
SYN  同步序列號,TCP建立連線時將這個位置1
FIN  傳送端完成傳送任務位,當TCP完成資料傳輸需要斷開時,提出斷開連線的一方將這位置1
TCP的包頭結構:
源埠 16位
目標埠 16位
序列號 32位
迴應序號 32位
TCP頭長度 4位
reserved 6位
控制程式碼 6位
視窗大小 16位
偏移量 16位
校驗和 16位
選項  32位(可選)
這樣我們得出了TCP包頭的最小長度,為20位元組。

UDP(User Data Protocol,使用者資料報協議)
(1) UDP是一個非連線的協議,傳輸資料之前源端和終端不建立連線,當它想傳送時就簡單地去抓取來自應用程式的資料,並儘可能快地把它扔到網路上。在傳送端,UDP傳送資料的速度僅僅是受應用程式生成資料的速度、計算機的能力和傳輸頻寬的限制;在接收端,UDP把每個訊息段放在佇列中,應用程式每次從佇列中讀一個訊息段。
(2) 由於傳輸資料不建立連線,因此也就不需要維護連線狀態,包括收發狀態等,因此一臺服務機可同時向多個客戶機傳輸相同的訊息。
(3) UDP資訊包的標題很短,只有8個位元組,相對於TCP的20個位元組資訊包的額外開銷很小。
(4) 吞吐量不受擁擠控制演算法的調節,只受應用軟體生成資料的速率、傳輸頻寬、源端和終端主機效能的限制。
(5)UDP使用盡最大努力交付,即不保證可靠交付,因此主機不需要維持複雜的連結狀態表(這裡面有許多引數)。
(6)UDP是面向報文的。傳送方的UDP對應用程式交下來的報文,在新增首部後就向下交付給IP層。既不拆分,也不合並,而是保留這些報文的邊界,因此,應用程式需要選擇合適的報文大小。
我們經常使用“ping”命令來測試兩臺主機之間TCP/IP通訊是否正常,其實“ping”命令的原理就是向對方主機發送UDP資料包,然後對方主機確認收到資料包,如果資料包是否到達的訊息及時反饋回來,那麼網路就是通的。
UDP的包頭結構:
源埠 16位
目的埠 16位
長度 16位
校驗和 16位

小結TCP與UDP的區別:

1、TCP面向連線(如打電話要先撥號建立連線);UDP是無連線的,即傳送資料之前不需要建立連線

2、TCP提供可靠的服務。也就是說,通過TCP連線傳送的資料,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保證可靠交付

Tcp通過校驗和,重傳控制,序號標識,滑動視窗、確認應答實現可靠傳輸。如丟包時的重發控制,還可以對次序亂掉的分包進行順序控制。

3、UDP具有較好的實時性,工作效率比TCP高,適用於對高速傳輸和實時性有較高的通訊或廣播通訊。

4.每一條TCP連線只能是點到點的;UDP支援一對一,一對多,多對一和多對多的互動通訊

  1. TCP對系統資源要求較多,UDP對系統資源要求較少。
    1.基於連線與無連線;
    2.對系統資源的要求(TCP較多,UDP少);
    3.UDP程式結構較簡單;
    4.流模式與資料報模式 ;
    5.TCP保證資料正確性,UDP可能丟包,TCP保證資料順序,UDP不保證。

4.閉包是什麼,有什麼特性,對頁面有什麼影響

    答:我的理解是,閉包就是能夠讀取其他函式內部變數的函式。在本質上,閉包就是將函式內部和函式外部連線起來的一座橋樑。

function outer(){

    var num = 1;

    function inner(){

        var n = 2;

        alert(n + num);

    }

    return inner;

}

outer()();

5:瀏覽不相容:瀏覽器版本,核心的不同;

html常見相容性問題?

1.雙邊距BUG float引起的  使用display

2.3畫素問題 使用float引起的 使用dislpay:inline -3px  

3.超連結hover 點選後失效  使用正確的書寫順序 link visited hover active

4.Ie z-index問題 給父級新增position:relative

5.Png 透明 使用js程式碼 改

6.Min-height 最小高度 !Important 解決’

7.select 在ie6下遮蓋 使用iframe巢狀

8.為什麼沒有辦法定義1px左右的寬度容器(IE6預設的行高造成的,使用over:hidden,zoom:0.08 line-height:1px)

9.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*/

}

10. IE6不支援PNG透明背景,解決辦法: IE6下使用gif圖片

6:Get和post的區別

    get引數通過url傳遞,post放在request body中。

    get請求在url中傳遞的引數是有長度限制的,而post沒有。

    get比post更不安全,因為引數直接暴露在url中,所以不能用來傳遞敏感資訊。

        get請求只能進行url編碼,而post支援多種編碼方式

        get請求會瀏覽器主動cache,而post支援多種編碼方式。

        get請求引數會被完整保留在瀏覽歷史記錄裡,而post中的引數不會被保留。

    GET和POST本質上就是TCP連結,並無差別。但是由於HTTP的規定和瀏覽器/伺服器的限制,導致他們在應用過程中體現出一些不同。

    GET產生一個TCP資料包;POST產生兩個TCP資料包。

ajax.請求頭,applation......

j傳送jipost請求的方法如下面所示:

var XMLHttpReq;

//建立XMLHttpRequest物件

function createXMLHttpRequest() {if(window.XMLHttpRequest) { //Mozilla 瀏覽

XMLHttpReq = new XMLHttpRequest();}

else if (window.ActiveXObject) { // IE瀏覽器

try {XMLHttpReq = new ActiveXObject("Msxml2.XMLHTTP");

} catch (e) {try {XMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");

} catch (e) {}

//傳送請求函

function sendRequest(url,para) {

createXMLHttpRequest();

XMLHttpReq.open("POST", url,true);

XMLHttpReq.onreadystatechange = processResponse;//指定響應函式

XMLHttpReq.setRequestHeader("Content-Type", "application/x-www-form-

urlencoded");

XMLHttpReq.send(para);  // 傳送請求}// 處理返回資訊函式

在通過POST方式向伺服器傳送AJAX請求時最好要通過設定請求頭來指定為application/x-www-form-urlencoded編碼型別。知道通過表單上傳檔案時必須指定編碼型別為"multipart/form-data"。ajax.setRequestHeader("content-type","application/x-www-form-urlencoded")表示將請求中的內容,按照UTF-8的方式進行編碼,只針對POST請求有效,設定此內容是為了確保伺服器知道實體中有引數變數,注意: 請求體格式和請求頭的Content-Type型別必須保持一致,如果1的格式,設定Content-Type是application/json,或者2的格式,設定Content-Type是application/x-www-form-urlencoded,後臺接收到的請求提都會是空的

一、返回控制與函式結果,

語法為:return 表示式;
語句結束函式執行,返回呼叫函式,而且把表示式的值作為函式的結果

 二、返回控制,

無函式結果,語法為:return;



 在大多數情況下,為事件處理函式返回false,可以防止預設的事件行為.例如,預設情況下點選一個<a>元素,頁面會跳轉到該元素href屬性指定的頁.   

 Return False 就相當於終止符,Return True 就相當於執行符。   

 在js中return false的作用一般是用來取消預設動作的。比如你單擊一個連結除了觸發你的   

 onclick時間(如果你指定的話)以外還要觸發一個預設事件就是執行頁面的跳轉。所以如果   

 你想取消物件的預設動作就可以return false。

首先在js中,我們常用return false來阻止提交表單者繼續執行下面的程式碼,通俗的來說就是阻止執行預設的行為。

function a(){

   if(True)
       return false;
},這是沒有任何問題的。

如果我改成這種

function Test(){

   a();

   b();

   c();

}

即使a函式返回return false 阻止提交了,但是不影響 b()以及 c()函式的執行。在Test()函式裡呼叫a()函式,那面裡面

return false 對於Test()函式來說,只是相當於返回值。而不能阻止Test()函式執行。

總之:return false 只在當前函式有效,不會影響其他外部函式的執行。

三:總結

retrun true; 返回正確的處理結果。

return false;分會錯誤的處理結果,終止處理。

return;把控制權返回給頁面。

8:URL 輸入到頁面展現的過程簡述

在瀏覽器中輸入URL到整個頁面顯示在使用者面前這個過程大致可以被分為以下幾個階段:

  1. 域名解析
  2. 伺服器處理
  3. 網站處理
  4. 瀏覽器處理與繪製

URL的定義

URL(Uniform Resource Locator),即統一資源定位符,是對可以從網際網路上得到的資源的位置和訪問方法的一種簡潔的表示,是網際網路上標準資源的地址(網址)。網際網路上的每個檔案都有一個唯一的URL,它包含的資訊指出檔案的位置以及瀏覽器應該怎麼處理它。

基本URL包含模式(或稱協議)、伺服器名稱(或IP地址)、路徑和檔名,如“協議://授權/路徑查詢”。完整的、帶有授權部分的普通統一資源標誌符語法看上去如下:協議://使用者名稱:密碼@子域名.域名.頂級域名:埠號/目錄/檔名.檔案字尾?引數=值#標誌

URL常用協議有:

  • http——超文字傳輸協議資源
  • https——用安全套接字層傳送的超文字傳輸協議(加密)
  • ftp——檔案傳輸協議
  • mailto——電子郵件地址
  • file——當地電腦或網上分享的檔案

具體過程介紹

一、域名解析

網際網路上每一臺計算機的唯一標識是它的IP地址,但是IP地址並不方便記憶。使用者更喜歡用方便記憶的網址去尋找網際網路上的其它計算機。所以網際網路設計者需要在使用者的方便性與可用性方面做一個權衡,這個權衡就是一個網址到IP地址的轉換,這個過程就是域名解析。它實際上充當了一個翻譯的角色,實現了網址到IP地址的轉換。域名的解析工作由DNS伺服器完成。

IP 地址:IP 協議為網際網路上的每一個網路和每一臺主機分配的一個邏輯地址。IP 地址如同門牌號碼,通過 IP 地址才能確定一臺主機位置。伺服器本質也是一臺主機,想要訪問某個伺服器,必須先知道它的 IP 地址

域名( DN ):IP 地址由四個數字組成,中間用點號連線,在使用過程中難記憶且易輸入錯誤,所以用我們熟悉的字母和數字組合來代替純數字的 IP 地址,比如我們只會記住 www.baidu.com(百度域名) 而不是 220.181.112.244(百度的其中一個 IP 地址)。

DNS: 每個域名都對應一個或多個提供相同服務伺服器的 IP 地址,只有知道伺服器 IP 地址才能建立連線,所以需要通過 DNS 把域名解析成一個 IP 地址。

具體流程

  1. 瀏覽器搜尋自己的DNS快取 – 瀏覽器會快取DNS記錄一段時間
  2. 搜尋作業系統中的Hosts檔案 - 從 Hosts 檔案查詢是否有該域名和對應 IP。
  3. 搜尋路由器快取 – 一般路由器也會快取域名資訊。
  4. 搜尋ISP DNS 快取 (ISP:網際網路服務提供商)– 比如到電信的 DNS 上查詢快取。
    如果都沒有找到,則向根域名伺服器查詢域名對應 IP,根域名伺服器把請求轉發到下一級,直到找到 IP

小知識

  1. 8.8.8.8 :8.8.8.8是一個IP地址,是Google提供的免費DNS伺服器的IP地址
    114.114.114.114 :是國內第一個、全球第三個開放的DNS服務地址,又稱114DNS
  2. DNS劫持:
    DNS劫持又稱域名劫持,是指在劫持的網路範圍內攔截域名解析的請求,分析請求的域名,把審查範圍以外的請求放行,否則返回假的IP地址或者什麼都不做使請求失去響應,其效果就是對特定的網路不能反應或訪問的是假網址。

二、伺服器處理

伺服器是一臺安裝系統的機器,常見的系統如Linux、windows server 2012等系統裡安裝的處理請求的應用叫 Web server(web伺服器)
常見的 web伺服器有 Apache、Nginx、IIS、Lighttpd
web伺服器接收使用者的Request 交給網站程式碼,或者接受請求反向代理到其他 web伺服器

** 飢人谷伺服器處理過程示意圖**

三、網站處理

**MVC架構網站處理示意圖**.png

MVC全名是Model View Controller,是模型(model)-檢視(view)-控制器(controller)的縮寫,一種軟體設計典範,用一種業務邏輯、資料、介面顯示分離的方法組織程式碼,將業務邏輯聚集到一個部件裡面,在改進和個性化定製介面及使用者互動的同時,不需要重新編寫業務邏輯。MVC被獨特的發展起來用於對映傳統的輸入、處理和輸出功能在一個邏輯的圖形化使用者介面的結構中。

  • Model(模型):是應用程式中用於處理應用程式資料邏輯的部分,通常模型物件負責在資料庫中存取資料。
  • View(檢視):是應用程式中處理資料顯示的部分。,通常檢視是依據模型資料建立的。(前端工程師主要負責
  • Controller(控制器):是應用程式中處理使用者互動的部分,通常控制器負責從檢視讀取資料,控制使用者輸入,並向模型傳送資料。

四、瀏覽器處理與繪製

解析過程:

  • HTML字串被瀏覽器接受後被一句句讀取解析
  • 解析到link 標籤後重新發送請求獲取css;解析到 script標籤後傳送請求獲取 js,並執行程式碼
  • 解析到img 標籤後傳送請求獲取圖片資源

繪製過程:

  • 瀏覽器根據 HTML 和 CSS 計算得到渲染樹,繪製到螢幕上,js 會被執行

解析順序:

  • 瀏覽器是一個邊解析邊渲染的過程。首先瀏覽器解析HTML檔案構建DOM樹,然後解析CSS檔案構建渲染樹,等到渲染樹構建完成後,瀏覽器開始佈局渲染樹並將其繪製到螢幕上。
  • JS的解析是由瀏覽器中的JS解析引擎完成的。JS是單執行緒執行,也就是說,在同一個時間內只能做一件事,所有的任務都需要排隊,前一個任務結束,後一個任務才能開始。
  • 瀏覽器在解析過程中,如果遇到請求外部資源時請求過程是非同步的,並不會影響HTML文件進行載入,但是當文件載入過程中遇到JS檔案,HTML文件會掛起渲染過程,不僅要等到文件中JS檔案載入完畢還要等待解析執行完畢,才會繼續HTML的渲染過程。原因是因為JS有可能修改DOM結構,這就意味著JS執行完成前,後續所有資源的下載是沒有必要的,這就是JS阻塞後續資源下載的根本原因。CSS檔案的載入不影響JS檔案的載入,但是卻影響JS檔案的執行。JS程式碼執行前瀏覽器必須保證CSS檔案已經下載並載入完畢。

連結:https://www.jianshu.com/p/63166522c244

9:淺談HTTP中Get、Post、Put與Delete的區別

1、GET請求會向資料庫發索取資料的請求,從而來獲取資訊,該請求就像資料庫的select操作一樣,只是用來查詢一下資料,不會修改、增加資料,不會影響資源的內容,即該請求不會產生副作用。無論進行多少次操作,結果都是一樣的。

2、與GET不同的是,PUT請求是向伺服器端傳送資料的,從而改變資訊,該請求就像資料庫的update操作一樣,用來修改資料的內容,但是不會增加資料的種類等,也就是說無論進行多少次PUT操作,其結果並沒有不同。

3、POST請求同PUT請求類似,都是向伺服器端傳送資料的,但是該請求會改變資料的種類等資源,就像資料庫的insert操作一樣,會建立新的內容。幾乎目前所有的提交操作都是用POST請求的。

4、DELETE請求顧名思義,就是用來刪除某一個資源的,該請求就像資料庫的delete操作。

就像前面所講的一樣,既然PUT和POST操作都是向伺服器端傳送資料的,那麼兩者有什麼區別呢。。。POST主要作用在一個集合資源之上的(url),而PUT主要作用在一個具體資源之上的(url/xxx),通俗一下講就是,如URL可以在客戶端確定,那麼可使用PUT,否則用POST。

綜上所述,我們可理解為以下:

1、POST /url 建立  
2、DELETE /url/xxx 刪除 
3、PUT /url/xxx 更新
4、GET /url/xxx 檢視
 
 Http定義了與伺服器互動的不同方法,最基本的方法有4種,分別是GET,POST,PUT,DELETE。URL全稱是統一資源定位符,我們可以這樣認為:一個URL地址,它用於描述一個網路上的資源,而HTTP中的GET,POST,PUT,DELETE就對應著對這個資源的查,改,增,刪4個操作。到這裡,大家應該有個大概的瞭解了,GET一般用於獲取/查詢資源資訊,而POST一般用於更新資源資訊。

1.根據HTTP規範,GET用於資訊獲取,而且應該是安全的和冪等的。

(1).所謂安全的意味著該操作用於獲取資訊而非修改資訊。換句話說,GET 請求一般不應產生副作用。就是說,它僅僅是獲取資源資訊,就像資料庫查詢一樣,不會修改,增加資料,不會影響資源的狀態。

* 注意:這裡安全的含義僅僅是指是非修改資訊。

(2).冪等的意味著對同一URL的多個請求應該返回同樣的結果。這裡我再解釋一下冪等這個概念:

冪等(idempotent、idempotence)是一個數學或計算機學概念,常見於抽象代數中。
  冪等有一下幾種定義:
  對於單目運算,如果一個運算對於在範圍內的所有的一個數多次進行該運算所得的結果和進行一次該運算所得的結果是一樣的,那麼我們就稱該運算是冪等的。比如絕對值運算就是一個例子,在實數集中,有abs(a)=abs(abs(a))。
  對於雙目運算,則要求當參與運算的兩個值是等值的情況下,如果滿足運算結果與參與運算的兩個值相等,則稱該運算冪等,如求兩個數的最大值的函式,有在在實數集中冪等,即max(x,x) = x。

看完上述解釋後,應該可以理解GET冪等的含義了。

  但在實際應用中,以上2條規定並沒有這麼嚴格。引用別人文章的例子:比如,新聞站點的頭版不斷更新。雖然第二次請求會返回不同的一批新聞,該操作仍然被認為是安全的和冪等的,因為它總是返回當前的新聞。從根本上說,如果目標是當用戶開啟一個連結時,他可以確信從自身的角度來看沒有改變資源即可。

2.根據HTTP規範,POST表示可能修改變伺服器上的資源的請求。繼續引用上面的例子:還是新聞以網站為例,讀者對新聞發表自己的評論應該通過POST實現,因為在評論提交後站點的資源已經不同了,或者說資源被修改了。

  上面大概說了一下HTTP規範中GET和POST的一些原理性的問題。但在實際的做的時候,很多人卻沒有按照HTTP規範去做,導致這個問題的原因有很多,比如說:

1.很多人貪方便,更新資源時用了GET,因為用POST必須要到FORM(表單),這樣會麻煩一點。

2.對資源的增,刪,改,查操作,其實都可以通過GET/POST完成,不需要用到PUT和DELETE。

3.另外一個是,早期的Web MVC框架設計者們並沒有有意識地將URL當作抽象的資源來看待和設計,所以導致一個比較嚴重的問題是傳統的Web MVC框架基本上都只支援GET和POST兩種HTTP方法,而不支援PUT和DELETE方法。

   * 簡單解釋一下MVC:MVC本來是存在於Desktop程式中的,M是指資料模型,V是指使用者介面,C則是控制器。使用MVC的目的是將M和V的實現程式碼分離,從而使同一個程式可以使用不同的表現形式。

  以上3點典型地描述了老一套的風格(沒有嚴格遵守HTTP規範),隨著架構的發展,現在出現REST(Representational State Transfer),一套支援HTTP規範的新風格,這裡不多說了,可以參考《RESTful Web Services》。

  說完原理性的問題,我們再從表面現像上面看看GET和POST的區別:

1.GET請求的資料會附在URL之後(就是把資料放置在HTTP協議頭中),以?分割URL和傳輸資料,引數之間以&相連,如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。如果資料是英文字母/數字,原樣傳送,如果是空格,轉換為+,如果是中文/其他字元,則直接把字串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX為該符號以16進製表示的ASCII。

POST把提交的資料則放置在是HTTP包的包體中。

2."GET方式提交的資料最多隻能是1024位元組,理論上POST沒有限制,可傳較大量的資料,IIS4中最大為80KB,IIS5中為100KB"??!

  以上這句是我從其他文章轉過來的,其實這樣說是錯誤的,不準確的:

(1).首先是"GET方式提交的資料最多隻能是1024位元組",因為GET是通過URL提交資料,那麼GET可提交的資料量就跟URL的長度有直接關係了。而實際上,URL不存在引數上限的問題,HTTP協議規範沒有對URL長度進行限制。這個限制是特定的瀏覽器及伺服器對它的限制。IE對URL長度的限制是2083位元組(2K+35)。對於其他瀏覽器,如Netscape、FireFox等,理論上沒有長度限制,其限制取決於作業系統的支援。

  注意這是限制是整個URL長度,而不僅僅是你的引數值資料長度。[見參考資料5]

(2).理論上講,POST是沒有大小限制的,HTTP協議規範也沒有進行大小限制,說“POST資料量存在80K/100K的大小限制”是不準確的,POST資料是沒有限制的,起限制作用的是伺服器的處理程式的處理能力。

  對於ASP程式,Request物件處理每個表單域時存在100K的資料長度限制。但如果使用Request.BinaryRead則沒有這個限制。

  由這個延伸出去,對於IIS 6.0,微軟出於安全考慮,加大了限制。我們還需要注意:

1).IIS 6.0預設ASP POST資料量最大為200KB,每個表單域限制是100KB。
2).IIS 6.0預設上傳檔案的最大大小是4MB。
3).IIS 6.0預設最大請求頭是16KB。
IIS 6.0之前沒有這些限制。[見參考資料5]

  所以上面的80K,100K可能只是預設值而已(注:關於IIS4和IIS5的引數,我還沒有確認),但肯定是可以自己設定的。由於每個版本的IIS對這些引數的預設值都不一樣,具體請參考相關的IIS配置文件。

3.在ASP中,服務端獲取GET請求引數用Request.QueryString,獲取POST請求引數用Request.Form。在JSP中,用request.getParameter(\"XXXX\")來獲取,雖然jsp中也有request.getQueryString()方法,但使用起來比較麻煩,比如:傳一個test.jsp?name=hyddd&password=hyddd,用request.getQueryString()得到的是:name=hyddd&password=hyddd。在PHP中,可以用$_GET和$_POST分別獲取GET和POST中的資料,而$_REQUEST則可以獲取GET和POST兩種請求中的資料。值得注意的是,JSP中使用request和PHP中使用$_REQUEST都會有隱患,這個下次再寫個文章總結。

4.POST的安全性要比GET的安全性高。注意:這裡所說的安全性和上面GET提到的“安全”不是同個概念。上面“安全”的含義僅僅是不作資料修改,而這裡安全的含義是真正的Security的含義,比如:通過GET提交資料,使用者名稱和密碼將明文出現在URL上,因為(1)登入頁面有可能被瀏覽器快取,(2)其他人檢視瀏覽器的歷史紀錄,那麼別人就可以拿到你的賬號和密碼了,除此之外,使用GET提交資料還可能會造成Cross-site request forgery攻擊。

  總結一下,Get是向伺服器發索取資料的一種請求,而Post是向伺服器提交資料的一種請求,在FORM(表單)中,Method預設為"GET",實質上,GET和POST只是傳送機制不同,並不是一個取一個發!

什麼是作用域鏈,什麼是原型鏈。

  作用域是針對變數的,比如我們建立了一個函式,函式裡面又包含了一個函式,那麼現在就有三個作用域

  全域性作用域==>函式1作用域==>函式2作用域

作用域的特點就是,先在自己的變數範圍中查詢,如果找不到,就會沿著作用域往上找。

如:

複製程式碼

var a = 1;
function b(){
    var a = 2;
    function c(){
        var a = 3;
        console.log(a);
    }
    c();
}
b();

複製程式碼

最後打印出來的是3,因為執行函式c()的時候它在自己的範圍內找到了變數a所以就不會越上繼續查詢,如果在函式c()中沒有找到則會繼續向上找,一直會找到全域性變數a,這個查詢的過程就叫作用域鏈。

不知道你有沒有疑問,函式c為什麼可以在函式b中查詢變數a,因為函式c是在函式b中建立的,也就是說函式c的作用域包括了函式b的作用域,當然也包括了全域性作用域,但是函式b不能向函式c中查詢變數,因為作用域只會向上查詢。

那麼什麼是原型鏈呢?

  原型鏈是針對建構函式的,比如我先建立了一個函式,然後通過一個變數new了這個函式,那麼這個被new出來的函式就會繼承創建出來的那個函式的屬性,然後如果我訪問new出來的這個函式的某個屬性,但是我並沒有在這個new出來的函式中定義這個變數,那麼它就會往上(向創建出它的函式中)查詢,這個查詢的過程就叫做原型鏈。

  Object ==> 建構函式1 ==> 建構函式2

  就和css中的繼承一樣,如果自身沒有定義就會繼承父元素的樣式。

function a(){};
a.prototype.name = "追夢子";
var b = new a();
console.log(b.name); //追夢子

11:JS繼承的實現方式

前言

JS作為面向物件的弱型別語言,繼承也是其非常強大的特性之一。那麼如何在JS中實現繼承呢?讓我們拭目以待。

JS繼承的實現方式

既然要實現繼承,那麼首先我們得有一個父類,程式碼如下:

// 定義一個動物類
function Animal (name) {
  // 屬性
  this.name = name || 'Animal';
  // 例項方法
  this.sleep = function(){
    console.log(this.name + '正在睡覺!');
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};

1、原型鏈繼承

核心: 將父類的例項作為子類的原型

function Cat(){ 
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true 
console.log(cat instanceof Cat); //true

特點:

  1. 非常純粹的繼承關係,例項是子類的例項,也是父類的例項
  2. 父類新增原型方法/原型屬性,子類都能訪問到
  3. 簡單,易於實現

缺點:

  1. 要想為子類新增屬性和方法,必須要在new Animal()這樣的語句之後執行,不能放到構造器中
  2. 無法實現多繼承
  3. 來自原型物件的引用屬性是所有例項共享的(詳細請看附錄程式碼: 示例1
  4. 建立子類例項時,無法向父類建構函式傳參

推薦指數:★★(3、4兩大致命缺陷)

2017-8-17 10:21:43補充:感謝 MMHS 指出。缺點1中描述有誤:可以在Cat建構函式中,為Cat例項增加例項屬性。如果要新增原型屬性和方法,則必須放在new Animal()這樣的語句之後執行。

2、構造繼承

核心:使用父類的建構函式來增強子類例項,等於是複製父類的例項屬性給子類(沒用到原型)

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

特點:

  1. 解決了1中,子類例項共享父類引用屬性的問題
  2. 建立子類例項時,可以向父類傳遞引數
  3. 可以實現多繼承(call多個父類物件)

缺點:

  1. 例項並不是父類的例項,只是子類的例項
  2. 只能繼承父類的例項屬性和方法,不能繼承原型屬性/方法
  3. 無法實現函式複用,每個子類都有父類例項函式的副本,影響效能

推薦指數:★★(缺點3)

3、例項繼承

核心:為父類例項新增新特性,作為子類例項返回

function Cat(name){
  var instance = new Animal();
  instance.name = name || 'Tom';
  return instance;
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false

特點:

  1. 不限制呼叫方式,不管是new 子類()還是子類(),返回的物件具有相同的效果

缺點:

  1. 例項是父類的例項,不是子類的例項
  2. 不支援多繼承

推薦指數:★★

4、拷貝繼承

function Cat(name){
  var animal = new Animal();
  for(var p in animal){
    Cat.prototype[p] = animal[p];
  }
  Cat.prototype.name = name || 'Tom';
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

特點:

  1. 支援多繼承

缺點:

  1. 效率較低,記憶體佔用高(因為要拷貝父類的屬性)
  2. 無法獲取父類不可列舉的方法(不可列舉方法,不能使用for in 訪問到)

推薦指數:★(缺點1)

5、組合繼承

核心:通過呼叫父類構造,繼承父類的屬性並保留傳參的優點,然後通過將父類例項作為子類原型,實現函式複用

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
Cat.prototype = new Animal();

// 感謝 @ 的提醒,組合繼承也是需要修復建構函式指向的。

Cat.prototype.constructor = Cat;

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

特點:

  1. 彌補了方式2的缺陷,可以繼承例項屬性/方法,也可以繼承原型屬性/方法
  2. 既是子類的例項,也是父類的例項
  3. 不存在引用屬性共享問題
  4. 可傳參
  5. 函式可複用

缺點:

  1. 呼叫了兩次父類建構函式,生成了兩份例項(子類例項將子類原型上的那份遮蔽了)

推薦指數:★★★★(僅僅多消耗了一點記憶體)

6、寄生組合繼承

核心:通過寄生方式,砍掉父類的例項屬性,這樣,在呼叫兩次父類的構造的時候,就不會初始化兩次例項方法/屬性,避免的組合繼承的缺點

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
(function(){
  // 建立一個沒有例項方法的類
  var Super = function(){};
  Super.prototype = Animal.prototype;
  //將例項作為子類的原型
  Cat.prototype = new Super();
})();

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

感謝 @ 提醒,該實現沒有修復constructor。

Cat.prototype.constructor = Cat; // 需要修復下建構函式

特點:

  1. 堪稱完美

缺點:

  1. 實現較為複雜

推薦指數:★★★★(實現複雜,扣掉一顆星)

附錄程式碼:

示例一:

function Animal (name) {
  // 屬性
  this.name = name || 'Animal';
  // 例項方法
  this.sleep = function(){
    console.log(this.name + '正在睡覺!');
  }
  //例項引用屬性
  this.features = [];
}
function Cat(name){
}
Cat.prototype = new Animal();

var tom = new Cat('Tom');
var kissy = new Cat('Kissy');

console.log(tom.name); // "Animal"
console.log(kissy.name); // "Animal"
console.log(tom.features); // []
console.log(kissy.features); // []

tom.name = 'Tom-New Name';
tom.features.push('eat');

//針對父類例項值型別成員的更改,不影響
console.log(tom.name); // "Tom-New Name"
console.log(kissy.name); // "Animal"
//針對父類例項引用型別成員的更改,會通過影響其他子類例項
console.log(tom.features); // ['eat']
console.log(kissy.features); // ['eat']

原因分析:

關鍵點:屬性查詢過程

執行tom.features.push,首先找tom物件的例項屬性(找不到),
那麼去原型物件中找,也就是Animal的例項。發現有,那麼就直接在這個物件的
features屬性中插入值。
在console.log(kissy.features); 的時候。同上,kissy例項上沒有,那麼去原型上找。
剛好原型上有,就直接返回,但是注意,這個原型物件中features屬性值已經變化了。

12:簡述下前後端,以及伺服器他們是如何如何協同工作的?

前後端分工協作是一個老生常談的大話題,很多公司都在嘗試用工程化的方式去提升前後端之間交流的效率,降低溝通成本,並且也開發了大量的工具。但是幾乎沒有一種方式是令雙方都很滿意的。事實上,也不可能讓所有人都滿意。根本原因還是前後端之間的交集不夠大,交流的核心往往只限於介面及介面往外擴散的一部分。這也是為什麼很多公司在招聘的時候希望前端人員熟練掌握一門後臺語言,後端同學瞭解前端的相關知識。

一、開發流程

前端切完圖,處理好介面資訊,接著就是把靜態demo交給後臺去拼接,這是一般的流程。這種流程存在很多的缺陷。

  • 後端同學對檔案進行拆分拼接的時候,由於對前端知識