整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          JavaScript 的 .reduce() 函數(shù)的完整指南(帶有真實(shí)示例)

          本指南中,我們將介紹:

          .reduce() 函數(shù)是什么?

          創(chuàng)建我們的 .reduce() 函數(shù)版本

          計(jì)算電子商務(wù)購(gòu)物車(chē)的商品總數(shù)和價(jià)格

          為餐廳菜單創(chuàng)建一組獨(dú)特的類(lèi)別

          從數(shù)組中刪除重復(fù)的對(duì)象

          用 .reduce() 替換 .filter().map()

          按鍵分組對(duì)象(類(lèi)似于 SQL GROUP BY 或 C# 的 .GroupBy())

          乍一看似乎很混亂

          如果您曾經(jīng)為理解 .reduce() 函數(shù)而苦苦掙扎,那么您并不孤單。 要真正了解它的工作原理并自信地使用它,需要多花幾次功夫。

          大多數(shù)例子都使用一個(gè)簡(jiǎn)單的數(shù)字或字符串?dāng)?shù)組,但現(xiàn)實(shí)是我們通常使用很少涉及的復(fù)雜對(duì)象。

          但在我們跳進(jìn)去之前。

          以下是如何從這些內(nèi)容中獲得更多信息。

          打開(kāi)您的代碼編輯器并親自嘗試示例

          修改它(更改值,向數(shù)組添加或從數(shù)組中刪除元素等)

          如果您發(fā)現(xiàn)自己迷失在其中一個(gè)示例中,請(qǐng)使用筆和紙或在您的代碼編輯器上追蹤變量的值。

          讓我們開(kāi)始吧!

          .reduce() 函數(shù)是什么?

          它是一種對(duì)數(shù)組的每個(gè)元素執(zhí)行回調(diào)函數(shù)的方法。

          計(jì)算的返回值傳遞給下一個(gè)元素。

          在第一次迭代中,沒(méi)有“上一次計(jì)算的返回值”,如果傳入,可以用一個(gè)初始值代替。

          否則,數(shù)組的第一個(gè)元素被用作初始值,迭代從下一個(gè)元素開(kāi)始。

          簡(jiǎn)單的說(shuō),就是一個(gè)變量和一個(gè)循環(huán)。

          變量保存新值

          循環(huán)遍歷數(shù)組,因此我們可以從每個(gè)元素中獲取我們想要的內(nèi)容

          這個(gè):

          實(shí)現(xiàn)與此相同:

          幾乎每次需要使用變量和循環(huán)時(shí),都可以用 reduce 函數(shù)替換它。

          由于沒(méi)有比實(shí)際嘗試更好的學(xué)習(xí)方法,讓我們構(gòu)建我們的 .reduce() 方法版本,以便我們真正理解它。

          構(gòu)建我們自己的 .reduce()

          讓我們通過(guò)解決一個(gè)簡(jiǎn)單的問(wèn)題來(lái)做到這一點(diǎn):

          我們有一個(gè)數(shù)字?jǐn)?shù)組,我們想要所有數(shù)字的總和。

          就像上面的變量和循環(huán)的例子一樣。

          我們需要三樣?xùn)|西:

          數(shù)組

          保存總值 total 的變量(通常稱為累加器)

          遍歷數(shù)組的循環(huán)

          假設(shè)你想把它變成一個(gè)函數(shù),這樣你就可以很容易地使用它,你會(huì)怎么做?

          也許沿著這些路線:

          我們將數(shù)組作為參數(shù)傳遞給我們的函數(shù)

          我們最后返回總數(shù)。

          這看起來(lái)不錯(cuò),但是如果我們想要設(shè)置變量總計(jì)初始值的選項(xiàng)怎么辦?

          我們可以將選項(xiàng)添加為另一個(gè)參數(shù)并將總計(jì)設(shè)置為它的值。

          像這樣:

          但是這個(gè)函數(shù)還有2個(gè)問(wèn)題。

          我們無(wú)法在循環(huán)內(nèi)添加要執(zhí)行的不同邏輯(它只會(huì)將當(dāng)前元素添加到 sum 變量)

          它僅適用于簡(jiǎn)單數(shù)組(其中每個(gè)項(xiàng)目都是值類(lèi)型,而不是對(duì)象)

          我會(huì)告訴你我的意思。

          這次讓我們創(chuàng)建一個(gè)對(duì)象數(shù)組

          讓我們調(diào)用傳入對(duì)象數(shù)組的 myReducer 函數(shù)

          它不起作用,因?yàn)槲覀円砑拥闹翟趯?duì)象內(nèi)部而不是對(duì)象本身。

          我們必須以 total += arr[i].number 的形式訪問(wèn)它

          但是這個(gè)函數(shù)沒(méi)有考慮到這一點(diǎn)。

          但是,如果我們添加一個(gè)回調(diào)函數(shù)作為第二個(gè)參數(shù),我們可以:

          對(duì)數(shù)組的每個(gè)元素執(zhí)行回調(diào)函數(shù)

          創(chuàng)建我們需要的任何自定義邏輯

          讓我們修改我們的 myReducer 函數(shù)。

          讓我們用對(duì)象數(shù)組再次測(cè)試它。

          首先,聲明回調(diào)函數(shù)并調(diào)用傳入它的 myReduce。

          請(qǐng)注意,我們根據(jù) total 的值添加了 if 和 else 條件,這是我們的 initialValue 選項(xiàng)。

          如果未給出初始值

          它不會(huì)在第一次迭代時(shí)執(zhí)行回調(diào)

          沒(méi)有什么要補(bǔ)充的,initialValue 是未定義的。

          只需將 total 設(shè)置為當(dāng)前元素的值

          如果給出初始值

          它在所有迭代中執(zhí)行回調(diào)

          這幾乎就是原始 Array.prototype.reduce() 所做的。

          主要區(qū)別在于不需要將數(shù)組作為參數(shù)傳遞,因?yàn)樵?.reduce() 綁定到 Array.prototype,因此數(shù)組始終是調(diào)用 .reduce() 的數(shù)組。

          計(jì)算電子商務(wù)購(gòu)物車(chē)的總項(xiàng)目數(shù)和價(jià)格

          假設(shè)你有一個(gè)像這樣的數(shù)組:

          您需要將此數(shù)組縮減為這樣的對(duì)象 { totalItems: 0, totalPrice: 0 } 以便我們可以在結(jié)帳頁(yè)面上顯示正確的信息。

          這是我們可以做到的:

          為餐廳菜單創(chuàng)建一組獨(dú)特的類(lèi)別

          給定這個(gè)數(shù)組:

          我們需要將其縮減為一系列獨(dú)特的類(lèi)別,例如 ['Appetizer','Entree','Main']

          這是我們可以做到的:

          從數(shù)組中刪除重復(fù)的對(duì)象

          與上面的示例類(lèi)似,但這次我們需要返回僅使用唯一對(duì)象過(guò)濾的相同對(duì)象數(shù)組。

          這是具有重復(fù)對(duì)象的數(shù)組:

          注意:你必須有一個(gè)類(lèi)似于 id 的屬性,它對(duì)每個(gè)對(duì)象都是唯一的

          這就是我們?nèi)绾蝿?chuàng)建另一個(gè)僅包含唯一元素的數(shù)組:

          將 .filter().map() 替換為 .reduce()

          過(guò)濾數(shù)組然后修改過(guò)濾后數(shù)組的元素是很常見(jiàn)的。

          我們將使用上面菜單類(lèi)別的相同數(shù)組

          但是這次我們想得到一個(gè)數(shù)組,其中只有類(lèi)別為“Entree”的項(xiàng)目的 itemName

          我們可以使用 .filter() 數(shù)組,然后使用 .map() 來(lái)完成它

          或者我們可以用 .reduce() 來(lái)做

          使用 .reduce() 的優(yōu)點(diǎn)是您只迭代數(shù)組一次。

          按鍵分組對(duì)象(類(lèi)似于 SQL GROUP BY 或 C# 的 .GroupBy())

          這是我最喜歡的。 這是一個(gè)非常方便的函數(shù),可能會(huì)在下一次更新時(shí)包含在 JavaScript 的數(shù)組方法中(目前處于第 3 階段以供批準(zhǔn))

          這個(gè) groupBy 函數(shù)也可以用作解決更復(fù)雜問(wèn)題的中間步驟。

          我們將再次使用菜單類(lèi)別數(shù)組:

          這是我們的 groupBy 函數(shù):

          如果我們添加將密鑰作為函數(shù)傳遞的選項(xiàng),它會(huì)變得更加方便。

          只需替換這一行:

          有了這個(gè):

          這樣我們就可以調(diào)用它并傳遞一個(gè)返回鍵的函數(shù),而不是自己編寫(xiě)字符串,避免拼寫(xiě)錯(cuò)誤。

          結(jié)論

          在這篇文章中,我們了解到:

          什么是 .reduce() 函數(shù)

          如何創(chuàng)建我們的 .reduce() 函數(shù)版本

          計(jì)算電子商務(wù)購(gòu)物車(chē)的總項(xiàng)目數(shù)和價(jià)格

          為餐廳菜單創(chuàng)建一組獨(dú)特的類(lèi)別

          從數(shù)組中刪除重復(fù)的對(duì)象

          將 .filter().map() 替換為 .reduce()

          如何按鍵對(duì)對(duì)象進(jìn)行分組(類(lèi)似于 SQL GROUP BY 或 C# 的 .GroupBy())

          謝謝閱讀!


          /下栽のke:quangneng.com/321/

          JavaScript高級(jí)玩法的詳細(xì)介紹

          JavaScript是一種非常靈活且強(qiáng)大的腳本語(yǔ)言,廣泛應(yīng)用于網(wǎng)頁(yè)開(kāi)發(fā)、移動(dòng)端開(kāi)發(fā)、后端開(kāi)發(fā)等多個(gè)領(lǐng)域。對(duì)于想要提升JavaScript編程能力的開(kāi)發(fā)者來(lái)說(shuō),掌握一些高級(jí)玩法是非常必要的。以下是一些JavaScript的高級(jí)玩法:

          1. 函數(shù)的高級(jí)特性

          JavaScript中的函數(shù)不僅能夠執(zhí)行特定任務(wù),還具有許多高級(jí)特性。例如,函數(shù)可以接受參數(shù),也可以返回值;函數(shù)可以嵌套在其他函數(shù)中,形成高階函數(shù);函數(shù)還可以作為一等公民存在,可以被賦值給變量,也可以作為函數(shù)的參數(shù)傳遞。

          2. 原型鏈和繼承

          JavaScript中的所有對(duì)象都有一個(gè)內(nèi)部屬性[[Prototype]],這個(gè)屬性指向它的原型對(duì)象。通過(guò)__proto__屬性或者Object.getPrototypeOf()方法,可以訪問(wèn)一個(gè)對(duì)象的原型。JavaScript中的繼承是通過(guò)原型鏈實(shí)現(xiàn)的,子類(lèi)的原型可以通過(guò)__proto__屬性或者constructor.prototype屬性指向父類(lèi)的實(shí)例。

          3. 異步編程

          JavaScript中的異步編程非常復(fù)雜,但非常重要。常見(jiàn)的異步編程方式有回調(diào)函數(shù)、Promise、async/await等。掌握這些異步編程方式,可以幫助開(kāi)發(fā)者更好地處理復(fù)雜的異步邏輯。

          4. 設(shè)計(jì)模式

          設(shè)計(jì)模式是一套被廣泛接受的面向?qū)ο蟮脑O(shè)計(jì)原則,用于解決特定問(wèn)題的最佳實(shí)踐。在JavaScript中,常用的設(shè)計(jì)模式有單例模式、工廠模式、觀察者模式、裝飾器模式等。掌握這些設(shè)計(jì)模式,可以幫助開(kāi)發(fā)者寫(xiě)出更加優(yōu)雅、高效的代碼。

          5. 性能優(yōu)化

          JavaScript程序的性能優(yōu)化是一項(xiàng)非常重要的任務(wù)。通過(guò)合理的算法設(shè)計(jì)、代碼組織、資源管理等方式,可以顯著提高JavaScript程序的運(yùn)行效率。

          JavaScript的函數(shù)有哪些高級(jí)特性

          JavaScript的函數(shù)具有以下一些高級(jí)特性:

          箭頭函數(shù):箭頭函數(shù)是ES6引入的一種新的函數(shù)語(yǔ)法。它們更簡(jiǎn)潔,并且在處理多個(gè)返回值時(shí)更方便。箭頭函數(shù)的語(yǔ)法如下:

          (parameters) => { // code to be executed}

          高階函數(shù):高階函數(shù)是接受一個(gè)或多個(gè)函數(shù)作為參數(shù),并返回一個(gè)新的函數(shù)的函數(shù)。它們?cè)诮M合和抽象中非常有用。例如,map()、filter() 和 reduce() 等函數(shù)都是高階函數(shù)的例子。

          閉包:閉包是一種特殊的函數(shù)結(jié)構(gòu),它允許一個(gè)函數(shù)在其定義范圍之外訪問(wèn)其父作用域的變量和函數(shù)。例如,你可以創(chuàng)建一個(gè)函數(shù),該函數(shù)在其定義范圍內(nèi)定義一個(gè)局部變量,然后返回一個(gè)內(nèi)部函數(shù),該內(nèi)部函數(shù)可以訪問(wèn)并修改這個(gè)局部變量。

          函數(shù)表達(dá)式:除了函數(shù)聲明外,JavaScript還支持函數(shù)表達(dá)式。函數(shù)表達(dá)式可以將函數(shù)賦值給變量,從而提供更大的靈活性。

          函數(shù)柯里化:函數(shù)柯里化是一種特殊的技術(shù),它將函數(shù)轉(zhuǎn)化為一系列嵌套函數(shù)的形式。每個(gè)嵌套函數(shù)都只接受部分參數(shù),并返回一個(gè)新的函數(shù),等待接收剩余的參數(shù)。

          函數(shù)的遞歸調(diào)用:函數(shù)可以調(diào)用自身,這種技術(shù)稱為函數(shù)的遞歸調(diào)用。函數(shù)的遞歸調(diào)用在很多情況下都非常有用,例如計(jì)算斐波那契數(shù)列、遍歷樹(shù)形結(jié)構(gòu)的數(shù)據(jù)等。

          以上就是JavaScript的一些高級(jí)玩法,希望對(duì)你有所幫助。如果你想深入了解這些話題,可以閱讀一些相關(guān)的書(shū)籍和教程,如《JavaScript高級(jí)教程》、《JavaScript權(quán)威指南》等。同時(shí),多做一些實(shí)踐項(xiàng)目,也是提升JavaScript編程能力的好方法。

          習(xí)目標(biāo):了解JavaScript是如何與HTML結(jié)合來(lái)創(chuàng)建動(dòng)態(tài)網(wǎng)頁(yè),網(wǎng)頁(yè)中嵌入JavaScript的不同方式,JavaScript的內(nèi)容類(lèi)型及其與<script>的關(guān)系

          <script>元素

          <script>是由Netscape創(chuàng)造出來(lái),后來(lái)加到HTML規(guī)范中的。

          <script>有8個(gè)屬性:

          1、async:表示立即開(kāi)始下載腳本,但不能阻止其他頁(yè)面動(dòng)作,比如下載資源或者等待其他腳本加載。只對(duì)外部腳本文件有效。

          2、charset:使用src屬性指定代碼字符集。這個(gè)屬性很少用,因?yàn)榇蠖鄶?shù)瀏覽器不在乎它的值。

          3、crossorigin;配置資源請(qǐng)求的CORS(跨源資源共享)設(shè)置。默認(rèn)情況下不使用CORS。crossorigin = “anonymous”配置文件請(qǐng)求不用設(shè)置憑據(jù)標(biāo)志。crossorigin = ”use-credentials“設(shè)置憑據(jù)標(biāo)志,意味著出站請(qǐng)求會(huì)包含憑據(jù)。

          4、defer:表示腳本可以延遲到文檔全部解析和顯示后再執(zhí)行。新版本中只能用于外部腳本。

          5、integrity:允許比對(duì)接收到的資源和指定的加密簽名以驗(yàn)證子資源完整性(SRI,Subresource integrity),如果驗(yàn)證簽名不匹配則腳本不會(huì)執(zhí)行。這個(gè)屬性可以用于確保內(nèi)容分發(fā)網(wǎng)絡(luò)(CDN,Content Delivery Network)不會(huì)提供惡意內(nèi)容。

          6、language:此屬性已被廢止。

          7、src:表示包含外部要執(zhí)行的代碼的外部文件。

          8、type:代替language,表示代碼塊中腳本語(yǔ)言的內(nèi)容類(lèi)型(也稱為MIME類(lèi)型),按照慣例這個(gè)值始終都是”text/JavaScript“,盡管”text/JavaScript“和”text/ecmascript“都已經(jīng)廢棄。JavaScript文件的MIME類(lèi)型通常是”application/x-javascript“,不過(guò)給type屬性這個(gè)值的話可能會(huì)導(dǎo)致腳本被忽略。在非IE的瀏覽器中有效的值還有”application/JavaScript“和”application/ecmascript"。如果這個(gè)值是module,則代碼會(huì)被當(dāng)成是ES6模塊,而且只有這時(shí)候代碼中才能出現(xiàn)import和export關(guān)鍵字。

          使用<script>的方式有內(nèi)聯(lián)和外嵌兩種,只要把code寫(xiě)入<script>code</script>中就好,code中要是包含字符串“<script>”,只要加上轉(zhuǎn)義字符“\”即可。

          如果要外嵌JavaScript代碼只要使用src屬性來(lái)鏈接外部文件即可如:

          <script src=“example.js”></script>

          XHTML 文檔中,可以忽略結(jié)束標(biāo)簽寫(xiě)成<script src=“example.js”/>即可,但是這在HTML中不能使用。

          標(biāo)簽位置

          過(guò)去把JavaScript和CSS一起寫(xiě)在head中,但是這意味著必須下載所有code并解析和解釋完成后才開(kāi)始渲染頁(yè)面,對(duì)于JavaScript很多的頁(yè)面會(huì)導(dǎo)致頁(yè)面渲染速度過(guò)慢,為解決這個(gè)問(wèn)題,JavaScript一般寫(xiě)在body元素的頁(yè)面內(nèi)容的最后邊,如下

          <html>

          <head></head>

          <body>

          message

          <script>code<\script>

          <\body>

          </html>

          推遲使用腳本

          在外聯(lián)JavaScript時(shí)可以使用defer屬性來(lái)推遲腳本的運(yùn)行。可以寫(xiě)成:

          <html>

          <head>

          <script defer src = "example.js">code<\script>

          </head>

          <body>

          message

          <\body>

          </html>

          異步執(zhí)行腳本

          async屬性從腳本處理方式上與defer類(lèi)似,但是不同的是標(biāo)記async的腳本并不能保證腳本按照他們的出現(xiàn)順序執(zhí)行,比如:

          <html>

          <head>

          <script sync src = "example1.js">code<\script>

          <script sync src = "example2.js">code<\script>

          </head>

          <body>

          message

          <\body>

          </html>

          不能保證example1比example2先執(zhí)行。

          動(dòng)態(tài)加載腳本

          除了<script>以外還可以用其他方式加載腳本。因?yàn)镴avaScript可以使用DOM API,所以通過(guò)向DOM中動(dòng)態(tài)地加入script元素同樣可以加載指定腳本。只要?jiǎng)?chuàng)建一個(gè)script元素并將其添加到DOM即可。

          let script = document.createElement('script');

          script.src = 'gibberish.js';

          document.head.appendChild(script);

          當(dāng)然,在把 HTMLElement 元素添加到 DOM 且執(zhí)行到這段代碼之前不會(huì)發(fā)送請(qǐng)求。默認(rèn)情況下,以這種方式創(chuàng)建的<script>元素是以異步方式加載的,相當(dāng)于添加了 async 屬性。不過(guò)這樣做可能會(huì)有問(wèn)題,因?yàn)樗袨g覽器都支持 createElement()方法,但不是所有瀏覽器都支持 async 屬性。因此,如果要統(tǒng)一動(dòng)態(tài)腳本的加載行為,可以明確將其設(shè)置為同步加載:

          let script = document.createElement('script');

          script.src = 'gibberish.js';

          script.async = false;

          document.head.appendChild(script);

          以這種方式獲取的資源對(duì)瀏覽器預(yù)加載器是不可見(jiàn)的。這會(huì)嚴(yán)重影響它們?cè)谫Y源獲取隊(duì)列中的優(yōu)先級(jí)。根據(jù)應(yīng)用程序的工作方式以及怎么使用,這種方式可能會(huì)嚴(yán)重影響性能。要想讓預(yù)加載器知道這些動(dòng)態(tài)請(qǐng)求文件的存在,可以在文檔頭部顯式聲明它們:

          <link rel="preload" href="gibberish.js">

          XHTML中的變化

          可擴(kuò)展超文本標(biāo)記語(yǔ)言(XHTML,Extensible HyperText Markup Language)是將 HTML 作為 XML的應(yīng)用重新包裝的結(jié)果。與 HTML 不同,在 XHTML 中使用 JavaScript 必須指定 type 屬性且值為text/javascript,HTML 中則可以沒(méi)有這個(gè)屬性。XHTML 雖然已經(jīng)退出歷史舞臺(tái),但實(shí)踐中偶爾可能也會(huì)遇到遺留代碼,為此本節(jié)稍作介紹。在 XHTML 中編寫(xiě)代碼的規(guī)則比 HTML 中嚴(yán)格,這會(huì)影響使用<script>元素嵌入 JavaScript 代碼。下面的代碼塊雖然在 HTML 中有效,但在 XHML 中是無(wú)效的。

          <script type="text/javascript">

          function compare(a, b) {

          if (a < b) {

          console.log("A is less than B");

          } else if (a > b) {

          console.log("A is greater than B");

          } else {

          console.log("A is equal to B");

          }

          }

          </script>

          在 HTML 中,解析<script>元素會(huì)應(yīng)用特殊規(guī)則。XHTML 中則沒(méi)有這些規(guī)則。這意味著 a < b語(yǔ)句中的小于號(hào)(<)會(huì)被解釋成一個(gè)標(biāo)簽的開(kāi)始,并且由于作為標(biāo)簽開(kāi)始的小于號(hào)后面不能有空格,這會(huì)導(dǎo)致語(yǔ)法錯(cuò)誤。避免 XHTML 中這種語(yǔ)法錯(cuò)誤的方法有兩種。第一種是把所有小于號(hào)(<)都替換成對(duì)應(yīng)的 HTML實(shí)體形式(<)。結(jié)果代碼就是這樣的:

          <script type="text/javascript">

          function compare(a, b) {

          if (a < b) {

          console.log("A is less than B");

          } else if (a > b) {

          console.log("A is greater than B");

          } else {

          console.log("A is equal to B");

          }

          }

          </script>

          這樣代碼就可以在 XHTML 頁(yè)面中運(yùn)行了。不過(guò),缺點(diǎn)是會(huì)影響閱讀。好在還有另一種方法。第二種方法是把所有代碼都包含到一個(gè) CDATA 塊中。在 XHTML(及 XML)中,CDATA 塊表示文檔中可以包含任意文本的區(qū)塊,其內(nèi)容不作為標(biāo)簽來(lái)解析,因此可以在其中包含任意字符,包括小于號(hào),并且不會(huì)引發(fā)語(yǔ)法錯(cuò)誤。使用 CDATA 的格式如下:

          <script type="text/javascript"><![CDATA[

          function compare(a, b) {

          if (a < b) {

          console.log("A is less than B");

          } else if (a > b) {

          console.log("A is greater than B");

          } else {

          console.log("A is equal to B");

          }

          }

          ]]></script>

          在兼容 XHTML 的瀏覽器中,這樣能解決問(wèn)題。但在不支持 CDATA 塊的非 XHTML 兼容瀏覽器中則不行。為此,CDATA 標(biāo)記必須使用 JavaScript 注釋來(lái)抵消:

          <script type="text/javascript">

          //<![CDATA[

          function compare(a, b) {

          if (a < b) {

          console.log("A is less than B");

          } else if (a > b) {

          console.log("A is greater than B");

          } else {

          console.log("A is equal to B");

          }

          }

          //]]>

          </script>

          這種格式適用于所有現(xiàn)代瀏覽器。雖然有點(diǎn)黑科技的味道,但它可以通過(guò) XHTML 驗(yàn)證,而且對(duì)XHTML 之前的瀏覽器也能優(yōu)雅地降級(jí)。

          廢棄的語(yǔ)法

          自 1995 年 Netscape 2 發(fā)布以來(lái),所有瀏覽器都將 JavaScript 作為默認(rèn)的編程語(yǔ)言。type 屬性使用一個(gè) MIME 類(lèi)型字符串來(lái)標(biāo)識(shí)<script>的內(nèi)容,但 MIME 類(lèi)型并沒(méi)有跨瀏覽器標(biāo)準(zhǔn)化。即使瀏覽器默認(rèn)使用 JavaScript,在某些情況下某個(gè)無(wú)效或無(wú)法識(shí)別的 MIME 類(lèi)型也可能導(dǎo)致瀏覽器跳過(guò)(不執(zhí)行)相關(guān)代碼。因此,除非你使用 XHTML 或<script>標(biāo)簽要求或包含非 JavaScript 代碼,最佳做法是不指定 type 屬性。在最初采用 script 元素時(shí),它標(biāo)志著開(kāi)始走向與傳統(tǒng) HTML 解析不同的流程。對(duì)這個(gè)元素需要應(yīng)用特殊的解析規(guī)則,而這在不支持 JavaScript 的瀏覽器(特別是 Mosaic)中會(huì)導(dǎo)致問(wèn)題。不支持的瀏覽器會(huì)把<script>元素的內(nèi)容輸出到頁(yè)面上,從而破壞頁(yè)面的外觀。Netscape 聯(lián)合 Mosaic 拿出了一個(gè)解決方案,對(duì)不支持 JavaScript 的瀏覽器隱藏嵌入的 JavaScript 代碼。最終方案是把腳本代碼包含在一個(gè) HTML 注釋中,像這樣:

          <script><!--

          function sayHi(){

          console.log("Hi!");

          }

          //--></script>

          使用這種格式,Mosaic 等瀏覽器就可以忽略<script>標(biāo)簽中的內(nèi)容,而支持 JavaScript 的瀏覽器則必須識(shí)別這種模式,將其中的內(nèi)容作為 JavaScript 來(lái)解析。雖然這種格式仍然可以被所有瀏覽器識(shí)別和解析,但已經(jīng)不再必要,而且不應(yīng)該再使用了。在XHTML 模式下,這種格式也會(huì)導(dǎo)致腳本被忽略,因?yàn)榇a處于有效的 XML 注釋當(dāng)中。

          行內(nèi)代碼與外部文件

          雖然可以直接在 HTML 文件中嵌入 JavaScript 代碼,但通常認(rèn)為最佳實(shí)踐是盡可能將 JavaScript 代碼放在外部文件中。不過(guò)這個(gè)最佳實(shí)踐并不是明確的強(qiáng)制性規(guī)則。推薦使用外部文件的理由如下。

          ? 可維護(hù)性。JavaScript 代碼如果分散到很多 HTML 頁(yè)面,會(huì)導(dǎo)致維護(hù)困難。而用一個(gè)目錄保存所有 JavaScript 文件,則更容易維護(hù),這樣開(kāi)發(fā)者就可以獨(dú)立于使用它們的 HTML 頁(yè)面來(lái)編輯代碼。

          ? 緩存。瀏覽器會(huì)根據(jù)特定的設(shè)置緩存所有外部鏈接的 JavaScript 文件,這意味著如果兩個(gè)頁(yè)面都用到同一個(gè)文件,則該文件只需下載一次。這最終意味著頁(yè)面加載更快。

          ? 適應(yīng)未來(lái)。通過(guò)把 JavaScript 放到外部文件中,就不必考慮用 XHTML 或前面提到的注釋黑科技。包含外部 JavaScript 文件的語(yǔ)法在 HTML 和 XHTML 中是一樣的。在配置瀏覽器請(qǐng)求外部文件時(shí),要重點(diǎn)考慮的一點(diǎn)是它們會(huì)占用多少帶寬。在 SPDY/HTTP2 中,預(yù)請(qǐng)求的消耗已顯著降低,以輕量、獨(dú)立 JavaScript 組件形式向客戶端送達(dá)腳本更具優(yōu)勢(shì)。比如,第一個(gè)頁(yè)面包含如下腳本:

          <script src="mainA.js"></script>

          <script src="component1.js"></script>

          <script src="component2.js"></script>

          <script src="component3.js"></script>

          ...

          后續(xù)頁(yè)面可能包含如下腳本:

          <script src="mainB.js"></script>

          <script src="component3.js"></script>

          <script src="component4.js"></script>

          <script src="component5.js"></script>

          ...

          在初次請(qǐng)求時(shí),如果瀏覽器支持 SPDY/HTTP2,就可以從同一個(gè)地方取得一批文件,并將它們逐個(gè)放到瀏覽器緩存中。從瀏覽器角度看,通過(guò) SPDY/HTTP2 獲取所有這些獨(dú)立的資源與獲取一個(gè)大JavaScript 文件的延遲差不多。在第二個(gè)頁(yè)面請(qǐng)求時(shí),由于你已經(jīng)把應(yīng)用程序切割成了輕量可緩存的文件,第二個(gè)頁(yè)面也依賴的某些組件此時(shí)已經(jīng)存在于瀏覽器緩存中了。當(dāng)然,這里假設(shè)瀏覽器支持 SPDY/HTTP2,只有比較新的瀏覽器才滿足。如果你還想支持那些比較老的瀏覽器,可能還是用一個(gè)大文件更合適。

          文檔模式

          IE5.5 發(fā)明了文檔模式的概念,即可以使用 doctype 切換文檔模式。最初的文檔模式有兩種:混雜模式(quirks mode)和標(biāo)準(zhǔn)模式(standards mode)。前者讓 IE 像 IE5 一樣(支持一些非標(biāo)準(zhǔn)的特性),后者讓 IE 具有兼容標(biāo)準(zhǔn)的行為。雖然這兩種模式的主要區(qū)別只體現(xiàn)在通過(guò) CSS 渲染的內(nèi)容方面,但對(duì)JavaScript 也有一些關(guān)聯(lián)影響,或稱為副作用。本書(shū)會(huì)經(jīng)常提到這些副作用。

          IE 初次支持文檔模式切換以后,其他瀏覽器也跟著實(shí)現(xiàn)了。隨著瀏覽器的普遍實(shí)現(xiàn),又出現(xiàn)了第三種文檔模式:準(zhǔn)標(biāo)準(zhǔn)模式(almost standards mode)。這種模式下的瀏覽器支持很多標(biāo)準(zhǔn)的特性,但是沒(méi)有標(biāo)準(zhǔn)規(guī)定得那么嚴(yán)格。主要區(qū)別在于如何對(duì)待圖片元素周?chē)目瞻祝ㄔ诒砀裰惺褂脠D片時(shí)最明顯)。

          混雜模式在所有瀏覽器中都以省略文檔開(kāi)頭的 doctype 聲明作為開(kāi)關(guān)。這種約定并不合理,因?yàn)榛祀s模式在不同瀏覽器中的差異非常大,不使用黑科技基本上就沒(méi)有瀏覽器一致性可言。標(biāo)準(zhǔn)模式通過(guò)下列幾種文檔類(lèi)型聲明開(kāi)啟:

          <!-- HTML 4.01 Strict -->

          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"

          "http://www.w3.org/TR/html4/strict.dtd">

          <!-- XHTML 1.0 Strict -->

          <!DOCTYPE html PUBLIC

          "-//W3C//DTD XHTML 1.0 Strict//EN"

          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

          <!-- HTML5 -->

          <!DOCTYPE html>

          準(zhǔn)標(biāo)準(zhǔn)模式通過(guò)過(guò)渡性文檔類(lèi)型(Transitional)和框架集文檔類(lèi)型(Frameset)來(lái)觸發(fā):

          <!-- HTML 4.01 Transitional -->

          <!DOCTYPE HTML PUBLIC

          "-//W3C//DTD HTML 4.01 Transitional//EN"

          "http://www.w3.org/TR/html4/loose.dtd">

          <!-- HTML 4.01 Frameset -->

          <!DOCTYPE HTML PUBLIC

          "-//W3C//DTD HTML 4.01 Frameset//EN"

          "http://www.w3.org/TR/html4/frameset.dtd">

          <!-- XHTML 1.0 Transitional -->

          <!DOCTYPE html PUBLIC

          "-//W3C//DTD XHTML 1.0 Transitional//EN"

          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

          <!-- XHTML 1.0 Frameset -->

          <!DOCTYPE html PUBLIC

          "-//W3C//DTD XHTML 1.0 Frameset//EN"

          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

          準(zhǔn)標(biāo)準(zhǔn)模式與標(biāo)準(zhǔn)模式非常接近,很少需要區(qū)分。人們?cè)谡f(shuō)到“標(biāo)準(zhǔn)模式”時(shí),可能指其中任何一個(gè)。而對(duì)文檔模式的檢測(cè)(本書(shū)后面會(huì)討論)也不會(huì)區(qū)分它們。本書(shū)后面所說(shuō)的標(biāo)準(zhǔn)模式,指的就是除混雜模式以外的模式。

          <noscript>元素

          針對(duì)早期瀏覽器不支持 JavaScript 的問(wèn)題,需要一個(gè)頁(yè)面優(yōu)雅降級(jí)的處理方案。最終,<noscript>元素出現(xiàn),被用于給不支持 JavaScript 的瀏覽器提供替代內(nèi)容。雖然如今的瀏覽器已經(jīng) 100%支持JavaScript,但對(duì)于禁用 JavaScript 的瀏覽器來(lái)說(shuō),這個(gè)元素仍然有它的用處。<noscript>元素可以包含任何可以出現(xiàn)在<body>中的 HTML 元素,<script>除外。在下列兩種情況下,瀏覽器將顯示包含在<noscript>中的內(nèi)容:

          ? 瀏覽器不支持腳本;

          ? 瀏覽器對(duì)腳本的支持被關(guān)閉。任何一個(gè)條件被滿足,包含在<noscript>中的內(nèi)容就會(huì)被渲染。否則,瀏覽器不會(huì)渲染<noscript>中的內(nèi)容。

          下面是一個(gè)例子:

          <!DOCTYPE html>

          <html>

          <head>

          <title>Example HTML Page</title>

          <script defer="defer" src="example1.js"></script>

          <script defer="defer" src="example2.js"></script>

          </head>

          <body>

          <noscript>

          <p>This page requires a JavaScript-enabled browser.</p>

          </noscript>

          </body>

          </html>

          這個(gè)例子是在腳本不可用時(shí)讓瀏覽器顯示一段話。如果瀏覽器支持腳本,則用戶永遠(yuǎn)不會(huì)看到它。

          小結(jié)

          JavaScript 是通過(guò)<script>元素插入到 HTML 頁(yè)面中的。這個(gè)元素可用于把 JavaScript 代碼嵌入到HTML 頁(yè)面中,跟其他標(biāo)記混合在一起,也可用于引入保存在外部文件中的 JavaScript。本章的重點(diǎn)可以總結(jié)如下。

          ? 要包含外部 JavaScript 文件,必須將 src 屬性設(shè)置為要包含文件的 URL。文件可以跟網(wǎng)頁(yè)在同一臺(tái)服務(wù)器上,也可以位于完全不同的域。

          ? 所有<script>元素會(huì)依照它們?cè)诰W(wǎng)頁(yè)中出現(xiàn)的次序被解釋。在不使用 defer 和 async 屬性的情況下,包含在<script>元素中的代碼必須嚴(yán)格按次序解釋。

          ? 對(duì)不推遲執(zhí)行的腳本,瀏覽器必須解釋完位于<script>元素中的代碼,然后才能繼續(xù)渲染頁(yè)面的剩余部分。為此,通常應(yīng)該把<script>元素放到頁(yè)面末尾,介于主內(nèi)容之后及</body>標(biāo)簽之前。

          ? 可以使用 defer 屬性把腳本推遲到文檔渲染完畢后再執(zhí)行。推遲的腳本原則上按照它們被列出的次序執(zhí)行。

          ? 可以使用 async 屬性表示腳本不需要等待其他腳本,同時(shí)也不阻塞文檔渲染,即異步加載。異步腳本不能保證按照它們?cè)陧?yè)面中出現(xiàn)的次序執(zhí)行。

          ? 通過(guò)使用<noscript>元素,可以指定在瀏覽器不支持腳本時(shí)顯示的內(nèi)容。如果瀏覽器支持并啟用腳本,則<noscript>元素中的任何內(nèi)容都不會(huì)被渲染。


          主站蜘蛛池模板: av无码免费一区二区三区| 午夜福利av无码一区二区| 亚洲色精品aⅴ一区区三区| 久久久99精品一区二区| 视频在线观看一区二区| 一区二区三区AV高清免费波多| 欧美日韩国产免费一区二区三区 | 亚洲国产激情在线一区| av在线亚洲欧洲日产一区二区| 久久久综合亚洲色一区二区三区 | 国产一区二区三区视频在线观看| 老熟女五十路乱子交尾中出一区| 中文字幕一区二区在线播放| 色窝窝免费一区二区三区| 亚洲综合一区二区精品导航| 久久久精品日本一区二区三区 | 精品一区二区三区在线视频观看 | 国产麻豆精品一区二区三区v视界| 国产精品日韩一区二区三区| 国产精品揄拍一区二区久久| 性色av一区二区三区夜夜嗨| 中文字幕精品一区| 国产精品福利区一区二区三区四区| 国产日韩精品一区二区在线观看| 无码国产精品一区二区免费式影视 | 亚洲福利电影一区二区?| 国产午夜福利精品一区二区三区| 一区二区免费电影| 色系一区二区三区四区五区| 无码人妻一区二区三区av| 亚洲熟女www一区二区三区| 人妻无码视频一区二区三区| 国产一区二区精品久久| 国产亚洲一区二区手机在线观看| 插我一区二区在线观看| 久久久久国产一区二区三区| 香蕉一区二区三区观| 99国产精品一区二区| 人妻少妇精品一区二区三区| 在线观看午夜亚洲一区| 日本一区二区免费看|