偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

全棧必備JavaScript基礎(chǔ)

開(kāi)發(fā) 開(kāi)發(fā)工具
JavaScript 是一個(gè)具有強(qiáng)大生命力的語(yǔ)言,前端框架更是日新月異,從Angular,Vue,到React, 乃至React Native,給人以目不暇接的感覺(jué),但是,老碼農(nóng)覺(jué)得基礎(chǔ)認(rèn)識(shí)還是非常必要的,勿在浮沙筑高塔。

[[187649]]

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

 

ECMAScript 和 JavaScript 的關(guān)系

JavaScript 誕生于Netscape,但是在1996年,微軟發(fā)布了與JavaScript 兼容的JScript,面對(duì)兼容和發(fā)展的需要,網(wǎng)景公司的先賢們努力加入了 ECMA International 標(biāo)準(zhǔn)化組織,致力于JavaScript 的標(biāo)準(zhǔn)化,命名為ECMAScript。后來(lái),由于歷史的原因, JavaScript標(biāo)準(zhǔn)的開(kāi)發(fā)主體變成了Mozila基金會(huì)。

簡(jiǎn)單地,ECMAScript 是JavaScript語(yǔ)言的標(biāo)準(zhǔn)規(guī)范,就像C++的標(biāo)準(zhǔn)相對(duì)于C++語(yǔ)言那樣。

JavaScript 是怎樣的語(yǔ)言

在mozilla 開(kāi)發(fā)者網(wǎng)站上是這樣描述JavaScript的:

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

意思是說(shuō)JavaScript 是一個(gè)輕量級(jí)解釋或即時(shí)編譯的函數(shù)式語(yǔ)言,里面有很多的概念,輕量、解釋、編譯、即時(shí)編譯、函數(shù)式。在老碼農(nóng)看來(lái),簡(jiǎn)單起見(jiàn),理解為擴(kuò)展語(yǔ)言較為方便。

一般的編程語(yǔ)言都有著自己相對(duì)獨(dú)立的執(zhí)行環(huán)境,但是JavaScript的執(zhí)行環(huán)境依賴在宿主環(huán)境中,宿主環(huán)境尤其是客戶端的宿主環(huán)境提供了更多統(tǒng)一的環(huán)境變量,比如瀏覽器中的window,document等。實(shí)際上,JavaScript 和DOM 是可分的,對(duì)于不同的運(yùn)行環(huán)境,有著不同的內(nèi)置宿主對(duì)象。JavaScript作為擴(kuò)展語(yǔ)言在內(nèi)置的宿主環(huán)境中運(yùn)行,全局對(duì)象在程序啟動(dòng)前就已經(jīng)存在了。

JavaScript的時(shí)空基礎(chǔ)

從空間觀的角度看,JavaScript包括數(shù)據(jù)結(jié)構(gòu),操作符,語(yǔ)句與表達(dá)式,函數(shù);從時(shí)間的角度看,包括作用域,處理方式,模塊與庫(kù)。

數(shù)據(jù)結(jié)構(gòu)

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

  • Boolean
  • Null
  • Undefined
  • Number
  • String
  • Symbol (ECMAScript 6)

其它全是對(duì)象。值是有類型的,變量是沒(méi)有類型的,類型定義了值的行為特征,變量在沒(méi)有持有值的時(shí)候是undefined。 JavaScript對(duì)值和引用的賦值/傳遞在語(yǔ)法上沒(méi)有區(qū)別,完全根據(jù)值的類型來(lái)判定。

對(duì)于對(duì)象的屬性和方法而言,全局變量和全局函數(shù)是全局對(duì)象的屬性,全局對(duì)象相當(dāng)于宿主對(duì)象的根對(duì)象。需要注意是屬性的屬性中那些不可變對(duì)象的實(shí)現(xiàn)方式:

  1. 對(duì)象常量: 結(jié)合writable和configurable:false 可以創(chuàng)建一個(gè)真正的常量屬性
  2. 禁止擴(kuò)張:Object.preventExtensions(..)來(lái)禁止一個(gè)對(duì)象添加新屬性并保留已有屬性
  3. 密封: 在 Object.seal(..) 后不能增,刪,改 該屬性
  4. 凍結(jié): Object.freeze(..) 會(huì)禁止對(duì)于對(duì)象本身及任意直接屬性的修改

數(shù)據(jù)類型的判定可以通過(guò) contructor,instanceof, isPrototypeOf等方法實(shí)現(xiàn),對(duì)于鴨子類型的判定還可以使用 in 的相關(guān)操作。符號(hào)并非對(duì)象,而是一種簡(jiǎn)單標(biāo)量基本類型。

JavaScript 中的強(qiáng)制類型轉(zhuǎn)換總是返回基本類型值,將對(duì)象強(qiáng)制轉(zhuǎn)換為String 是通過(guò)ToPrimitive抽象操作完成的,而toJSON()是返回一個(gè)能夠被字符串化的安全的JSON值。

操作符

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

在JavaScript中以操作符進(jìn)行操作往往都附帶著類型轉(zhuǎn)換。

