全棧必備 JavaScript基礎

編程語言 JavaScript 泛函編程 GitHub 海同職座標 2017-04-07

JavaScript 來了

1995年,誕生了JavaScript語言,那一年,我剛剛從大學畢業。在今年RedMonk 推出的2017 年第一季度編程語言排行榜中,JavaScript 排第一,Java 第二,Python 反超 PHP 排第三,PHP 第四,C# 和 C++ 並列第五。RedMonk 排名的主要依舊是各種編程語言在 Stack Overflow 和 GitHub 上的表現,比如編程語言在 Stack Overflow 上的討論數量,在 GitHub 上的代碼量等。儘管有一定的片面性,還是說明了JavaScript 應用的廣泛性。從全棧的角度看,Javascript 是必備的一種編程語言。

全棧必備 JavaScript基礎

ECMAScript 和 JavaScript 的關係

JavaScript 誕生於Netscape,但是在1996年,微軟發佈了與JavaScript 兼容的JScript,面對兼容和發展的需要,網景公司的先賢們努力加入了 ECMA International 標準化組織,致力於JavaScript 的標準化,命名為ECMAScript。後來,由於歷史的原因, JavaScript標準的開發主體變成了Mozila基金會。關於ECMAScript 的最新版本可以參閱 https://tc39.github.io/ecma262/。

簡單地,ECMAScript 是JavaScript語言的標準規範,就像C++的標準相對於C++語言那樣。

JavaScript 是怎樣的語言

在mozilla 開發者網站上是這樣描述JavaScript的:

JavaScript (JS) is a lightweight interpreted or JIT-compiled programming language with first-class functions.

意思是說JavaScript 是一個輕量級解釋或即時編譯的函數式語言,裡面有很多的概念,輕量、解釋、編譯、即時編譯、函數式。在老碼農看來,簡單起見,理解為擴展語言較為方便。

一般的編程語言都有著自己相對獨立的執行環境,但是JavaScript的執行環境依賴在宿主環境中,宿主環境尤其是客戶端的宿主環境提供了更多統一的環境變量,比如瀏覽器中的window,document等。實際上,JavaScript 和DOM 是可分的,對於不同的運行環境,有著不同的內置宿主對象。JavaScript作為擴展語言在內置的宿主環境中運行,全局對象在程序啟動前就已經存在了。

JavaScript的時空基礎

從空間觀的角度看,JavaScript包括數據結構,操作符,語句與表達式,函數;從時間的角度看,包括作用域,處理方式,模塊與庫。關於技術系統的時空觀,可以參見《面向全棧的技術管理》一文。

數據結構

JavaScript 中包含的六種基本類型:

  • Boolean

  • Null

  • Undefined

  • Number

  • String

  • Symbol (ECMAScript 6)

其它全是對象。值是有類型的,變量是沒有類型的,類型定義了值的行為特徵,變量在沒有持有值的時候是undefined。 JavaScript對值和引用的賦值/傳遞在語法上沒有區別,完全根據值的類型來判定。

對於對象的屬性和方法而言,全局變量和全局函數是全局對象的屬性,全局對象相當於宿主對象的根對象。需要注意是屬性的屬性中那些不可變對象的實現方式:

  1. 對象常量: 結合writable和configurable:false 可以創建一個真正的常量屬性

  2. 禁止擴張:Object.preventExtensions(..)來禁止一個對象添加新屬性並保留已有屬性

  3. 密封: 在 Object.seal(..) 後不能增,刪,改 該屬性

  4. 凍結: Object.freeze(..) 會禁止對於對象本身及任意直接屬性的修改

數據類型的判定可以通過 contructor,instanceof, isPrototypeOf等方法實現,對於鴨子類型的判定還可以使用 in 的相關操作。符號並非對象,而是一種簡單標量基本類型。

JavaScript 中的強制類型轉換總是返回基本類型值,將對象強制轉換為String 是通過ToPrimitive抽象操作完成的,而toJSON()是返回一個能夠被字符串化的安全的JSON值。

