天天看點

JQuery之父John Resig帶你了解無處不在的JavaScript

本文包括以下内容:

  • JavaScript核心語言特性
  • JavaScript引擎核心要素
  • JavaScript開發中的3個最佳實踐

我們先來聊聊Bob。2000年年初,在花了幾年時間學習C++桌面應用開發之後,新晉程式員Bob從學校畢業,奔向了軟體開發的廣闊天地。那個時候,網際網路的跨越式發展才剛剛開始。每個公司都想成為下一個亞馬遜。有鑒于此,他做的第一件事就是學習網絡開發。

最初他用PHP動态生成網頁,并在其中穿插JavaScript代碼來實作複雜的功能,例如表單驗證,甚至是動态的頁内計時器。時光如梭,幾年之後,智能手機已然成了氣候。預見到一個龐大的新興市場即将形成,Bob決定先行一步,開始學習使用Objective-C和Java來建立運作于iOS和Android上的移動端應用。

幾年來,Bob開發了很多成功的應用軟體,并且都需要維護和擴充。遺憾的是,日日輾轉于不同的程式設計語言和應用架構之間,可憐的Bob已經筋疲力盡了。

現在我們來談一下Ann。兩年前,Ann在獲得軟體開發相關的學位後畢業。她的專業方向偏向于網絡以及基于雲的應用開發。她已經開發出了一些中等規模的網絡應用。這些應用基于現代的模型—視圖—控制器(Model—View—Controller, MVC)架構,并且還有相應的移動應用供iOS和Android使用者使用。她還開發了一款能夠同時在Linux、Windows和OS X上運作的桌面應用,甚至着手将其改為完全基于雲的無伺服器的版本。最重要的是,她所做的所有事情都是通過JavaScript來實作的。

真是一件了不起的事情。Bob花了10年用5種語言才完成的事情,Ann隻需要2年以及1種語言就完成了。縱觀整個計算機的發展史,還沒有哪個特定的知識集合能夠如此容易地通行于不同的領域,并發揮作用。

1995年的一項10天内倉促完成的項目,現在卻成為了世界上使用最廣泛的程式設計語言之一。JavaScript現在确确實實是無處不在了,這得歸功于更強大的JavaScript引擎和一衆架構的出現,如Node、Apache Cordova、Ionic和Electron,是它們讓這門粗陋的語言沖出了網頁的牢籠,飛向了更廣闊的空間。此外,如同HTML一樣,這門語言本身也正處于期待已久的進化當中,進而被打造成更加适合現代應用開發的語言。

在本文中,我們首先要保證讓你了解所有你需要了解的關于JavaScript的内容,這樣無論你的情況與Ann還是Bob更為接近,都能夠開發各種類型的應用。

你知道嗎?

  • Babel和Traceur是什麼?為什麼它們對現在的JavaScript開發者至關重要?
  • 在網絡應用中,什麼才是浏覽器的JavaScript API的核心組成部分?

1.1 “了解”JavaScript語言