一元運(yùn)算符+ 是顯式強(qiáng)制類型轉(zhuǎn)換,而~是先轉(zhuǎn)換為32位數(shù)字,然后按位反轉(zhuǎn)。|| 和&& 更應(yīng)該算是選擇器運(yùn)算符,其返回值不一定是布爾值,而是兩個(gè)操作數(shù)其中的一個(gè)值。一般先對(duì)第一個(gè)操作數(shù)進(jìn)行toBoolean強(qiáng)制類型轉(zhuǎn)換,然后再執(zhí)行條件判斷。例如:a||b 理解成a?a:b 更通俗。對(duì)&& 而言,如果第一個(gè)是真值,則把第二個(gè)作為返回值,a&&b 理解成a?b:a 。

== 和=== 都會(huì)對(duì)操作數(shù)進(jìn)行類型檢查,并執(zhí)行隱性類型轉(zhuǎn)換,需要注意的是:

  • 如果兩邊的值中有true或false,千萬(wàn)不要使用==
  • 如果兩邊有[],””或者0,盡量不要使用==

這里是Github上關(guān)于各種相等性的矩陣:

 

語(yǔ)句與表達(dá)式

操作符與變量/常量等連接形成了語(yǔ)句和表達(dá)式,例如表達(dá)式a+1中的null 被強(qiáng)制轉(zhuǎn)換為0。 語(yǔ)句包括聲明與塊,控制語(yǔ)句有判斷,循環(huán),break,continue,return,異常等。每個(gè)語(yǔ)句都有一個(gè)結(jié)果值,哪怕是undefined。

正則表達(dá)式是非常重要的一類表達(dá)式,主要使用RegExp類,執(zhí)行方法test效率高,exec 會(huì)得到一個(gè)結(jié)果對(duì)象的數(shù)組。

逗號(hào)運(yùn)算符可以把多個(gè)獨(dú)立的表達(dá)式串聯(lián)成一個(gè)語(yǔ)句,{ }在不同情況下的意思不盡相同,作為語(yǔ)句塊,{ ..} 和for/while循環(huán)以及if條件語(yǔ)句中代碼塊的作用基本相同。{a,b} 實(shí)際上是{a:a,b:b}的簡(jiǎn)化版本。

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

函數(shù)與作用域

函數(shù)就是具有運(yùn)算邏輯的對(duì)象,匿名函數(shù)不利于調(diào)試,回調(diào)函數(shù)是一種控制反轉(zhuǎn)。所有的函數(shù)(對(duì)象)都具有名為prototype的屬性,prototype屬性引用的對(duì)象是prototype對(duì)象;所有的對(duì)象都含有一個(gè)隱式鏈接,用以指向在對(duì)象生成過(guò)程中所使用的構(gòu)造函數(shù)的prototype對(duì)象。

匿名函數(shù)沒(méi)有name 標(biāo)識(shí)符,具有如下缺陷:

  1. 代碼更難理解
  2. 調(diào)試棧更難追蹤
  3. 自我引用(遞歸,事件(解除)綁定,等)更難

如果function是聲明的第一個(gè)詞,那就是函數(shù)聲明,否則就是函數(shù)表達(dá)式。立即執(zhí)行函數(shù)表達(dá)式形如:(function …)( )

時(shí)空密不可分,作用域是時(shí)空連接的紐帶之一。作用域包括全局,函數(shù),塊級(jí)作用域。作用域是根據(jù)名稱查找變量的一套規(guī)則,遍歷嵌套作用域鏈的規(guī)則簡(jiǎn)單:引擎從當(dāng)前執(zhí)行作用域逐級(jí)向上查找。閉包可以理解為具有狀態(tài)的函數(shù)。

函數(shù)作用域指屬于這個(gè)函數(shù)的全部變量都可以在整個(gè)函數(shù)的范圍內(nèi)使用或復(fù)用。塊作用域形如 with, try/catch, ES6 引入了let,const等。