操作符

操作符是空間元素連接的紐帶之一,JavaScript操作符包括算術,連接,相等,比較,邏輯,位,類型判斷,條件,new,delete, void,",", ".", "[]"等。

在JavaScript中以操作符進行操作往往都附帶著類型轉換。

一元運算符+ 是顯式強制類型轉換,而~是先轉換為32位數字,然後按位反轉。|| 和&& 更應該算是選擇器運算符,其返回值不一定是布爾值,而是兩個操作數其中的一個值。一般先對第一個操作數進行toBoolean強制類型轉換,然後再執行條件判斷。例如:a||b 理解成a?a:b 更通俗。對&& 而言,如果第一個是真值,則把第二個作為返回值,a&&b 理解成a?b:a 。

== 和=== 都會對操作數進行類型檢查,並執行隱性類型轉換,需要注意的是:

  • 如果兩邊的值中有true或false,千萬不要使用==

  • 如果兩邊有[],””或者0,儘量不要使用==

這裡是Github上關於各種相等性的矩陣:

全棧必備 JavaScript基礎

語句與表達式

操作符與變量/常量等連接形成了語句和表達式,例如表達式a+1中的null 被強制轉換為0。 語句包括聲明與塊,控制語句有判斷,循環,break,continue,return,異常等。每個語句都有一個結果值,哪怕是undefined。

正則表達式是非常重要的一類表達式,主要使用RegExp類,執行方法test效率高,exec 會得到一個結果對象的數組。

逗號運算符可以把多個獨立的表達式串聯成一個語句,{ }在不同情況下的意思不盡相同,作為語句塊,{ ..} 和for/while循環以及if條件語句中代碼塊的作用基本相同。{a,b} 實際上是{a:a,b:b}的簡化版本。

try..catch..finally 中,如果finally中拋出異常,函數會在此處終止。需要注意的是,如果此前try中已經有return設置了返回值,則該值會被丟棄。finally中的return也會覆蓋try和catch中的return的返回值。

函數與作用域

函數就是具有運算邏輯的對象,匿名函數不利於調試,回調函數是一種控制反轉。所有的函數(對象)都具有名為prototype的屬性,prototype屬性引用的對象是prototype對象;所有的對象都含有一個隱式鏈接,用以指向在對象生成過程中所使用的構造函數的prototype對象。

匿名函數沒有name 標識符,具有如下缺陷:

  1. 代碼更難理解

  2. 調試棧更難追蹤

  3. 自我引用(遞歸,事件(解除)綁定,等)更難

如果function是聲明的第一個詞,那就是函數聲明,否則就是函數表達式。立即執行函數表達式形如:(function …)( )

時空密不可分,作用域是時空連接的紐帶之一。作用域包括全局,函數,塊級作用域。作用域是根據名稱查找變量的一套規則,遍歷嵌套作用域鏈的規則簡單:引擎從當前執行作用域逐級向上查找。閉包可以理解為具有狀態的函數。

函數作用域指屬於這個函數的全部變量都可以在整個函數的範圍內使用或複用。塊作用域形如 with, try/catch, ES6 引入了let,const等。

動態作用域並不關心函數和作用域是如何聲明以及在何處聲明的,只關心它們從何處調用的。詞法作用域是定義在詞法分析階段的作用域,詞法作用域查找會在第一個匹配的標識符時停止。作用域鏈是基於調用棧的,而不是代碼中的作用域嵌套。ReferenceError 是與作用域判別失敗相關,而TypeError則是作用域判別成功,但是對結果的操作非法或不合理。

this 提供了一種優雅方式來隱式“傳遞”一個對象引用。 this 即沒有指向函數的自身,也沒有指向函數的作用域,是在函數被調用時發生的綁定,它指向什麼完全取決於函數在哪裡被調用。如果分析this綁定的話,可以使用調試工具得到調用棧,然後找到棧中的第二個元素,就是真正的調用位置。