随着職業生涯的發展,許多有着與Bob和Ann類似經曆的JavaScript程式員,都到了在工作中運用構成這門語言大部分的元素的階段。但實際上,很多時候這些技能的運用都處于相當初級的層次。我們對此做出的猜測是,由于JavaScript(采用類似于C語言的文法)有着與其他得到廣泛使用的類C語言(比如C#和Java)相近的皮相,進而給人留下了與這些語言相似的印象。

人們總是覺得他們對C#或者Java的了解,能為他們了解JavaScript的工作原理打下堅實的基礎。然而這是一個陷阱。與其他主流語言相比,JavaScript函數式語言的血統更多一些。JavaScript中的一些概念從根本上不同于其他的語言。

這些根本性的差異包括以下内容。

  • 函數是一等公民(一級對象)——在JavaScript中,函數與其他對象共存,并且能夠像任何其他對象一樣地使用。函數可以通過字面量建立,可以指派給變量,可以作為函數參數進行傳遞,甚至可以作為傳回值從函數中傳回。在第3章中我們将花費大量篇幅解釋函數,探索它作為第一類對象在編寫代碼中的好處。
  • 函數閉包——大部分人對閉包都缺乏了解,然而它卻從根本上例證了函數之于JavaScript的重要性。盡管就目前而言,了解當函數主動維護了在函數内使用的外部的變量,則該函數為一個閉包就已經足夠。現在還沒看到閉包的好處也不要緊,第5章中我們會把它搞得一清二楚。除了閉包以外,在第3章和第4章中我們也會深入探讨函數的方方面面,第5章中還會讨論辨別符作用域。
  • 作用域——直到最近,JavaScript都還沒有(類似C語言中的)塊級作用域下的變量,取而代之則隻能依賴函數級别的變量和全局變量。
  • 基于原型的面向對象——不同于其他主流的面向對象語言(例如C#、Java、Ruby)使用基于類的面向對象,JavaScript使用基于原型的面向對象。很多開發者是從基于類的面向對象語言(例如Java)轉而開發JavaScript,他們試圖像開發Java一樣開發JavaScript。然而由于某些原因,他們會因為結果與預期不同而感到出乎意料。這種情況就是我們要深入了解原型的原因,我們要知道基于原型的面向對象如何工作,以及怎樣在JavaScript中實作面向對象。

對象、原型、函數和閉包的緊密結合組成了JavaScript。了解這些概念的密切聯系能大大提高你的程式設計能力,為你開發各種類型的應用提供堅固的基礎,無論你的應用是開發在網頁上、桌面應用上、移動應用上還是伺服器端。

除了這些基本概念,JavaScript的一些其他功能也能幫你書寫優雅高效的代碼。對于經驗老道的Bob一樣的開發者來說,這些部分特性在其他語言中也出現過,例如Java和C++。我們會特别聚焦于以下特性。

  • 生成器,一種可以基于一次請求生成多次值的函數,在不同請求之間也能挂起執行。
  • Promise,讓我們更好地控制異步代碼。
  • 代理,讓我們控制對特定對象的通路。
  • 進階數組方法,書寫更優雅的數組處理函數。
  • Map,用于建立字典集合;Set,處理僅包含不重複項目的集合。
  • 正規表達式,簡化用代碼書寫起來很複雜的邏輯。
  • 子產品,把代碼劃分為較小的可以自包含的片段,使項目更易于管理。

深入了解JavaScript的基礎知識,以及學習如何最大程度地利用JavaScript的進階特性,能夠讓你的代碼編寫水準提升到一個更高的水準。磨煉代碼技能、并将這些概念和特性連貫起來也能讓你對JavaScript的了解更上一層樓,進而為你編寫各種類型的Javscript應用賦予強大的創造力。

1.1.1 JavaScript是如何發展的

ECMAScript語言标準化委員會已經完成了ES7/ES2016版本JavaScript的制定。對于JavaScript(至少相對于ES6而言)ES7是個較小的更新。這是因為委員會的未來目标是每年都能為JavaScript更新較小的改動。

本書中将徹底探索ES6以及ES7的新特性,例如用于處理異步代碼的async函數(第6章中會讨論)。

注意

在本文中涉及ES6/ES2015或ES7/ES2016的JavaScript特性時,你将能看到,凡是在提供浏覽器是否支援該特性的連結旁邊都會有一個這樣的圖示。
JQuery之父John Resig帶你了解無處不在的JavaScript

盡管每年都能增量釋出語言新特性是個利好消息,但這并不代表Web開發者能在标準一釋出就能立即使用新特性。由于JavaScript代碼必須由JavaScript引擎來執行,是以我們必須耐心等待心愛的引擎更新,進而能支援那些令人激動的新特性。

盡管JavaScript引擎開發者也在力求始終保持對最新特性的支援,但開發者還是很可能陷入想使用新特性卻還沒被支援的困境。

好在你還能通過下列方式https://kangax.github.io/compat-table/es6/、http://kangax. github. io/compat-table/es2016plus/以及 https://kangax.github.io/compat-table/esnext/進行檢視,由此保持對浏覽器支援狀态的了解。

1.1.2 如今的轉換編譯器已經能讓我們體驗未來的JavaScript

由于浏覽器版本的飛速釋出,我們通常不需要等待多久就能等到對JavaScript的支援。但當我們想利用JavaScript的最新特性時,也往往會被殘酷的現實綁架:使用者依然在使用老舊的浏覽器。這時該怎麼辦?

解決這個問題的方式之一是使用轉換編譯器transpilers(即“轉換器+編譯器”,“transformation + compiling”),這類工具能夠把最前沿的JavaScript代碼轉換為等價的(如果不能實作,則使用相似的)能在目前浏覽器中運作的代碼。

最流行的轉換編譯器是Traceur和Babel。使用如下教程可以很容易地配置它們:https://github.com/googLe/traceur-compiler/wiki/Getting-stanted或http://babeljs.io/docs/setup。

本書中,我們會主要集中讨論浏覽器中的JavaScript代碼。為了有效利用浏覽器平台,你需要多多實踐,學習浏覽器的内部原理。讓我們開始吧!

1.2 了解浏覽器

現如今,JavaScript應用能在很多環境中執行。但是,Java Script最初的運作環境是浏覽器環境,而其他運作環境也是借鑒于浏覽器環境。本書将重點專注浏覽器環境。浏覽器提供了多種概念和API讓我們來探索,如圖1.1所示。

JQuery之父John Resig帶你了解無處不在的JavaScript

圖1.1 用戶端Web應用依賴于浏覽器提供的架構。我們主要讨論DOM、

事件、計時器和浏覽器API

我們将集中讨論如下概念。

  • 文檔對象模型(DOM)——DOM 是Web應用的結構化的UI表現形式,至少最初由Web應用的HTML代碼構成。為開發大型應用,你不僅需要深入了解JavaScript 的核心機制,還要學習 DOM 是如何構成的(第2章)以及如何書寫有效的DOM操作代碼(第12章)。你将學會如何創造進階的、動态的UI。
  • 事件——大部分JavaScript應用都是事件驅動的應用,這表示大部分代碼執行在對某個特殊事件響應的上下文中。這樣的事件例如網絡事件、計時器、使用者生成事件例如點選、滑鼠移動、鍵盤按壓事件等。是以,第13章中我們将完整探索事件機制。我們特殊關注計時器,計時器通常像個謎團一樣,但它能幫我們處理複雜編碼任務:例如長期執行的計算和流暢的動畫。
  • 浏覽器API——幫助我們與世界互動,浏覽器提供擷取裝置的資訊、存儲本地資料或與遠端浏覽器互動的API。本書我們會探索其中的一些API。完善程式設計技能并對浏覽器提供的API有深入了解能讓你走的更遠。但是遲早,你将會遇到浏覽器的不一緻性等問題。在完美的世界中,所有浏覽器都應該沒有缺陷,應該都能以一緻的方式支援Web标準。然而我們的現實世界并不完美。

近來浏覽器的品質已經大大提高了,但我們仍然需要面對一些缺陷:例如缺失的API、某個浏覽器的奇怪問題。針對浏覽器的這些問題開發出一種易于了解的機制,并搞清楚它們的差異和寬松模式,這與精通JavaScript幾乎同等重要。

當我們開發浏覽器應用或JavaScript庫時,選擇支援哪個路藍旗是很值得深思熟慮的。我們希望全部支援,但受限于開發測試資源要求或其他要求。是以在第14章中,我們将徹底地探索跨浏覽器開發的政策。

開發高效的跨浏覽器代碼顯著依賴于開發者的經驗和技巧。本書旨在提高開發者技能水準,是以讓我們通過目前的最佳實踐來開始學習吧。

1.3 使用目前的最佳實踐

精通JavaScript語言和掌握跨浏覽器代碼問題對于專家級Web應用開發者來說是重要課題,但它們不是整個藍圖。若想進入整個聯盟,你還需要展示出一些已經被大量先前開發者所證明能夠開發出高品質代碼的特質。這些特質被稱為最佳實踐,是以你除了精通JavaScript語言以外,還需要具有以下特質:

  • 調試技巧;
  • 測試;
  • 性能分析。

在程式設計中把這些技能有效結合在一起非常重要,本書會使用它們。接下來看看這些技巧。

1.3.1 調試

以前,調試JavaScript代碼意味着使用alert來驗證變量的值。好在,由于Firefox浏覽器的開發者擴充Firebug的流行,是以調試JavaScript代碼的能力大大增強了。所有主流浏覽器的類似工具也都被開發出來:

  • Firebug——開發者擴充工具Firefox的流行成為了調試工具的開端;
  • Chrome DevTools——由Chrome 團隊開發,并應用在了 Chrome 和 Opera浏覽器中;
  • Firefox開發者工具——包含在Firefox中的工具,由Firefox 團隊開發;
  • F12 開發者工具——Internet Explorer 浏覽器 及微軟 Edge浏覽器中包含的調試工具;
  • WebKit 檢視器——Safari中包含的調試工具。

如你所見,主流浏覽器都為開發者提供了調試Web應用程式的工具。使用alert來調試JavaScript代碼的日子一去不複返了!所有這些工具都有着類似于Firebug最初引入的概念,故而它們都提供着相似的功能:探索DOM、調試JavaScript、編輯CSS樣式和跟蹤網絡事件等。其中的每樣工具都做得很棒。你既可以使用你自己選擇的浏覽器所提供的調試工具,也可以使用你發現缺陷時所用的浏覽器調試工具。

除此之外,你也可以使用其中的幾個工具,例如用Chrome開發者工具來調試其他類型的應用,例如 Node.js應用(在附錄B中,我們會向你介紹一些調試技術)。

1.3.2 測試

在本書中,我們會使用一些測試技術來確定示例代碼按預期執行,同時這些測試技術也用于展示一般情況下如何測試代碼。我們用于測試的主要工具是一個斷言函數,其目的在于斷定某個假設是真值還是假值。

該函數的一般形式如下所示:

assert(condition, message);

第一個參數是一個應為真值的條件,第二個參數是當斷言為假時所展示的一句話。

例如:

assert(a === 1, "Disaster! a is not 1!");

如果變量的值不等于1,則斷言失敗,然後那段有點兒戲劇性的消息就會被展示出來。

注意

 

斷言函數并不是JavaScript的标準特性,是以我們在附錄B中會展示它的實作。

1.3.3 性能分析

分析性能是另一個重要實踐。盡管JavaScript引擎已經讓JavaScript以驚人的效率提升,然而我們依然沒有理由書寫粗糙低效的代碼。

我們會使用如下的代碼來收集性能資訊:

console.time("My operation");  

⇽--- 開始計時器for(var n = 0; n < maxCount; n++){

 /*perform the operation to be measured*/}  

 ⇽--- 執行多次操作console.timeEnd("My operation");  

 ⇽--- 停止計時器

這段代碼中,我們把要被測量的代碼放在兩個計時器調用之間,分别是内置console對象上的time和timeEnd方法。

在操作開始執行之前,調用console.time啟動一個命名計時器(本例中計時器名為 My operation)。然後在特定的循環次數下運作代碼(本例中運作maxCount次)。由于一次操作執行太快很難測量,是以我們要多次運作代碼進而取得一個能夠測量的值。運作次數可以成百上千,甚至上萬,其完全依賴于将被測量的代碼性質。幾次摸索後我們就能得到一個合理的值。

操作結束後則用相同的計時器名字調用console.timeEnd。随後浏覽器就會輸出從開始到目前的時間差。

把這種技術與前面所學到的最佳實踐技術統一起來,你對JavaScript的開發能力就會大幅度提升。在浏覽器提供的有限資源下,在浏覽器能力和相容性逐漸複雜的世界中開發應用,需要一套健壯和完整的技巧。

1.4 提高跨平台開發能力

Bob初入Web開發行業時,他會發現每個浏覽器都有一套自己的腳本及UI樣式的解釋方式,并試圖鼓吹他們的方式才是最好的方式,這使開發者們沮喪地咬牙切齒。好在浏覽器之争以HTML、CSS, DOM、API和JavaScript的标準化而結束,進而開發者能集中精力開發高效的跨浏覽器JavaScript應用。确實,集中精力于把網站開發為應用催生了大量的想法、工具和從桌面應用到網站應用的技術。現如今,這些知識和工具的轉換再次發生,想法、工具和源于用戶端Web開發的技術逐漸滲入應用開發的其他領域。

對JavaScript基本原理和核心API的滲入了解能讓你成為更全能的開發者。通過使用浏覽器和Node.js(源自于浏覽器的環境),你能夠開發幾乎你能想到的任何類型的應用。

  • 桌面應用,通過使用如NW.js(http://nwjs.io/)或Electron (http://electron.atom.io/)的庫可以開發桌面應用。這些技術通常通過包裝浏覽器使我們能用标準的HTML、CSS和JavaScript(我們可以完全依賴我們的核心JavaScript和浏覽器知識來開發)以及一些額外的通路檔案系統的能力來建構桌面應用。進而能夠開發真正獨立于平台的桌面應用,它和我們在Windows、Mac和Linux上見到的應用看起來一樣。
  • 移動應用,使用類似Apache Cordova (https://cordova.apache.org/)的架構開發。與使用 Web 技術建構桌面應用一樣,該應用架構也包裝了浏覽器,不過其中還包含一些額外的針對特定平台的API,進而讓開發者能與移動平台互動。
  • 使用Node.js開發伺服器端應用和嵌入式應用,Node.js是源自于浏覽器的環境,使用了很多類似浏覽器的底層原理。例如,Node.js 能執行 JavaScript 代碼,并且也基于事件驅動。

Ann并不知道自己有多幸運(盡管Bob有個很棒的想法)。無論她是否需要建構一個标準的桌面應用還是移動應用、伺服器端應用或嵌入式應用都沒問題——所有這些應用都共享同樣的标準用戶端Web應用底層原理。

隻要了解了JavaScript工作的核心原理、了解了浏覽器提供的核心API(例如事件,同樣與Node.js提供的機制有很多共同點),她就能加速所有應用的開發。在這個過程中,你将變得更全能,知識和了解力也逐漸增長,進而能夠處理各種各樣的問題。你将能夠在雲上通過使用JavaScript API建構無需依賴伺服器的應用,例如使用類似AWS Lamda來部署、維護和控制你應用的雲元件。

  • 用戶端Web應用作為如今最流行的應用,其概念、工具和技術從僅開發用戶端Web應用已經深入到其他應用領域。了解用戶端Web應用的基礎能幫助你開發一系列不同領域的應用。
  • 為了提高開發技能,你需要深入了解JavaScript的核心機制和浏覽器所提供的架構。
  • 本書集中探讨了核心JavaScript的機制,例如函數、函數閉包和原型,還有一些新的JavaScript特性,例如生成器、promise、代理、映射、集合和子產品。
  • JavaScript可以在大量的環境中執行,但所有環境的開端是我們将集中探讨的浏覽器環境。
  • 除了JavaScript以外,我們還将探索浏覽器内部,例如DOM (網頁UI的一種結構化表示方式)和事件,這是因為用戶端Web應用是事件驅動的應用。

繼續閱讀