動(dòng)態(tài)作用域并不關(guān)心函數(shù)和作用域是如何聲明以及在何處聲明的,只關(guān)心它們從何處調(diào)用的。詞法作用域是定義在詞法分析階段的作用域,詞法作用域查找會(huì)在第一個(gè)匹配的標(biāo)識(shí)符時(shí)停止。作用域鏈?zhǔn)腔谡{(diào)用棧的,而不是代碼中的作用域嵌套。ReferenceError 是與作用域判別失敗相關(guān),而TypeError則是作用域判別成功,但是對(duì)結(jié)果的操作非法或不合理。

this 提供了一種優(yōu)雅方式來(lái)隱式“傳遞”一個(gè)對(duì)象引用。 this 即沒(méi)有指向函數(shù)的自身,也沒(méi)有指向函數(shù)的作用域,是在函數(shù)被調(diào)用時(shí)發(fā)生的綁定,它指向什么完全取決于函數(shù)在哪里被調(diào)用。如果分析this綁定的話,可以使用調(diào)試工具得到調(diào)用棧,然后找到棧中的第二個(gè)元素,就是真正的調(diào)用位置。

this 的綁定規(guī)則有:

  1. 默認(rèn)綁定:獨(dú)立的函數(shù)調(diào)用,嚴(yán)格模式不能將全局對(duì)象用于默認(rèn)綁定
  2. 隱式綁定:把函數(shù)調(diào)用中的this 綁定到函數(shù)引用中的上下文對(duì)象
  3. 顯式綁定:通過(guò)call()和apply()方法可以直接指定this的綁定對(duì)象。其中,硬綁定是一種顯式的強(qiáng)制綁定,ES5中提供了內(nèi)置方法Function.prototype.bind, API中調(diào)用的上下文和bind的作用一樣。
  4. new 綁定,構(gòu)造函數(shù)只是一些使用new操作符調(diào)用的函, 使用new 來(lái)調(diào)用函數(shù)的操作過(guò)程大致如下:
  • 創(chuàng)建一個(gè)全新的對(duì)象
  • 這個(gè)新對(duì)象會(huì)被執(zhí)行[[Prototype]]鏈接
  • 這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的this
  • 如果函數(shù)沒(méi)有返回其他對(duì)象,那么new表達(dá)式中的函數(shù)調(diào)用會(huì)自動(dòng)返回這個(gè)新對(duì)象

如果同時(shí)存在多種綁定,那么綁定的優(yōu)先級(jí)大致如下:

  1. 由new調(diào)用綁定到新創(chuàng)建的對(duì)象
  2. 由call 或者apply(或bind)調(diào)用綁定到指定的對(duì)象
  3. 由上下文對(duì)象調(diào)用綁定到那個(gè)上下文對(duì)象
  4. 默認(rèn)在在嚴(yán)格模式下綁定到undefined,否則綁定到全局對(duì)象

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

還要注意一點(diǎn),eval 和 with 會(huì)導(dǎo)致作用域變化而引起性能下降,盡量不要使用。eval() 函數(shù)中的字符串是代碼,用來(lái)執(zhí)行動(dòng)態(tài)創(chuàng)建的代碼,嚴(yán)格模式有自己的作用域,還存在安全隱患;with 是重復(fù)引用一個(gè)對(duì)象中的多個(gè)屬性的快捷方式,通過(guò)將一個(gè)對(duì)象的引用當(dāng)作作用域來(lái)處理,會(huì)改變作用域范圍。

處理和執(zhí)行方式

JavaScript引擎本身沒(méi)有時(shí)間概念,只是一個(gè)按需執(zhí)行任意代碼片段的環(huán)境,事件調(diào)度總是由包含它的宿主環(huán)境來(lái)執(zhí)行。一旦有事件需要運(yùn)行,事件循環(huán)隊(duì)列就會(huì)運(yùn)行,直到隊(duì)列清空,用戶交互、IO和定時(shí)器等事件源會(huì)向事件隊(duì)列加入事件。

由于JavaScript的單線程特性,很多函數(shù)的代碼具有原子性。

回調(diào)函數(shù)封裝了程序的延續(xù)性,常見(jiàn)設(shè)計(jì)是分離回調(diào)(一個(gè)用于成功通知,一個(gè)用于出錯(cuò)通知)。另一種回調(diào)模式是“error-first”,可能受到防御式編程的影響,NodeJS API 采用了此類的風(fēng)格,如果成功的話,這個(gè)參數(shù)就會(huì)被清空。需要注意的是,回調(diào)函數(shù)的嵌套往往稱為回調(diào)地獄。

Deferred是一種將異步處理串聯(lián)書(shū)寫(xiě)并執(zhí)行的機(jī)制,Deferred對(duì)象是一種具有unresolved,resolved,rejected 中某一種狀態(tài)的對(duì)象。Deferred內(nèi)部機(jī)制是先注冊(cè)回調(diào)函數(shù),Deferred對(duì)象狀態(tài)發(fā)生變化時(shí)執(zhí)行該函數(shù),是一種提高代碼可讀性的機(jī)制。

Deferred對(duì)象的狀態(tài)遷移只能發(fā)生一次,以then(),done(),fail(),always(),pipe()指定后續(xù)函數(shù)的方法,通過(guò)when()來(lái)并行處理,將Deferred 對(duì)象中的一部分方法刪除后得到是Promise對(duì)象,對(duì)狀態(tài)的管理由最初創(chuàng)建該Deferred對(duì)象的所有者來(lái)執(zhí)行。

Promise 封裝了依賴于時(shí)間的狀態(tài),從而使得本身與時(shí)間無(wú)關(guān),Promise 可以按照可預(yù)測(cè)的方式進(jìn)行,而不用關(guān)心時(shí)序或底層的結(jié)果。一旦Promise決議完成,就成為了不變值,可以安全地吧這個(gè)值傳遞給第三方,并確保不會(huì)改變。

Promise 是一種在異步任務(wù)中作為兩個(gè)或更多步驟的流程控制機(jī)制,時(shí)序上的this-then-that。 不僅表達(dá)了多步異步序列的流程控制,還是一個(gè)從一個(gè)步驟到下一個(gè)步驟傳遞消息的消息通道。事件監(jiān)聽(tīng)對(duì)象可以當(dāng)成是對(duì)promise 的一種模擬,對(duì)控制反轉(zhuǎn)的恢復(fù)實(shí)現(xiàn)了更好的關(guān)注點(diǎn)分離。

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

  1. if( 
  2.     p !==null && 
  3.     ( typeof p ===“object” || typeof p ===“function”) && typeof p.then===“function”) 
  4.     { 
  5.         console.log(“thenable”); 
  6.     } 
  7. else
  8.     console.log(“not thenable”); 

生成器是一類特殊的函數(shù),可以一次或多次啟動(dòng)和停止,并不非的一定要完成,生成器把while true 帶回了Javascript的世界。其中,yield 委托的主要目的是代碼組織,以達(dá)到與普通函數(shù)調(diào)用的對(duì)稱。從生成器yield出一個(gè)Promise, 并且讓這個(gè)Promise 通過(guò)一個(gè)輔助函數(shù)恢復(fù)這個(gè)生成器,這是通過(guò)生成器管理異步的好方法之一。

需要注意的是,如果在Promise.all([..]) 中傳入空數(shù)組,會(huì)立即完成, 而Promise.race([..]) 則會(huì)掛住。 在各種Promise庫(kù)中,finally ( .. ) 還是會(huì)創(chuàng)建并返回一個(gè)新Promise的。

模塊與庫(kù)

模塊和庫(kù)是JavaScript 時(shí)空中的另一紐帶,提高了代碼的復(fù)用性和開(kāi)發(fā)效率。

模塊充分利用了閉包的強(qiáng)大能力,從模塊中返回一個(gè)實(shí)際的對(duì)象并不是必須的,也可以直接返回一個(gè)內(nèi)部函數(shù),例如:jQauery 和 $標(biāo)識(shí)符就是jQuery 模塊的公共API。

模塊有兩個(gè)必要條件:

  1. 必須有外部的封閉函數(shù),該函數(shù)必須至少被調(diào)用一次
  2. 封閉函數(shù)必須返回至少一個(gè)內(nèi)部函數(shù),這樣內(nèi)部函數(shù)才能在私有作用域中形成閉包,并且可以訪問(wèn)或修改私有的狀態(tài)

import 可以將一個(gè)模塊的一個(gè)或多個(gè)API導(dǎo)入到當(dāng)前作用域中,并分別綁定在一個(gè)變量上;module 則將整個(gè)模塊的API 導(dǎo)入并綁定到一個(gè)變量上, export 將當(dāng)前模塊的一個(gè)標(biāo)識(shí)符導(dǎo)出為公共API。

大多數(shù)模塊所依賴的加載器/管理器本質(zhì)上是將這種模塊定義封裝進(jìn)一個(gè)API?;诤瘮?shù)的模塊并不是一個(gè)能被靜態(tài)識(shí)別的模式(編譯器),API定義只有在運(yùn)行時(shí)考慮進(jìn)來(lái)。但是ES6 模塊的API 是靜態(tài)的,必須被定義在獨(dú)立的文件中。