this 的綁定規則有:

  1. 默認綁定:獨立的函數調用,嚴格模式不能將全局對象用於默認綁定

  2. 隱式綁定:把函數調用中的this 綁定到函數引用中的上下文對象

  3. 顯式綁定:通過call()和apply()方法可以直接指定this的綁定對象。其中,硬綁定是一種顯式的強制綁定,ES5中提供了內置方法Function.prototype.bind, API中調用的上下文和bind的作用一樣。

  4. new 綁定,構造函數只是一些使用new操作符調用的函, 使用new 來調用函數的操作過程大致如下:

  • 創建一個全新的對象

  • 這個新對象會被執行[[Prototype]]鏈接

  • 這個新對象會綁定到函數調用的this

  • 如果函數沒有返回其他對象,那麼new表達式中的函數調用會自動返回這個新對象

如果同時存在多種綁定,那麼綁定的優先級大致如下:

  1. 由new調用綁定到新創建的對象

  2. 由call 或者apply(或bind)調用綁定到指定的對象

  3. 由上下文對象調用綁定到那個上下文對象

  4. 默認在在嚴格模式下綁定到undefined,否則綁定到全局對象

更安全地使用this 綁定的做法是傳入一個特殊的對象,把this 綁定到這個對象。需要注意的是,箭頭函數不使用this的4種規則,而是根據外層(函數或全局)作用域來決定this。

還要注意一點,eval 和 with 會導致作用域變化而引起性能下降,儘量不要使用。eval() 函數中的字符串是代碼,用來執行動態創建的代碼,嚴格模式有自己的作用域,還存在安全隱患;with 是重複引用一個對象中的多個屬性的快捷方式,通過將一個對象的引用當作作用域來處理,會改變作用域範圍。

處理和執行方式

JavaScript引擎本身沒有時間概念,只是一個按需執行任意代碼片段的環境,事件調度總是由包含它的宿主環境來執行。一旦有事件需要運行,事件循環隊列就會運行,直到隊列清空,用戶交互、IO和定時器等事件源會向事件隊列加入事件。

由於JavaScript的單線程特性,很多函數的代碼具有原子性。

回調函數封裝了程序的延續性,常見設計是分離回調(一個用於成功通知,一個用於出錯通知)。另一種回調模式是“error-first”,可能受到防禦式編程的影響,NodeJS API 採用了此類的風格,如果成功的話,這個參數就會被清空。需要注意的是,回調函數的嵌套往往稱為回調地獄。

Deferred是一種將異步處理串聯書寫並執行的機制,Deferred對象是一種具有unresolved,resolved,rejected 中某一種狀態的對象。Deferred內部機制是先註冊回調函數,Deferred對象狀態發生變化時執行該函數,是一種提高代碼可讀性的機制。

Deferred對象的狀態遷移只能發生一次,以then(),done(),fail(),always(),pipe()指定後續函數的方法,通過when()來並行處理,將Deferred 對象中的一部分方法刪除後得到是Promise對象,對狀態的管理由最初創建該Deferred對象的所有者來執行。

Promise 封裝了依賴於時間的狀態,從而使得本身與時間無關,Promise 可以按照可預測的方式進行,而不用關心時序或底層的結果。一旦Promise決議完成,就成為了不變值,可以安全地吧這個值傳遞給第三方,並確保不會改變。

Promise 是一種在異步任務中作為兩個或更多步驟的流程控制機制,時序上的this-then-that。 不僅表達了多步異步序列的流程控制,還是一個從一個步驟到下一個步驟傳遞消息的消息通道。事件監聽對象可以當成是對promise 的一種模擬,對控制反轉的恢復實現了更好的關注點分離。

判斷是否是Promise 值的示例代碼如下:

