這個問題已經有不少人回答過了,其中不乏一些大牛,接下來我做爲一個草根來發表一些我的的見解:php
一、地址輸入過程css
地址欄能夠抽象成一個文本輸入域對象,Chrome應用程序內必定給該對象綁定了鍵盤輸入的回調,該回調將交給操做系統,操做系統會在用戶按鍵時執行全部應用傳遞給它的回調隊列,當操做系統監聽到用戶按下了回車鍵而且在回調隊列遍歷執行到Chrome瀏覽器傳遞給操做系統綁定的回調時,開始解析地址,Chrome會調用網絡模塊對地址進行解析,將其中的應用層協議、主機、端口、虛擬目錄、文件名、參數、錨等各部分解析出來。html
二、DNS解析前端
當發現主機部分不是以IP形式表示時,就會試圖去尋找該主機的IP,在此說一些廢話來解釋下爲何要找IP,由於IP是網絡中每臺計算機的惟一標識,計算機採用IP做爲惟一標識而沒有采用域名做爲惟一標識,我的感受緣由是由於計算機更擅長處理數字,而數字不易於被人類所記憶,所以誕生了DNS域名解析系統html5
咱們本身的PC和手機中其實都運行着DNS客戶端,若是運行在用戶主機上的某些應用程序(如Web瀏覽器或者郵件閱讀器)須要將主機名轉換爲IP地址時,也就是咱們如今的狀況,這些應用程序將調用DNS的客戶機端,並指明須要被轉換的主機名。mysql
DNS客戶端拿着這個主機名依次從本地hosts文件、本地DNS解析器緩存、本地DNS服務器、13臺根DNS服務器、一級域名服務器、二級域名服務器...此外,DNS是應用層協議,全部DNS請求和回答報文使用的UDP數據報通過端口53發送。總之咱們最終能夠拿到目標主機的IP地址jquery
三、瀏覽器http數據包到客戶端網卡css3
內部應該是經過一個對象(相似於XMLHttpRequest對象)將要傳遞的數據進行封裝,具體的數據包格式以下:git
調用系統函數socket,將該請求交給傳輸層,因爲http是基於TCP來傳輸的,所以傳輸層協議是TCP協議,剛纔封裝好的http數據包將做爲TCP段的數據部分,TCP段的頭部封裝了源端口和目標端口github
接下來TCP段會交給網絡層,網絡層使用IP協議,網絡層將整個TCP段做爲IP數據包的數據部分,IP數據包的頭部封裝了源主機IP和目標主機IP
這個IP數據包接下來進入數據鏈路層,數據鏈路層將整個IP數據包做爲數據幀數據部分,數據幀的頭部封裝了源主機MAC地址和下一跳路由的MAC地址,若是是第一跳,能夠理解爲網關的地址,源主機和各個路由器一般經過廣播的方式學習到下一跳路由器的MAC地址
封裝好的數據幀經過物理層(網卡驅動)轉換爲二進制字節再進行傳輸
四、客戶端到服務器端
電腦的網絡適配器(也就是網線接口)能夠鏈接交換器或路由器,而後再連調制解調器(貓)轉變爲模擬信號
我的感受模擬信號從電話線、光纖、網線出去以後在路由器之間作轉發時在各個路由器節點中也被轉變爲了數字信號,而後分析處理完再轉變爲模擬信號再轉發
五、服務器接收到數據並將各層頭部拆解再交給服務器應用程序處理
服務器網卡接收到瀏覽器發來的二進制字符序列,網卡驅動程序分析其目標Mac地址,從而判斷是否該接受該數據包,肯定接收該包以後再交給傳輸層進一步取出端口信息,從而肯定該包到底要轉給應用層中哪一個應用程序,在此,目標端口是80,若是服務器的80端口處於開啓狀態(監聽狀態)則將該數據包交給該服務器應用程序(Apache Nginx等)作進一步分析
對於規模很是小的應用,這臺主機極可能承擔了全部角色(應用服務器、文件服務器、數據庫服務器)
稍微成點規模的應用都會在此布一臺反向代理服務器,根據Request URL頭和Remote Address頭和必定的算法(例如輪尋)對請求進行轉發,轉發到多臺服務器作負載均衡,這樣一來這臺作轉發的服務器訪問量就是轉發到的那些負載均衡服務器的訪問量的好多倍,這也就要求這個服務器可以承受很大的併發量,這種可以承受很大併發量的服務器的典型表明就是Nginx。代理服務器轉發到的負載均衡服務器一般是應用服務器,所謂應用服務器就是咱們的後臺程序(Java PHP Node)所存放的服務器,後臺程序訪問數據庫是常有的事,而數據庫一般不會和應用服務器放在一塊兒,執行這些高級語言編譯成的機器指令必然對CPU和內存有着很高的要求,而數據庫其實本質就是一種特殊的文件系統,所以數據庫讀寫本質上就是對文件的讀寫,文件讀寫必然對機器的I/O接口(硬盤讀寫)性能有着很高的要求,可見應用服務器和數據庫服務器有着不一樣的需求,所以術業有專攻,兩者一般不會放在一塊兒,同理應用中的圖片、音頻、視頻等文件道理也同樣,有專門的處理這些文件類型的設備,所以在有條件的狀況下也會分開存放在不一樣的文件服務器上。
當數據訪問量大到一臺數據庫服務器、一臺圖片服務器、一臺音頻視頻服務器...不能知足需求時,咱們並不該該想着換一臺性能更好的服務器,而是再配置一臺和第一臺服務器性能差很少的服務器,同時和多臺應用服務器爲用戶提供服務的道理同樣,分佈式集羣一般是解決網站高併發、海量數據存儲的問題的慣用手法。
將目光再轉向數據庫,例如新浪微博的服務器,那些明星大腕的微博帳號中存儲的數據訪問量和咱們凡人的數據訪問量相比必定不是一個級別,這就形成了數據庫訪問的不均衡問題,80%的訪問量都集中在20%的數據上,這時緩存就應運而生了,對於緩存有兩種處理方案,一種是直接緩存到應用服務器的內存中,這樣應用服務器能夠很是快速的訪問到數據再作出響應,但問題是自己應用服務器的內存就緊張,再加上緩存的競爭,顯然不合適,因而分佈式緩存服務器就誕生了,即專門拿出一臺或多臺內存超大的服務器作緩存存儲器,目前比較流行的緩存應用有redis。
固然這以後問題還沒完,由於雖然能夠經過從緩存中讀取數據把壓力降下來,可是對數據庫的寫操做依然無動於衷,一般的作法是配置數據庫服務器的主從關係,寫操做發生時應用服務器訪問主服務器,而後作主從複製。當咱們的應用涉及到的用戶遍及全中國時,還能夠架設CDN服務器。。。
稍微扯的遠了一些,一般應用服務器也稱爲主服務器,主服務器接收到http數據包時,會取出Request URL,若是Request URL有值,則去找它對應的虛擬主機,再去找虛擬主機所映射的真實路徑,從而找到服務器端項目目錄
若是直接經過IP地址訪問,則會找默認應用
六、應用服務器對請求的處理過程
在傳統的後臺渲染架構中,一般會根據請求的虛擬路徑例如/User/User/getUserList,定位到某個服務器端腳本過程
對於虛擬路徑,服務器端有專門的入口文件和配置文件進行處理,若是後臺採用典型的三層架構的話,對於index.php/User/User/getUserList,一般表明找到User模塊下的UserController的getUserList方法,首先實例化UserController類,經過獲得的實例化對象調用getUserList方法,該方法可能還會實例化模型UserModel類,模型類一般會讀寫數據,數據源有多是緩存,也有多是數據庫,緩存和數據庫都有可能放在不一樣的服務器中,所以還可能要創建到數據源的鏈接,鏈接過程和瀏覽器請求差很少,若是向redis緩存取數據的話傳輸層TCP段的頭部源端口和目的端口應該是80和6379(可能會出於多實例和安全性的考慮將其改成7200),若是向mysql存取數據的話傳輸層TCP段的頭部源端口和目標端口應該是80和3306,所以UserModel實例化對象應該有從數據源中取出全部user信息的方法,這樣,Model拿到數據,再將其返給Controller,Controller拿到這個數據以後一般會引進來一個模板,對象拿到的數據一般會做爲模板變量傳進去,這樣本來靜態的html頁面就由於模板變量的介入而變成動態頁面,這個模板這樣動態化了以後就會將其返回給瀏覽器,這種情形下瀏覽器拿到的將是一個處理好了部分數據的html頁面,將直接塞到頁面中去
注意咱們剛纔提到了瀏覽器拿到的是一個處理好了部分數據的html頁面,爲何是部分數據呢?由於瀏覽器是要和用戶交互的,在服務器端怎麼能知道用戶有什麼動做呢?例如咱們下面列出來的這個省市聯動的狀況:
注意到,咱們只是把全部的省份循環出來了,但並無把城市循環出來,緣由也很簡單,中國有34個省級行政單位這個毋庸置疑,但問題是城市總得是某個省下面的,具體哪一個省是要根據用戶的選擇來加載的,而用戶的選擇這個操做必定發生在瀏覽器端,而咱們渲染的這一步發生在服務器上,怎麼可能知道選擇了哪一個省呢,因此這部分數據並無渲染,而是等用戶作出選擇以後異步的經過ajax告訴服務器用戶選擇了哪一個省,再加載對應的城市數據,咱們在此提到了異步加載,所謂異步加載也就是說只是發一個請求讓服務器返回城市對應的數據,瀏覽器拿到這個數據以後將id爲city的select填充滿該省下轄的城市,注意在此期間province部分的select數據並無動,即瀏覽器和服務器都沒有從新去渲染,在此值得一提的是,在ajax誕生以前(1998年之前),不論用戶作什麼操做都會向服務器發一個請求,包括咱們這裏的獲取城市數據,這種狀況下option裏面可能還套了一個a連接,當選擇了一個省以後直接刷新頁面,服務器從新把省、市的數據從新渲染一遍一併返給瀏覽器
早期業務不太複雜,數據量小的時候這麼作徹底沒問題,可是後來瀏覽器端的操做愈來愈多,操做一次請求一次服務器,請求的次數也就愈來愈多,服務器壓力愈來愈大,還有典型的場合是表單校驗,瀏覽器端用戶即便什麼都沒填(不須要服務器端的任何幫助就知道這表單必定是錯誤的)也向服務器發請求,事無鉅細的請求服務器。。。終於異步的概念被提了出來,Javascript在被沉寂了遺忘了多年以後被人拾起來,在此以前Js僅僅就是在頁面上弄個點擊隱藏顯示、圖片輪換等微不足道的事情。
剛纔咱們說到這是傳統的後臺處理方式,異步的引入的確讓服務器端性能有所好轉,可是用戶的要求在慢慢變高,所以這樣作還遠遠不夠,咱們但願盡最大可能的減小服務器的壓力,能交給客戶端處理的就交給客戶端處理,畢竟人多力量大,假如1萬人同時請求一臺服務器去渲染一個全部省份的select,服務器要渲染1萬次,所以近幾年又誕生了一種新的處理方式就是客戶端渲染,咱們經過URL僅僅是請求服務器返回一個空的頁面:
這個空的頁面一加載完成,立刻再向服務器發一個請求,請求全部省份數據,注意這裏的省份的數據是json的格式,和上面說的返回一個拼接成的html串相比數據包長度減少了不少
所以,當一樣有1萬人請求服務器時服務器所作的處理要簡單不少,只需單純的返回從庫裏取出的數據便可(一般會轉換爲json形式)
固然這樣作的同時,就會發現瀏覽器端在ajax的success回調中僅僅拿到了一個很是輕量的json,接下來的操做(操做DOM)由瀏覽器本身處理,不過瀏覽器給提供的dom接口很是底層,並且設計極其反人類,還有諸多兼容性問題,所以瀏覽器端的處理邏輯將會變得很複雜,最開始的時候搞後臺的大神們不覺得然,感受這些瀏覽器端的刪刪改改的處理沒什麼了不得的,複製粘貼抄起傢伙就幹,等到乾的時候感受各類不爽。。。後來的後來,在2008年左右,終於誕生了web前端工程師這個崗位,這個崗位主要的任務就是專門來處理瀏覽器客戶端的各類交互。還拿我們剛纔的這個省市聯動的例子,在獲取省份或城市數據成功了以後前端拿到了省份或城市的數據,而後再調用瀏覽器提供的操做DOM的API建立一個個option,而後再附加到select中去,前面提到瀏覽器端給提供的DOM接口很是底層,並且還不太好用,兼容問題又多,更重要的是前端每天都在幹這些事,寫的多了天然以爲不爽,因而便出現了jquery一統前端江湖的局面,能夠說作前端的人jquery都是必備的基本技能,固然jquery的學習門檻很是低,並且處理了全部的瀏覽器兼容問題,還提供了鏈式調用的方便寫法,並且jquery提供的功能也特別豐富:強大的選擇器、鏈式操做、事件綁定、ajax、動畫函數,比較高級一點的API有函數隊列、延遲對象、數據緩存等等。所以直到今天,jquery依然很火爆
而隨着時間的推移,前端處理的數據毫不是像省市聯動這種小兒科的東西同樣那麼簡單了,愈來愈多的業務邏輯放在前端,jquery慢慢顯露出它的不足,例如咱們須要渲染下面這種形式的一個表格:
每趟列車的數據確定是一個很大的json,而後放着列車的信息,用js寫出來以後效果和下面這種的差很少:
能夠看到,這段代碼不只包含了dom操做,還綁定了事件,事件裏面又有一些效果,有些a鏈接還跳到一個新頁面,有些地方還須要再經過ajax獲取更詳細的信息。。。整個一坨代碼就像一個大雜燴,亂七八糟。雖說能夠封裝一個函數把各個功能打散,可是就以我我的經從來看,這種開發模式下單個文件寫個三五千行、最頂上的全局變量定義個十幾二十個都是常事,後期的維護更是一場噩夢。
這樣的問題不光是像我這樣的草根遇到了,全世界的前端都面臨這樣的問題,終於,在2009年,Google公司內部某個項目在用傳統的jquery開發模式下代碼寫了17000多行,而其中一位叫Misko Hevery的前端工程師就提出了改造它的想法,如今看來我我的認爲這位大神的整體思想是把後臺渲染的思路拿到前端來,也就是用Js這門語言寫了一個html的編譯器。固然回想起後臺渲染的那個頁面,我我的惟一的感受就是不三不四,由於頁面中有一部分數據是後臺渲染好的,還有一部分和用戶交互的數據是前端js加上的,這樣一來這個html頁面就通過了後臺和前端兩種人之手,除了在交互方式上感受各類不爽以外,在後期維護中這是典型的灰色地帶,出現問題責任沒法明確分清、相互推脫。而這位大神的偉大之處就在於把數據渲染和用戶交互進行了統一,一併劃到前端來處理,從處理的方式上看感受很是流暢,這個思路就是Angular框架的前身
以前個人一位40多歲高齡的老大曾經這樣跟我說過使用Angular和使用Jquery的區別:Jquery僅僅是把原生的API封裝了一下,說白了就是個庫函數,並無達到框架的做用,而Angular是真正改善Js代碼結構的真正意義上的框架。用了Angular以後,上面12306的那個例子就能夠寫成:
和以前的Jquery開發方式相比實在是好了太多
Angular的出現我我的認爲具備劃時代的意義,由於它把前端再一次推上了一個新的高峯,此後的2013年Facebook發佈了React,2015年尤雨溪發佈了Vue,實際上都是對於DOM渲染提供的一種新的處理思路,例如React推崇經過組件化的方式來組合web項目,而Vue則是把Angular和React結合在了一塊兒,可是Angular絕對是具備開創性意義的一個框架
固然Angular並非一點缺點都沒有,首先使用Angular的項目幾乎都作成了單頁面應用,而單頁面應用的首屏加載了全部的Controller Directive Services以及各類庫,所以首屏性能極差;其次,因爲數據都經過Js渲染,對於SEO來講很是不友好;再者,Angular1對於移動端支持的不太好,我我的以前在公司作過一個Angular+Ionic的webapp,最後的體驗是卡到爆
對於Angular和React的學習成本,門檻的確很是高;而Vue以其簡單易學的API、上手較快的特色在github上的star數正在猛增,可是我我的仍是認爲每一個框架的出現必然有它的歷史意義,確定是應運而生的,所以無所謂哪一個框架好,哪一個很差,只是適用的場合不太同樣而已,當前前端的框架至關之多,就以我工做的這幾年內接觸過的大大小小的庫和框架絕對超過二三十種,庫和框架永遠都學不完,所以我我的感受學習框架內部的API設計思路,學習它經過什麼方式解決了什麼問題,這纔是學習框架的關鍵所在
對於Angular的缺點我我的以爲不過重要,由於適合作單頁面應用的項目每每對SEO的要求不過高,而性能的問題經過按需加載以及壓縮、合併代碼減小請求次數,下降請求量也能夠從必定程度上避免,並且首頁性能差換來的是接下來各個頁面良好的用戶體驗,Angular二、React和Vue已經提出了SSR(服務器端渲染)的思路來解決這些問題了。
Angular2已經對這些問題有所改善,期待ECMAScript6普及的那一天,Angular會再次輝煌起來,固然Angular2的學習門檻更高,Angular1和Angular2的區別基本上是象牙和象牙塔的區別。
七、數據到瀏覽器中的處理過程
事實上咱們能夠猜想一下瀏覽器內部的工做流程:應該是在地址欄中的值改變時(因爲用戶的輸入或者頁面的跳轉)調用相關的接口去獲取數據,例如若是地址欄中輸入了file:///C:/Users/lenovo/Desktop/attrtest.html,瀏覽器應該就會去本地對應目錄下尋找attrtest.html文件,地址欄中若是輸入了https://www.baidu.com/,瀏覽器使用http或https等應用層協議對數據進行解析,再去網絡中尋找對應的數據,根據響應頭中提供的數據類型(Content-Type響應頭)分別作不一樣的處理,接下來解釋一下當經過http或https協議獲得的數據中Content-Type響應頭獲得的類型是text/html時或經過file協議取到了html類型的文件時所作的處理:
根據HTML結構構建DOM樹,根據CSS結構構件render樹,遍歷這兩棵樹各個節點而後向頁面中渲染
遍歷兩棵樹的節點過程當中,若是發現連接屬性,例如DOM樹中link標籤的href,img的src,script標籤的src,video和audio標籤的,css3自定義字體加載的文件,以及render樹種background屬性的url,會再開新的請求去請求對應的資源
我的感受:link標籤的href、script標籤的src加載完以後觸發DOMReady事件(DOMContentLoaded和onreadystatechange),當圖片、視頻、音頻等資源加載完時觸發onload事件
實際上瀏覽器拿到一個html頁面以後解析全部的html、css、js的操做其實就是對一組DOM節點對象及其屬性(其中典型的就是style屬性)的增刪改查操做
至於說瀏覽器內部究竟是如何渲染頁面的,如何將一個個div根據匹配的css樣式生成一個個DOM對象,這些DOM對象在C++類或結構體中是怎麼表示的,都有哪些屬性哪些方法,如何渲染到頁面中的,我我的還在學習中,等後期學完C++,看了必定的webkit和V8的源碼以後再來補充。在此極力推薦這篇文章:how browsers work
在此格外要提一下JavaScript的執行流程,咱們從宏觀到微觀的順序來講明:
瀏覽器拿到一個html頁面以後可能會遇到好多個script標籤,無論這些script標籤放到哪裏,老是落後於css的執行,換句話說,若是css和Js分別對某個節點的某個樣式進行操做,無論css寫在了Js的前面仍是後面,CSS老是會優先於Js執行:
結果發現div是綠色的
瀏覽器在解析每一個script標籤時會作判斷,判斷它有沒有src屬性,若是有的話就從新發起請求,請求src值對應的腳本資源,不然查看script標籤內部是否有腳本,找到腳本以後執行,若是在一個script標籤上既加了src又在標籤內部寫了一段腳本,則只去加載遠程腳本資源,而標籤內的腳本不會執行,如下代碼myj變量找不到,所以會報錯:
能夠猜想,瀏覽器在加載執行js的時候是同步的,例如對於下面這段代碼
最開始遇到第一個script標籤,發現它帶有src,那麼瀏覽器會將其下載完,緊接着再解析該段腳本,而後再往下走,發現第二個script標籤,沒有src屬性,因而就直接執行裏面的腳本,因爲阻塞加載,後面的script才能夠用到前面從遠程加載來的jquery腳本中定義的變量$
這種阻塞加載的機制在html5中作出必定改觀:html5爲script標籤新增長了一個屬性:async,該屬性表明script標籤裏面的內容是否要異步加載
若是 async 屬性爲 true,則腳本會相對於文檔的其他部分異步執行,這樣腳本會在頁面繼續解析的過程當中執行。
若是 async 屬性爲 false,而 defer 屬性爲 true,則腳本會在頁面完成解析後執行。
若是 async 和 defer 屬性均爲 false,那麼腳本會當即執行,頁面會在腳本執行完畢後繼續解析。
JavaScript是一個單線程執行的指令序列,每一個script標籤內的代碼會分別被瀏覽器解釋,雖然有變量的提高,可是後面的script標籤中定義的變量不會提高到前面的script標籤中,這一點要格外注意,例以下面的代碼中第一個script標籤裏面console.log(a);是要報錯的
可是後面的script代碼塊可使用前面的script代碼塊中定義的變量,由於它們都做爲屬性掛在了全局對象window上,例如:
函數的提高也是一樣的道理
Js中一切接對象,數組、json、本身定義的構造函數實例化以後的對象天然沒必要多說,函數也是對象,就連數字、字符串、布爾這些基本類型的值也能夠當作是對象,我我的對對象的理解是對象是一個屬性和方法的集合,咱們能夠經過點和中括號的形式來對對象進行set或get的操做,咱們能夠經過下面這幾個例子來證實這個觀點:
這個例子中咱們把js中幾種典型的對象列了出來,並分別定義了各類類型的對象,並且經過點或中括號的方式訪問或設置了對象的屬性或方法,這裏有幾點須要咱們注意:
一、對於基礎類型的對象(數字 字符串 布爾),在set/get屬性和方法時瀏覽器會生成一個臨時對象,set/get操做結束後該對象被回收,而複合類型的對象會在其所處的做用域可用的時間段內常駐於堆內存中,所以複合類型的對象在js中又叫引用類型,也就是說在其所處的做用域可用的時間段內經過指向它的各個指針對其進行修改時修改的都是一個東西,同時,若是指向該對象的指針被賦值爲其餘值,該指針就不指向該對象了,也就不能經過該指針訪問對象中的屬性和方法了,同時咱們也能夠猜想,瀏覽器內部的垃圾回收機制中有可能會監聽指向該堆空間的指針,若是沒有指針指向該堆空間了,那該對象也該被回收了
二、咱們像上面那個樣子寫,好比var a = 1; var arr = [1,2,3]; function fn(){},其實本質上就是在建立對象,分別建立數字類型的、數組類型的、函數類型的對象。而咱們同時也能夠看出,對象是分「類型」的,而實際上咱們在建立每一個對象的時候,都會默認建立一個名爲constructor的屬性,該屬性值爲函數類型。其實,JavaScript給咱們提供了一種經過構造函數建立對象的機制,例如我想建立一個數組類型的對象除了能夠經過var arr = [1,2,3];的方式,還能夠經過var arr = new Array(1,2,3);這種構造函數的方式;再如,咱們建立一個普通對象除了能夠經過var obj = {a: 1};的方式,還能夠經過var obj = new Object();obj.a = 1;這種構造函數的方式,而構造函數這種方式其實是更爲通用的一種方式,由於咱們能夠自定義一個構造函數來建立咱們本身想要的一種對象類型,再去實例化該類型從而建立該類型的對象。而咱們同時也能夠猜想,瀏覽器內部其實是把var obj = {a: 1};和var obj = new Object();obj.a = 1;這兩種建立對象的方式作了相同的處理,可能在詞法分析階段不一樣,可是在語法分析構成AST、中間代碼、目標代碼生成階段的處理應該是徹底一致的,而之因此出現var obj = {a: 1};這種定義對象的方式是由於咱們常常須要定義這種對象,而每次new Object這樣寫太過於繁瑣,所以這其實就是瀏覽器給咱們提供的一種建立對象的簡便寫法而已
三、經過上面的分析,相信你們對對象已經有了一個初步認識,那麼對象與對象之間必然不是獨立的關係,它們之間必定存在着某種關聯,沒錯,確實是這樣,首先咱們考慮這樣一種情景:對於數組,全部數組對象都有push pop等方法,若是在每一個對象所屬的堆內存空間中都給他們分配各自的push pop空間,這就有點太浪費了,由於無論是哪一個數組對象,push和pop的操做時徹底同樣的,根本不必一人一份,所以這些東西必定要共享才能夠。實際上當咱們每次建立一個對象時,該對象會自動建立一個__proto__屬性,這個__proto__屬性就指向該對象的原型對象,經過剛纔的分析,相信你們已經猜到,所謂原型對象,其主要功能就是存放一類對象的公共部分屬性和方法的對象,其實咱們還能夠猜想,實際上全部的對象是否是都有一些公共的方法呢,沒錯,實際上全部的對象都有兩個方法:valueOf和toString,咱們不可能在每一個對象的堆空間中存放這兩個方法,若是在各類類型對象的原型對象所處的堆空間中存放valueOf和toString這兩個方法的話彷佛也有一些浪費,畢竟原型對象有可能也挺多的,因而,更進一步的抽象思路來了:原型鏈,原型對象也是對象,原型對象也能夠有原型,所以原型對象的__proto__還能夠再往上指,那麼最上面的那個對象是誰呢?就是Object.prototype,這個對象就沒原型了,由於已經到頭了。
能夠看出原型是同類對象的一個公共對象,這些對象的__proto__屬性都指向它,而構造這一類對象的也是同一個構造函數,由此咱們能夠猜想:構造函數和原型對象之間有什麼關係嗎?確定是有的:構造函數有一個prototype屬性,這個prototype屬性就指向經過這個類實例化建立出來的對象的原型對象
對象能夠經過constructor訪問到建立本身的構造函數
綜上,聯繫對象之間的橋樑是——原型(即對象的__proto__屬性)
其實Js中繼承的原理就是咱們剛纔分析的這些:
在inheritPrototype函數內部咱們明顯發現咱們將子類subType的prototype指向F實例化對象,而F類的prototype已經被咱們修正成父類的prototype了,所以至關於咱們的子類指向了父類的prototype,天然能夠訪問父類prototype上的方法了
固然對象自身身上的屬性繼承的時候還須要藉助call和apply
四、在瀏覽器的環境中實際上已經建立了不少內置對象了,具體有哪些內置對象就不一一闡述了,能夠參考下圖:
接下來是我我的對函數對象的一些看法:因爲函數也是對象,那麼函數自己也必定是屬性和方法的集合,理解這一點能夠參考經典的面嚮對象語言——Java的設計:Java中類也有方法和屬性,被稱爲類屬性和類方法(或者靜態屬性和靜態方法),既然如此,能夠猜想在Java虛擬機內部對類和類的實例必然有一些相同的處理手段,再進一步抽象一下,能夠猜想類也是一個特殊的對象,固然等後期對Java比較熟悉以後再看一下深刻理解Java虛擬機這本書以後再過來補充
關於對象的話題暫且先說這麼多,接下來進入下一個話題,做用域:
能夠猜想在瀏覽器引擎內部,做用域是實實在在的對象,只不過在Js中它爲咱們隱藏了做用域的細節
2017年6月3日編輯====================
在ECMAScript5以前,js中只有兩種做用域:全局做用域和局部做用域(函數在執行時生成的做用域),函數執行時會生成一個新的做用域對象,並在棧上開一塊新的私有空間用於存放當前該函數中各個變量,當函數執行結束時,做用域對象被回收,棧上的私有空間也被釋放,這是正常的函數執行的結果。可是有種不正常的狀況——閉包:當一個函數在執行完以後最後返回來一個函數供外部調用,並且該返回值函數中還訪問到了父函數中的某個變量,那麼即便父函數執行完了父函數中的這個變量也還會駐留在內存中不會釋放,例如:
這個案例中的變量a就在函數closure執行結束以後一直駐留在內存中,由於外面innerFn函數還會調用到它,而正由於一直在內存中,因此每次均可以對同一塊內存空間操做,因此console出來的a的值每次都會變
實際上函數內部並不必定非得返回函數類型的值才叫閉包,只要返回回來的東西用到了父函數的變量那都叫閉包,例如能夠返回回來一個對象,對象的某個方法調用到了父函數的某個變量,這種狀況其實也是閉包,例如:
callback函數內部_callbackCache變量其實在callback執行完以後也不會被釋放,由於返回的對象在外部調用其add方法時會用到這個變量,實際上這種思路在jQuery以及Angular內部用的很是多,例如jQuery內部的數據緩存管理、隊列管理、回調函數、延遲對象等等,Angular裏面把全部註冊的模塊都放到一個閉包變量中,把每一個模塊下綁定的constroller、directive、service、provider也放大對應的閉包變量中等等,就不一一舉例了
參考連接:
一、DNS解析的過程是什麼? https://www.zhihu.com/question/23042131
二、當時發生了什麼? https://github.com/skyline75489/what-happens-when-zh_CN
三、網卡(網絡適配器),貓(調制解調器),路由器三者有什麼區別? https://www.zhihu.com/question/27142839
四、WAN口和LAN口有何不一樣 https://zhidao.baidu.com/question/180687224.html
五、路由器與交換機的本質區別 http://jingyan.baidu.com/article/8065f87fe57f372330249851.html
六、常見的網站服務器架構有哪些? https://www.zhihu.com/question/20657269
七、圖解正向代理、反向代理、透明代理 http://z00w00.blog.51cto.com/515114/1031287
八、從輸入 URL 到頁面加載完成的過程當中都發生了什麼事情? http://fex.baidu.com/blog/2014/05/what-happen/
九、瀏覽器內部工做原理 http://kb.cnblogs.com/page/129756/
十、Javascript的執行過程詳細研究 http://blog.csdn.net/cxiaokai/article/details/7552653
十一、HTML屬性與DOM屬性的區別? https://segmentfault.com/q/1010000004100696?_ea=489898