JavaScript 中的庫(kù)浩如煙海,這里僅對(duì)JQuery做簡(jiǎn)要說(shuō)明。JQuery壓縮后大約31k,輕巧靈活,通過(guò)鏈?zhǔn)秸Z(yǔ)法實(shí)現(xiàn)邏輯功能,通過(guò)CSS3選擇器及自定義選擇器獲取元素,支持插件,可擴(kuò)展性高。

JQuery中 的特色函數(shù)——$ ,可以抽取與選擇器匹配的元素,或者創(chuàng)建新的DOM元素,將已有的DOM元素轉(zhuǎn)換為jQuery對(duì)象,對(duì)DOM構(gòu)造完成后的事件監(jiān)聽(tīng)器進(jìn)行設(shè)定等等。JQuery 對(duì)DOM,樣式,AJAX 均可有效處理。

通過(guò)擴(kuò)展JQuery.fn 就可以創(chuàng)建JQuery的插件,code.google.com/apis/libraries 給出了很多JQuery 的插件信息。

利用JavaScript 的時(shí)空觀,可以對(duì)這一語(yǔ)言有一些基本的梳理。就語(yǔ)言本身而言,關(guān)鍵字是不能回避的,對(duì)JavaScript 關(guān)鍵字,在StackOverFlow中有人給出了如下詩(shī)一樣的總結(jié):

  1. Let this long package float, 
  2. Goto private class if short。 
  3. While protected with debug case, 
  4. Continue volatile interface。 
  5. Instanceof super synchronized throw, 
  6. Extends final export throws. 
  7.  
  8. Try import double enum? 
  9. -False, boolean, abstract function
  10. Implements typeof transient break! 
  11. Void static,default do, 
  12. Switch int native new, 
  13. elsedelete null public var, 
  14. In return for const, truechar
  15. …… finally catch byte. 

客戶端應(yīng)用

一門(mén)語(yǔ)言所被使用的廣泛程度取決于使用的場(chǎng)景,正如PHP被廣泛采用那樣,互聯(lián)網(wǎng)應(yīng)用不僅是JavaScript 的家鄉(xiāng),而且是它大展身手的最重要場(chǎng)所,沒(méi)有JavaScript 的Web應(yīng)用幾乎絕跡了。