if(

生成器是一類特殊的函數,可以一次或多次啟動和停止,並不非的一定要完成,生成器把while true 帶回了Javascript的世界。其中,yield 委託的主要目的是代碼組織,以達到與普通函數調用的對稱。從生成器yield出一個Promise, 並且讓這個Promise 通過一個輔助函數恢復這個生成器,這是通過生成器管理異步的好方法之一。

需要注意的是,如果在Promise.all([..]) 中傳入空數組,會立即完成, 而Promise.race([..]) 則會掛住。 在各種Promise庫中,finally ( .. ) 還是會創建並返回一個新Promise的。

模塊與庫

模塊和庫是JavaScript 時空中的另一紐帶,提高了代碼的複用性和開發效率。

模塊充分利用了閉包的強大能力,從模塊中返回一個實際的對象並不是必須的,也可以直接返回一個內部函數,例如:jQauery 和 $標識符就是jQuery 模塊的公共API。

模塊有兩個必要條件:

  1. 必須有外部的封閉函數,該函數必須至少被調用一次

  2. 封閉函數必須返回至少一個內部函數,這樣內部函數才能在私有作用域中形成閉包,並且可以訪問或修改私有的狀態

import 可以將一個模塊的一個或多個API導入到當前作用域中,並分別綁定在一個變量上;module 則將整個模塊的API 導入並綁定到一個變量上, export 將當前模塊的一個標識符導出為公共API。

大多數模塊所依賴的加載器/管理器本質上是將這種模塊定義封裝進一個API。基於函數的模塊並不是一個能被靜態識別的模式(編譯器),API定義只有在運行時考慮進來。但是ES6 模塊的API 是靜態的,必須被定義在獨立的文件中。

JavaScript 中的庫浩如煙海,這裡僅對JQuery做簡要說明。JQuery壓縮後大約31k,輕巧靈活,通過鏈式語法實現邏輯功能,通過CSS3選擇器及自定義選擇器獲取元素,支持插件,可擴展性高。

JQuery中 的特色函數——$ ,可以抽取與選擇器匹配的元素,或者創建新的DOM元素,將已有的DOM元素轉換為jQuery對象,對DOM構造完成後的事件監聽器進行設定等等。JQuery 對DOM,樣式,AJAX 均可有效處理。

通過擴展JQuery.fn 就可以創建JQuery的插件,code.google.com/apis/libraries 給出了很多JQuery 的插件信息。

利用JavaScript 的時空觀,可以對這一語言有一些基本的梳理。就語言本身而言,關鍵字是不能迴避的,對JavaScript 關鍵字,在StackOverFlow中有人給出瞭如下詩一樣的總結:

Let this long package float,

客戶端應用

一門語言所被使用的廣泛程度取決於使用的場景,正如PHP被廣泛採用那樣,互聯網應用不僅是JavaScript 的家鄉,而且是它大展身手的最重要場所,沒有JavaScript 的Web應用幾乎絕跡了。

web應用中使用JavaScript有拖拽操作,異步讀取,鍵盤訪問 和動畫效果等基本功能。對於清晰地使用JavaScript實現Web應用而言,理解瀏覽器網頁處理過程是必要的。一般地,瀏覽器先分析HTML,然後構造DOM樹,再載入外部Javascript 文件以及CSS文件,接下來載入圖像文件等外部資源,最後在分析Javascript後開始執行至全部完成。

在HTML中加載JavaScript的方式有多種:

  • <script> 標籤,在body 結束標籤前寫

  • 讀取外部JavaScript 文件,讀取完就開始執行,瀏覽器可以緩存

  • onload 事件加載

  • DOMContentLoaded是在完成HTML解析後發生的事件,也可以用於加載JavaScript

  • 動態載入,這樣JS在載入時不會阻斷其他操作,如

    var script = document.createElement(‘script’);

    script.src = ‘my-javascript.js’;

    document.getElementsByTagName(‘head’)[0].appendChild(script)

window對象是JavaScript所能操作的最高層對象,其中的屬性包括navigator,location,history,screen,frames,document,parent,top,self 等。

DOM 是一種API,完成對HTML/XML 的樹形結構訪問,如標籤,元素,節點等。節點可以通過ID,標籤名,名稱和類名進行檢索,例如:

var element = document.getElementById(“abel”)

由於返回的是NodeList對象,性能較差,可以通過 var array = Array.prototye.slice.call(allelements)轉換為array 後處理。節點的訪問可以通過XPath 進行靈活的訪問,當然,Selector API 比XPath更簡單且同樣靈活,例如:

var a_label = document.querySelector(‘#abel’)

如果先修改DocumentFragment,再對實際的document對象操作,DOM 的操作性能會較高一些。

事件偵聽器的設定可以制定HTML元素的屬性,也可以指定DOM元素的屬性,還可以通過EventTarget.addEventListenser()進行指定。事件的處理包括捕獲,目標處理和事件冒泡三個階段,捕獲的過程是:

window -> document -> html -> body -> div -> button

然後處理器執行,冒泡向上傳播的過程是遍歷DOM樹,需要注意的是 focus 不會冒泡。

DOM2中的標準事件有HTMLEvent,MouseEvent,UIEvent和MutationEvent。DOM3 中的事件更多:UIEvent,FocusEvent,MouseEvent, WheelEvent, TextEvent,KeyboardEvent 和compositionEvent等,還可以通document.createEvent來自定義事件。

通過JavaScript 對CSS樣式變更的方法有通過className 屬性變更class名,通過classList屬性更改class名(其中classList 是H5對DOM TokenList接口的實現),還可以更改Style 屬性或者直接更改樣式表。通過JavaScript可以對屏幕位置(screenX,screenY),窗口位置(clientX,clientY),文檔座標(pageX,pageY,由瀏覽器自行實現的),特定元素內的相對位置(layerX,layerY 或offsetX offsetY)進行修改。通過JavaScript可以對錶單中的元素,控件和內容進行驗證,可用於驗證的事件有submit,focus,blur,change,keydown/up/press,input。使用表單而不產生頁面跳轉的方式可以是指向到一個 (0,0 )的空iframe。

對於動畫而言,css的動畫性能一般要更好一些。

AJAX 在Web應用中是不可或缺的,簡單地說,是一種不發生頁面跳轉就能異步載入內容並改寫頁面內容的技術,主要通過 XMLHttpRequest 對象的創建,實現通/異步通信,處理超時和響應。AJAX有著跨源限制,實現跨源通信的方式有:JSONP,iframe hack,window.postMessage() 以及 XMLHttpRequest Level 2。

HTML5+CSS3+JavaScript的綜合使用才可能成就一個Web應用。H5中的 History API 使用了window屬性的history對象監聽popstate事件,用於恢復頁面狀態的處理。ApplicationCache 在html標籤的manifest 屬性中指定了緩存清單文件的路徑,必須通過text/cache-manifest 這一MIME type 來發布緩存清單文件,注意清單中的CACHE,NETWORK,和FALLBACK 的區分。

通過navigator.onLine 可以獲知網絡狀態,還可以通過online/offline事件來偵聽連接狀態的切換時機。online/offline事件是document.body 觸發的,並傳給document對象和window對象。

<p> network is : <span id = “indicator”> (state unknown) </span> </p>

DataTransfer 是Drag Drop API 的核心,在所有拖拽事件的事件對象中,都有該屬性,主要是接收數據。拖拽文件從瀏覽器保存到桌面:event.dataTransfer.setData(‘DownloadURL’,’MIMETYPE: 文件url’)例如:

 <a href=“http://a.b.c/abel.pdf”

FileAPI 通過FileReader 讀取文件,也可以讀取dataURL,FileReaderSync 用於同步讀取文件內容,可以在Web Worker 中使用。

Web Storage 為所有源共享5M空間,localStorage 和sessionStorage 的區別在於數據的生命週期。cookie 最大4k,發請求時一起發送,保存會話等重要信息。indexedDB 可以歸為文檔型數據庫, 作為客戶端存儲又一選擇。

var indexdb = window.indexDB||window.webkitIndexedDB||window.mozIndexedDB;

Web worker 是H5 的新特性,是宿主環境(瀏覽器)的功能,JavaScript 本身是不支持多線程的。專用的worker 與創建它的程序之間是一對一的關係。

Web worker 能在另外的線程中創建新的Javascript 運行環境,使JavaScripts可以在後臺處理。主線程和工作線程分離,無法使用對方環境的變量。工作線程無法引用document對象,需要通過消息收發完成數據傳遞。 在主線程創建工作線程,大約向var worker = new Worker(‘work.js’)這樣 在主線程中停止worker的方式是worker.terminate(); worker 自身停止的方式是 self.close();worker 中 可以通個 importScripts 方法,在工作線程內讀取外部的文件。

瞭解了這些基礎方式和方法,僅僅是Web應用中JavaScript開發的第一步吧。

服務端應用

技術系統總是又著向超系統進化的趨勢,JavaScript 也不例外。

JavaScript 應用於服務端的開發源於2009年初出現的CommonJS,後來成為為了服務器端javaScript的規範。基於JavaScript沒有模塊系統、標準庫較少、缺乏包管理工具等現狀,CommonJS規範希望JavaScript可以在任何地方運行,以達到Java、C#、PHP這些後臺語言具備開發大型應用的能力。CommonJS是一種思想,它的終極目標是使應用程序開發者根據CommonJS API編寫的JavaScript應用可以在不同的JavaScript解析器和HOST環境上運行,例如編寫服務端應用,命令行工具,基於GUI的桌面應用和混合應用編程等,詳情參加 www.commonjs.org 。

NodeJS可以理解成CommonJS規範的一種實現,而且是部分實現。NodeJS以V8作為JavaScript的實現引擎,通用的異步處理事件循環,提供了一系列非阻塞函數庫來支持實踐循環特性。同時,NodeJS提供了高度優化的應用庫,來提高服務器效率,例如其http 模塊是為快速非阻塞式http服務而用C語言重寫的。另外,NodeJS還有shell的命令行工具,通過包系統實現擴展,擴展列表可以詳情參見: GitHub.com/node/wiki/modules。

JavaScript 中的主要實現引擎包括:IE採用的JScript,Firefox採用的SpiderMoneky,Chrome 採用的V8,Safari採用的webkit中的 javacriptcore燈。如果要對引擎有進一步的瞭解,可以研讀一下javascriptcore等相關的源代碼。

V8 是NodeJS 中的核心引擎,NodeJS的系統架構大致如下:

全棧必備 JavaScript基礎

與瀏覽器相對應,Node 中的全局變量可以通過 Object.keys(global); 獲得, 看一看NodeJS中的 “hello world” 程序:

var http = require('http');

幾行代碼就實現一個簡單web server, 使Pythoner 們聯想到了 Tornado, 它們都走在單線程異步IO的路上。

NodeJS 提供了對https 的支持,可以通過openssl 生成證書的方式大致是:

openssl req -new -x509 -keyout key.pen -out cert.perm

使用證書的示例如下:

var fs =require(‘fs’);

NodeJS支持socket 和文件處理,配合系統擴展可以使用各種模版語言。基於NodeJS的實際在業界非常廣泛,比如面向websocket的IM系統,各種web應用網站等等。

鑑於微服務架構的興起,也誕生了基於Node的微服務架構——Seneca,它使用完備的模式匹配接口來連接各個服務,從代碼中將數據傳輸抽象出來,使編寫具有高擴展性的軟件變得相當容易。Seneca 沒有使用依賴注入,但是在處理控制反轉上相當靈活,沒有關鍵字和強制的字段,只需一組鍵值對,用於模式匹配的引擎中。具體參考實現,可以參考《Node.js 微服務》一書。

基於JavaScript的全棧

如果在整個應用系統中主要使用JavaScript編程語言作為技術棧,那麼也可以成為基於JavaScript 的全棧,關於全棧的論述可以參加《全棧的技術棧設想》和《再談< 全棧架構師>》兩篇文字。例如MEAN架構,即MongoDB + Express + Angular + Node,MEAN 技術棧代表著一種完全現代的 Web 開發方法:一種語言運行在應用程序的所有層次上,從客戶端到服務器,再到持久層。藉助JavaScript的測試框架,比如MochaJS、JasmineJS 和 KarmaJS,可以為自己的 MEAN 應用程序編寫深入而又全面的測試套件,據說MEAN有取代LAMP/LNMP的的趨勢,但還需保持謹慎。

引擎的差異

正像Java 那樣,儘管又著虛擬機規範,但各個JVM的實現還是有著些許的不同,JavaScript 也是如此。JavaScript各引擎中同樣存在著少量的限制,例如:

  • 字符串常量中允許的最大字符數

  • 作為參數傳遞到函數中的數據大小(棧大小)

  • 函數聲明中的參數個數

  • 函數調用鏈的最大長度

  • 以阻塞方式在瀏覽器中運行的最大時間

  • 變量名的最大長度

儘管如此,JavaScript 在瀏覽器中的表現還是基本上可信的。

從軟件到硬件

實際上,JavaScript已經嵌入到了從機器人到各種家電等各種各樣的設備中。這裡隆重推薦我非常敬佩的好友——周愛民老師,他在Ruff(南潮信息科技)做的事情就是JavaScript 在物聯網上的進一步應用。

Ruff 是一個可以讓開發者實現敏捷開發智能硬件的系統平臺。它包含了Ruff SDK、Ruff OS,Rap Registry等。從技術上講,Ruff 是一個 JavaScript 運行時,專為硬件開發而設計。Ruff 對硬件進行了抽象,使用了基於事件驅動、異步 I/O 的模型,使硬件開發變得輕量而且高效。硬件抽象層,使得操作硬件猶如普通程序庫,降低了硬件領域進入門檻。

Ruff 為開發者提供了完善的開發服務。從項目生產、軟件包管理、應用管理、外設管理到固件管理等一系列現代軟件開發方式,PC 端完成開發,無需燒板子,提升開發者的開發效率。Ruff 還提供了完善的測試框架,支持 assert、test、mock 等模塊,在開發機上測試邏輯,硬件測試也能 TDD。

官網(ruff.io) 上給出的示例如下:

$.ready(function() {

打開電路板上的一個LED 燈,就是如此的簡單。目前,一個 Ruff 硬件同時只能運行一款 Ruff 應用,它將擁有自己獨立的進程,著可能也受到JavaScript自身的限制吧。

關注性能

性能是全棧關注的一個重要維度,那句“過早優化是萬惡之源”實際上是我們對高德納先生的斷章取義,原文是這樣的:

我們應該在例如97%的時間裡,忘掉小處的效率;

過早優化是萬惡之源。

但我們不應該錯過關鍵的3%中的機會。

實際上是非關鍵路徑上的優化是萬惡之源,問題在於如何確定我們的代碼是否在關鍵路徑上。不論節省的時間多麼少,花費在關鍵路徑上的性能優化都是值得的。

對於性能優化工具,用於JavaScript源代碼壓縮有 google Closure complier,packer,YUI compressor,JSmin等。頁面的性能優化工具有YSlow 和Page Speed等。實際上,任何有意義且可靠的性能測試都是基於統計學上的合理實踐。 就JavaScript 代碼本身的性能而言,benchmarkjs 是一個很好的工具,而jsperf.com 提供了對JavaScript 執行環境的性能測試。

總之,JavaScript 是一個具有強大生命力的語言,前端框架更是日新月異,從Angular,Vue,到React, 乃至React Native,給人以目不暇接的感覺,但是,老碼農覺得基礎認識還是非常必要的,勿在浮沙築高塔。

參考閱讀

https://developer.mozilla.org/en-US/docs/Web/JavaScript

https://tc39.github.io/ecma262/#sec-global-object

From:互聯網

學習IT編程技術,就到職座標,如果你喜歡我們的文章,可以點擊右上角關注我們。想看到更多IT界的資訊,關注職座標公眾號,每天為你奉上最新行業動態及技術乾貨。

公眾號:Zhizuobiao_Online(職座標在線)

相關推薦

推薦中...