web應(yīng)用中使用JavaScript有拖拽操作,異步讀取,鍵盤(pán)訪問(wèn) 和動(dòng)畫(huà)效果等基本功能。對(duì)于清晰地使用JavaScript實(shí)現(xiàn)Web應(yīng)用而言,理解瀏覽器網(wǎng)頁(yè)處理過(guò)程是必要的。一般地,瀏覽器先分析HTML,然后構(gòu)造DOM樹(shù),再載入外部Javascript 文件以及CSS文件,接下來(lái)載入圖像文件等外部資源,最后在分析Javascript后開(kāi)始執(zhí)行至全部完成。

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

  • <script> 標(biāo)簽,在body 結(jié)束標(biāo)簽前寫(xiě)
  • 讀取外部JavaScript 文件,讀取完就開(kāi)始執(zhí)行,瀏覽器可以緩存
  • onload 事件加載
  • DOMContentLoaded是在完成HTML解析后發(fā)生的事件,也可以用于加載JavaScript
  • 動(dòng)態(tài)載入,這樣JS在載入時(shí)不會(huì)阻斷其他操作,如
  1. var script = document.createElement(‘script’); 
  2. script.src = ‘my-javascript.js’; 
  3. document.getElementsByTagName(‘head’)[0].appendChild(script) 

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

DOM 是一種API,完成對(duì)HTML/XML 的樹(shù)形結(jié)構(gòu)訪問(wèn),如標(biāo)簽,元素,節(jié)點(diǎn)等。節(jié)點(diǎn)可以通過(guò)ID,標(biāo)簽名,名稱和類名進(jìn)行檢索,例如:

  1. var element = document.getElementById(“abel”)  
  2. var allelements = document.getElementByTagName(‘*’) 

由于返回的是NodeList對(duì)象,性能較差,可以通過(guò) var array = Array.prototye.slice.call(allelements)轉(zhuǎn)換為array 后處理。節(jié)點(diǎn)的訪問(wèn)可以通過(guò)XPath 進(jìn)行靈活的訪問(wèn),當(dāng)然,Selector API 比XPath更簡(jiǎn)單且同樣靈活,例如:

  1. var a_label = document.querySelector(‘#abel’)  
  2. var b_all = document.querySelectorAll(‘div’) 

如果先修改DocumentFragment,再對(duì)實(shí)際的document對(duì)象操作,DOM 的操作性能會(huì)較高一些。

事件偵聽(tīng)器的設(shè)定可以制定HTML元素的屬性,也可以指定DOM元素的屬性,還可以通過(guò)EventTarget.addEventListenser()進(jìn)行指定。事件的處理包括捕獲,目標(biāo)處理和事件冒泡三個(gè)階段,捕獲的過(guò)程是:

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

然后處理器執(zhí)行,冒泡向上傳播的過(guò)程是遍歷DOM樹(shù),需要注意的是 focus 不會(huì)冒泡。

DOM2中的標(biāo)準(zhǔn)事件有HTMLEvent,MouseEvent,UIEvent和MutationEvent。DOM3 中的事件更多:UIEvent,F(xiàn)ocusEvent,MouseEvent, WheelEvent, TextEvent,KeyboardEvent 和compositionEvent等,還可以通document.createEvent來(lái)自定義事件。

通過(guò)JavaScript 對(duì)CSS樣式變更的方法有通過(guò)className 屬性變更c(diǎn)lass名,通過(guò)classList屬性更改class名(其中classList 是H5對(duì)DOM TokenList接口的實(shí)現(xiàn)),還可以更改Style 屬性或者直接更改樣式表。通過(guò)JavaScript可以對(duì)屏幕位置(screenX,screenY),窗口位置(clientX,clientY),文檔坐標(biāo)(pageX,pageY,由瀏覽器自行實(shí)現(xiàn)的),特定元素內(nèi)的相對(duì)位置(layerX,layerY 或offsetX offsetY)進(jìn)行修改。通過(guò)JavaScript可以對(duì)表單中的元素,控件和內(nèi)容進(jìn)行驗(yàn)證,可用于驗(yàn)證的事件有submit,focus,blur,change,keydown/up/press,input。使用表單而不產(chǎn)生頁(yè)面跳轉(zhuǎn)的方式可以是指向到一個(gè) (0,0 )的空iframe。

對(duì)于動(dòng)畫(huà)而言,css的動(dòng)畫(huà)性能一般要更好一些。

AJAX 在Web應(yīng)用中是不可或缺的,簡(jiǎn)單地說(shuō),是一種不發(fā)生頁(yè)面跳轉(zhuǎn)就能異步載入內(nèi)容并改寫(xiě)頁(yè)面內(nèi)容的技術(shù),主要通過(guò) XMLHttpRequest 對(duì)象的創(chuàng)建,實(shí)現(xiàn)通/異步通信,處理超時(shí)和響應(yīng)。AJAX有著跨源限制,實(shí)現(xiàn)跨源通信的方式有:JSONP,iframe hack,window.postMessage() 以及 XMLHttpRequest Level 2。

HTML5+CSS3+JavaScript的綜合使用才可能成就一個(gè)Web應(yīng)用。H5中的 History API 使用了window屬性的history對(duì)象監(jiān)聽(tīng)popstate事件,用于恢復(fù)頁(yè)面狀態(tài)的處理。ApplicationCache 在html標(biāo)簽的manifest 屬性中指定了緩存清單文件的路徑,必須通過(guò)text/cache-manifest 這一MIME type 來(lái)發(fā)布緩存清單文件,注意清單中的CACHE,NETWORK,和FALLBACK 的區(qū)分。

通過(guò)navigator.onLine 可以獲知網(wǎng)絡(luò)狀態(tài),還可以通過(guò)online/offline事件來(lái)偵聽(tīng)連接狀態(tài)的切換時(shí)機(jī)。online/offline事件是document.body 觸發(fā)的,并傳給document對(duì)象和window對(duì)象。

  1. <p> network is : <span id = “indicator”> (state unknown) </span> </p> 
  2. <script> 
  3.     function updateIndicator = document.getElementById(‘indicator’); 
  4.     indicator.textContext = navigator.online?’online’:’offline’; 
  5. document.body.onload = updateIndicator; 
  6. document.body.ononline= updateIndicator; 
  7. document.body.onoffline = updateIndicator; 
  8. </script> 

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

  1. <a href=“http://a.b.c/abel.pdf”  
  2.    data-downloadurl = “application/pdf:abel.pdf:http://a.b.c/abel.pdf” 
  3.    class=“dragout” draggable = “true”>download </a> 
  4.    <script> 
  5.    var files = document.querySelectorAll(‘.dragout’); 
  6.    for (var i = 0,file; file =files[i];i++) { 
  7.        file.addEventListener(‘dragstart’,function(event){ 
  8.    event.dataTransfer.setData(“DownloadURL”,this.dataset.downloadurl); 
  9.    },false); 
  10.    } 
  11.    </script> 

FileAPI 通過(guò)FileReader 讀取文件,也可以讀取dataURL,F(xiàn)ileReaderSync 用于同步讀取文件內(nèi)容,可以在Web Worker 中使用。

Web Storage 為所有源共享5M空間,localStorage 和sessionStorage 的區(qū)別在于數(shù)據(jù)的生命周期。cookie 最大4k,發(fā)請(qǐng)求時(shí)一起發(fā)送,保存會(huì)話等重要信息。indexedDB 可以歸為文檔型數(shù)據(jù)庫(kù), 作為客戶端存儲(chǔ)又一選擇。

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

Web worker 是H5 的新特性,是宿主環(huán)境(瀏覽器)的功能,JavaScript 本身是不支持多線程的。專用的worker 與創(chuàng)建它的程序之間是一對(duì)一的關(guān)系。

Web worker 能在另外的線程中創(chuàng)建新的Javascript 運(yùn)行環(huán)境,使JavaScripts可以在后臺(tái)處理。主線程和工作線程分離,無(wú)法使用對(duì)方環(huán)境的變量。工作線程無(wú)法引用document對(duì)象,需要通過(guò)消息收發(fā)完成數(shù)據(jù)傳遞。 在主線程創(chuàng)建工作線程,大約向var worker = new Worker(‘work.js’)這樣 在主線程中停止worker的方式是worker.terminate(); worker 自身停止的方式是 self.close();worker 中 可以通個(gè) importScripts 方法,在工作線程內(nèi)讀取外部的文件。

了解了這些基礎(chǔ)方式和方法,僅僅是Web應(yīng)用中JavaScript開(kāi)發(fā)的第一步吧。

服務(wù)端應(yīng)用

技術(shù)系統(tǒng)總是又著向超系統(tǒng)進(jìn)化的趨勢(shì),JavaScript 也不例外。

JavaScript 應(yīng)用于服務(wù)端的開(kāi)發(fā)源于2009年初出現(xiàn)的CommonJS,后來(lái)成為為了服務(wù)器端javaScript的規(guī)范?;贘avaScript沒(méi)有模塊系統(tǒng)、標(biāo)準(zhǔn)庫(kù)較少、缺乏包管理工具等現(xiàn)狀,CommonJS規(guī)范希望JavaScript可以在任何地方運(yùn)行,以達(dá)到Java、C#、PHP這些后臺(tái)語(yǔ)言具備開(kāi)發(fā)大型應(yīng)用的能力。CommonJS是一種思想,它的終極目標(biāo)是使應(yīng)用程序開(kāi)發(fā)者根據(jù)CommonJS API編寫(xiě)的JavaScript應(yīng)用可以在不同的JavaScript解析器和HOST環(huán)境上運(yùn)行,例如編寫(xiě)服務(wù)端應(yīng)用,命令行工具,基于GUI的桌面應(yīng)用和混合應(yīng)用編程等,詳情參加 www.commonjs.org 。

[[187650]]

NodeJS可以理解成CommonJS規(guī)范的一種實(shí)現(xiàn),而且是部分實(shí)現(xiàn)。NodeJS以V8作為JavaScript的實(shí)現(xiàn)引擎,通用的異步處理事件循環(huán),提供了一系列非阻塞函數(shù)庫(kù)來(lái)支持實(shí)踐循環(huán)特性。同時(shí),NodeJS提供了高度優(yōu)化的應(yīng)用庫(kù),來(lái)提高服務(wù)器效率,例如其http 模塊是為快速非阻塞式http服務(wù)而用C語(yǔ)言重寫(xiě)的。另外,NodeJS還有shell的命令行工具,通過(guò)包系統(tǒng)實(shí)現(xiàn)擴(kuò)展,擴(kuò)展列表可以詳情參見(jiàn): GitHub.com/node/wiki/modules。

JavaScript 中的主要實(shí)現(xiàn)引擎包括:IE采用的JScript,F(xiàn)irefox采用的SpiderMoneky,Chrome 采用的V8,Safari采用的webkit中的 javacriptcore燈。如果要對(duì)引擎有進(jìn)一步的了解,可以研讀一下javascriptcore等相關(guān)的源代碼。

V8 是NodeJS 中的核心引擎,NodeJS的系統(tǒng)架構(gòu)大致如下:

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

  1. var http = require('http'); 
  2. http.createServer(function (req,res){ 
  3.     res.writeHead(200,{'Content-type':'text/plain'}); 
  4.     res.end('Hello Node.js \n'); 
  5. }).listen(1234,"127.0.0.1"); 
  6. console.log('Server running on http://127.0.0.1:1234/'); 

幾行代碼就實(shí)現(xiàn)一個(gè)簡(jiǎn)單web server, 使Pythoner 們聯(lián)想到了 Tornado, 它們都走在單線程異步IO的路上。

NodeJS 提供了對(duì)https 的支持,可以通過(guò)openssl 生成證書(shū)的方式大致是:

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

使用證書(shū)的示例如下:

  1. var fs  =require(‘fs’); 
  2. var options = { 
  3.     key: fs.readFileSync(‘key.perm’); 
  4.     cert:fs.readFileSync(‘cert.perm’); 

NodeJS支持socket 和文件處理,配合系統(tǒng)擴(kuò)展可以使用各種模版語(yǔ)言。基于NodeJS的實(shí)際在業(yè)界非常廣泛,比如面向websocket的IM系統(tǒng),各種web應(yīng)用網(wǎng)站等等。

鑒于微服務(wù)架構(gòu)的興起,也誕生了基于Node的微服務(wù)架構(gòu)——Seneca,它使用完備的模式匹配接口來(lái)連接各個(gè)服務(wù),從代碼中將數(shù)據(jù)傳輸抽象出來(lái),使編寫(xiě)具有高擴(kuò)展性的軟件變得相當(dāng)容易。Seneca 沒(méi)有使用依賴注入,但是在處理控制反轉(zhuǎn)上相當(dāng)靈活,沒(méi)有關(guān)鍵字和強(qiáng)制的字段,只需一組鍵值對(duì),用于模式匹配的引擎中。具體參考實(shí)現(xiàn),可以參考《node.js 微服務(wù)》一書(shū)。

基于JavaScript的全棧

如果在整個(gè)應(yīng)用系統(tǒng)中主要使用JavaScript編程語(yǔ)言作為技術(shù)棧,那么也可以成為基于JavaScript 的全棧,關(guān)于全棧的論述可以參加《全棧的技術(shù)棧設(shè)想》和《再談< 全棧架構(gòu)師>》兩篇文字。例如MEAN架構(gòu),即MongoDB + Express + Angular + Node,MEAN 技術(shù)棧代表著一種完全現(xiàn)代的 Web 開(kāi)發(fā)方法:一種語(yǔ)言運(yùn)行在應(yīng)用程序的所有層次上,從客戶端到服務(wù)器,再到持久層。借助JavaScript的測(cè)試框架,比如MochaJS、JasmineJS 和 KarmaJS,可以為自己的 MEAN 應(yīng)用程序編寫(xiě)深入而又全面的測(cè)試套件,據(jù)說(shuō)MEAN有取代LAMP/LNMP的的趨勢(shì),但還需保持謹(jǐn)慎。

引擎的差異

正像Java 那樣,盡管又著虛擬機(jī)規(guī)范,但各個(gè)JVM的實(shí)現(xiàn)還是有著些許的不同,JavaScript 也是如此。JavaScript各引擎中同樣存在著少量的限制,例如:

  • 字符串常量中允許的最大字符數(shù)
  • 作為參數(shù)傳遞到函數(shù)中的數(shù)據(jù)大小(棧大小)
  • 函數(shù)聲明中的參數(shù)個(gè)數(shù)
  • 函數(shù)調(diào)用鏈的最大長(zhǎng)度
  • 以阻塞方式在瀏覽器中運(yùn)行的最大時(shí)間
  • 變量名的最大長(zhǎng)度
  • 盡管如此,JavaScript 在瀏覽器中的表現(xiàn)還是基本上可信的。

從軟件到硬件

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

Ruff 是一個(gè)可以讓開(kāi)發(fā)者實(shí)現(xiàn)敏捷開(kāi)發(fā)智能硬件的系統(tǒng)平臺(tái)。它包含了Ruff SDK、Ruff OS,Rap Registry等。從技術(shù)上講,Ruff 是一個(gè) JavaScript 運(yùn)行時(shí),專為硬件開(kāi)發(fā)而設(shè)計(jì)。Ruff 對(duì)硬件進(jìn)行了抽象,使用了基于事件驅(qū)動(dòng)、異步 I/O 的模型,使硬件開(kāi)發(fā)變得輕量而且高效。硬件抽象層,使得操作硬件猶如普通程序庫(kù),降低了硬件領(lǐng)域進(jìn)入門(mén)檻。

Ruff 為開(kāi)發(fā)者提供了完善的開(kāi)發(fā)服務(wù)。從項(xiàng)目生產(chǎn)、軟件包管理、應(yīng)用管理、外設(shè)管理到固件管理等一系列現(xiàn)代軟件開(kāi)發(fā)方式,PC 端完成開(kāi)發(fā),無(wú)需燒板子,提升開(kāi)發(fā)者的開(kāi)發(fā)效率。Ruff 還提供了完善的測(cè)試框架,支持 assert、test、mock 等模塊,在開(kāi)發(fā)機(jī)上測(cè)試邏輯,硬件測(cè)試也能 TDD。

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

  1. $.ready(function() { 
  2.    $('#led-0').turnOn(); 
  3. }); 

打開(kāi)電路板上的一個(gè)LED 燈,就是如此的簡(jiǎn)單。目前,一個(gè) Ruff 硬件同時(shí)只能運(yùn)行一款 Ruff 應(yīng)用,它將擁有自己獨(dú)立的進(jìn)程,著可能也受到JavaScript自身的限制吧。

關(guān)注性能

性能是全棧關(guān)注的一個(gè)重要維度,那句“過(guò)早優(yōu)化是萬(wàn)惡之源”實(shí)際上是我們對(duì)高德納先生的斷章取義,原文是這樣的:

我們應(yīng)該在例如97%的時(shí)間里,忘掉小處的效率;過(guò)早優(yōu)化是萬(wàn)惡之源。但我們不應(yīng)該錯(cuò)過(guò)關(guān)鍵的3%中的機(jī)會(huì)。

實(shí)際上是非關(guān)鍵路徑上的優(yōu)化是萬(wàn)惡之源,問(wèn)題在于如何確定我們的代碼是否在關(guān)鍵路徑上。不論節(jié)省的時(shí)間多么少,花費(fèi)在關(guān)鍵路徑上的性能優(yōu)化都是值得的。

對(duì)于性能優(yōu)化工具,用于JavaScript源代碼壓縮有 google Closure complier,packer,YUI compressor,JSmin等。頁(yè)面的性能優(yōu)化工具有YSlow 和Page Speed等。實(shí)際上,任何有意義且可靠的性能測(cè)試都是基于統(tǒng)計(jì)學(xué)上的合理實(shí)踐。 就JavaScript 代碼本身的性能而言,benchmarkjs 是一個(gè)很好的工具,而jsperf.com 提供了對(duì)JavaScript 執(zhí)行環(huán)境的性能測(cè)試。

總之,JavaScript 是一個(gè)具有強(qiáng)大生命力的語(yǔ)言,前端框架更是日新月異,從Angular,Vue,到React, 乃至React Native,給人以目不暇接的感覺(jué),但是,老碼農(nóng)覺(jué)得基礎(chǔ)認(rèn)識(shí)還是非常必要的,勿在浮沙筑高塔。

【本文來(lái)自51CTO專欄作者“老曹”的原創(chuàng)文章,作者微信公眾號(hào):喔家ArchiSelf,id:wrieless-com】

戳這里,看該作者更多好文

責(zé)任編輯:武曉燕 來(lái)源: 51CTO專欄
相關(guān)推薦

2020-07-20 08:23:04

Redis分布式系統(tǒng)

2021-06-01 07:16:21

C語(yǔ)言基礎(chǔ)代碼

2017-06-13 15:10:02

大數(shù)據(jù)Log日志

2017-06-13 08:55:29

Log日志MySQL

2013-12-09 09:42:50

JavaScript全棧式

2017-10-12 14:24:24

2017-12-18 15:33:56

Java基礎(chǔ)編程

2017-04-12 14:45:20

數(shù)據(jù)架構(gòu)數(shù)據(jù)源

2017-08-07 13:02:32

全棧必備貝葉斯

2023-12-10 20:30:51

SQL工具數(shù)據(jù)

2018-01-09 15:35:54

Python編程基礎(chǔ)

2022-07-06 11:21:11

JHipsterJavaJavaScript

2015-08-17 09:27:51

全棧工程師Devops工具周期表

2018-10-15 10:22:51

2019-06-05 13:30:24

ReactJavaScript開(kāi)發(fā)

2023-08-21 09:51:57

全棧軟件開(kāi)發(fā)

2015-05-04 09:23:38

JavaScript全棧開(kāi)發(fā)員云計(jì)算

2023-07-03 00:47:23

2017-11-10 19:00:37

華為

2017-07-05 11:09:35

華為開(kāi)發(fā)云
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)