整合營銷服務(wù)商

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

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

          HTML基礎(chǔ)

          TML的作用

          HTML是用來開發(fā)網(wǎng)頁的,它是開發(fā)網(wǎng)頁的語言

          HTML的定義

          全稱HyperText Mark-up Language,超文本標(biāo)記語言

          標(biāo)記就是標(biāo)簽

          <標(biāo)簽名稱></標(biāo)簽名稱> 比如 <html></html> <h1></h1>等,標(biāo)簽大多數(shù)都是成對出現(xiàn)的。

          超文本 兩層含義:

          1. 因?yàn)榫W(wǎng)頁中還可以有圖片、視頻、音頻等內(nèi)容(超越文本限制)
          2. 它還可以在網(wǎng)頁中跳轉(zhuǎn)到另一個(gè)網(wǎng)頁,與世界各地主機(jī)的網(wǎng)頁鏈接(超鏈接文本)

          HTML的基本結(jié)構(gòu)

          <!DOCTYPE html>
          <html>
              <head>
                  <meta charset="UTF-8">
                  <title>網(wǎng)頁標(biāo)題</title>
              </head>
              <body>
                  網(wǎng)頁顯示內(nèi)容
              </body>
          </html>

          第一行<!DOCTYPE html>是文檔聲明

          用來指定頁面所使用的html的版本, 這里聲明的是一個(gè)html5的文檔

          <html>...</html>標(biāo)簽是開發(fā)人員在告訴瀏覽器

          整個(gè)網(wǎng)頁是從<html>這里開始的,到</html>結(jié)束

          也就是html文檔的開始和結(jié)束標(biāo)簽

          <head>...</head>標(biāo)簽用于定義文檔的頭部

          是負(fù)責(zé)對網(wǎng)頁進(jìn)行設(shè)置標(biāo)題、編碼格式以及引入css和js文件的

          <body>...</body>標(biāo)簽是編寫網(wǎng)頁上顯示的內(nèi)容

          網(wǎng)頁文件的后綴是.html, 一個(gè)html文件就是一個(gè)網(wǎng)頁,html文件用編輯器打開顯示的是文本,可以用文本的方式編輯它,如果用瀏覽器打開,瀏覽器會按照標(biāo)簽描述內(nèi)容將文件渲染成網(wǎng)頁

          VS Code 安裝

          VS Code全拼是 Visual Studio Code 是由微軟研發(fā)的一款免費(fèi)、開源的跨平臺代碼編輯器

          目前是前端(網(wǎng)頁)開發(fā)使用最多的一款軟件開發(fā)工具

          下載網(wǎng)址: https://code.visualstudio.com/Download

          選擇對應(yīng)的安裝包進(jìn)行下載:

          安裝一切默認(rèn)

          VS Code 的插件安裝

          • Chinese(Simplified) Language Pack for VS Code 中文漢化包
          • open in browser 右擊在瀏覽器打開html

          常用的HTML標(biāo)簽

          1 標(biāo)簽不區(qū)分大小寫,但是推薦使用小寫

          2 根據(jù)標(biāo)簽的書寫形式,標(biāo)簽分為雙標(biāo)簽(閉合標(biāo)簽)和單標(biāo)簽(空標(biāo)簽) 2.1 雙標(biāo)簽是指由開始標(biāo)簽和結(jié)束標(biāo)簽組成的一對標(biāo)簽,這種標(biāo)簽允許嵌套和承載內(nèi)容,比如: div標(biāo)簽 2.2 單標(biāo)簽是一個(gè)標(biāo)簽組成,沒有標(biāo)簽內(nèi)容, 比如: img標(biāo)簽

          標(biāo)簽的使用形式

          1. 成對出現(xiàn)的標(biāo)簽
          2. 標(biāo)簽的嵌套
          3. 單個(gè)出現(xiàn)的標(biāo)簽
          4. 帶屬性的標(biāo)簽


          列表標(biāo)簽

          1. 無序列表標(biāo)簽(ul標(biāo)簽)
          2. 有序列表標(biāo)簽(ol標(biāo)簽)

          網(wǎng)頁效果

          表格標(biāo)簽

          <table>標(biāo)簽:表示一個(gè)表格

          <tr>標(biāo)簽:表示表格中的一行

          <td>標(biāo)簽:表示表格中的列

          <th>標(biāo)簽:表示表格中的表頭

          屬性設(shè)置

          border: 1px solid black:設(shè)置邊框和顏色

          border-collapse: collapse:設(shè)置邊框合并



          網(wǎng)頁效果

          表單標(biāo)簽

          表單用于搜集不同類型的用戶輸入的數(shù)據(jù),然后可以把用戶數(shù)據(jù)提交到web服務(wù)器

          <form>標(biāo)簽 表示表單標(biāo)簽,定義整體的表單區(qū)域

          一個(gè)表單中有很多信息組成,比如 姓名,愛好,地址等,這些內(nèi)容有很多其他標(biāo)簽來承載

          這些標(biāo)簽稱為表單元素標(biāo)簽

          網(wǎng)頁效果

          表單提交

          表單用于搜集不同類型的用戶輸入的數(shù)據(jù),然后可以把用戶數(shù)據(jù)提交到web服務(wù)器

          • action屬性 設(shè)置表單數(shù)據(jù)提交地址
          • method屬性 設(shè)置表單提交的方式,一般有“GET”方式和“POST”方式, 不區(qū)分大小寫

          兩種方式的區(qū)別:

          • “GET”方式 : 沒有請求體
          • “POST”方式 : 有請求體

          表單元素屬性設(shè)置

          • name: 表單元素的名稱,用于作為提交表單數(shù)據(jù)時(shí)的參數(shù)名
          • value: 表單元素的值,用于作為提交表單數(shù)據(jù)時(shí)參數(shù)名所對應(yīng)的值

          <!DOCTYPE html>

          <html lang="en">

          <head>

          <meta charset="UTF-8">

          <meta name="viewport" content="width=device-width, initial-scale=1.0">

          <meta http-equiv="X-UA-Compatible" content="ie=edge">

          <title>Document</title>

          </head>

          <body>

          <!--

          姓名 type="text" 定義單行文本輸入框

          密碼 type="password" 定義密碼輸入框

          性別 type="radio" 定義單選框

          愛好 type="checkbox" 定義復(fù)選框

          照片 type="file" 定義上傳文件

          個(gè)人描述 <textarea></textarea> 定義多行文本輸入框

          地址 <select></select> 定義下拉列表

          提交 type="submit" 定義提交按鈕

          重置 type="reset" 定義重置按鈕

          按鈕 type="button" 定義一個(gè)普通按鈕

          -->

          <form action="http://192.168.1.106:8080" method="POST">

          <label>姓名:</label>

          <input type="text" name="username" >

          <br>

          <label>密碼:</label>

          <input type="password" name="password">

          <br>

          <label>性別:</label>

          <input type="radio" name="sex" value="1">男

          <input type="radio" name="sex" value="0">女

          <br>

          <label>愛好:</label>

          <input type="checkbox" name="like" value="睡覺">睡覺

          <input type="checkbox" name="like" value="吃飯">吃飯

          <input type="checkbox" name="like" value="打豆豆">打豆豆

          <br>

          <label>照片:</label>

          <input type="file" name="pic">

          <br>

          <label>個(gè)人描述:</label>

          <textarea name="desc"></textarea>

          <br>

          <label>地址:</label>

          <select name="addr">

          <option value="1">北京</option>

          <option value="2">上海</option>

          <option value="3">廣州</option>

          <option value="4">深圳</option>

          </select>

          <br>

          <input type="submit" value="提交">

          <input type="reset" value="重置">

          <input type="button" value="按鈕">

          </form>

          </body>

          </html>


          點(diǎn)擊提交:

          可以看到服務(wù)器收到了請求報(bào)文。

          擊標(biāo)題下「異步社區(qū)」可快速關(guān)注

          本文包括以下內(nèi)容:

          • 理解函數(shù)為何如此重要

          • 函數(shù)為何是第一類對象

          • 定義函數(shù)的方式

          • 參數(shù)賦值之謎

          在本文這一部分討論JavaScript基礎(chǔ)時(shí),也許你會感到驚訝,我們的第一個(gè)論點(diǎn)是函數(shù)(function)而非對象(object)。當(dāng)然,第3部分會用大量筆墨解釋對象,但歸根結(jié)底,你要理解一些基本事實(shí),像普通人一樣編寫代碼和像“忍者”一樣編寫代碼的最大差別在于是否把JavaScript作為函數(shù)式語言(functional language)來理解。對這一點(diǎn)的認(rèn)知水平?jīng)Q定了你編寫的代碼水平。

          如果你正在閱讀這本文,那么你應(yīng)該不是一位初學(xué)者。對于后續(xù)內(nèi)容,我們假設(shè)你已經(jīng)足夠了解面向?qū)ο蠡A(chǔ)(當(dāng)然,我們會在以后章節(jié)詳細(xì)討論對象的高級概念),但真正理解JavaScript中的函數(shù)才是你能使用的唯一一件重要武器。函數(shù)是如此重要,所以本文及接下來兩章將帶領(lǐng)你徹底理解JavaScript中的函數(shù)。

          JavaScript中最關(guān)鍵的概念是:函數(shù)是第一類對象(first-class objects),或者說它們被稱作一等公民(first-class citizens)。函數(shù)與對象共存,函數(shù)也可以被視為其他任意類型的JavaScript對象。函數(shù)和那些更普通的JavaScript數(shù)據(jù)類型一樣,它能被變量引用,能以字面量形式聲明,甚至能被作為函數(shù)參數(shù)進(jìn)行傳遞。本文一開始會介紹面向函數(shù)編程帶來的差異,你會發(fā)現(xiàn),在需要調(diào)用某函數(shù)的位置定義該函數(shù),能讓我們編寫更緊湊、更易懂的代碼。其次,我們還會探索如何把函數(shù)用作第一類對象來編寫高性能函數(shù)。你能學(xué)到多種不同的函數(shù)定義方式,甚至包括一些新類型,例如箭頭(arrow)函數(shù),它能幫你編寫更優(yōu)雅的代碼。最后,我們會學(xué)習(xí)函數(shù)形參和函數(shù)實(shí)參的區(qū)別,并重點(diǎn)關(guān)注ES6的新增特性,例如剩余參數(shù)和默認(rèn)參數(shù)。

          讓我們通過了解函數(shù)式編程的優(yōu)點(diǎn)來開始學(xué)習(xí)吧。

          你知道嗎?

          • 回調(diào)函數(shù)在哪種情況下會同步調(diào)用,或者異步調(diào)用呢?

          • 箭頭函數(shù)和函數(shù)表達(dá)式的區(qū)別是什么?

          • 你為什么需要在函數(shù)中使用默認(rèn)參數(shù)?

          1.1 函數(shù)式的不同點(diǎn)到底是什么

          函數(shù)及函數(shù)式概念之所以如此重要,其原因之一在于函數(shù)是程序執(zhí)行過程中的主要模塊單元。除了全局JavaScript代碼是在頁面構(gòu)建的階段執(zhí)行的,我們編寫的所有的腳本代碼都將在一個(gè)函數(shù)內(nèi)執(zhí)行。

          由于我們的大多數(shù)代碼會作為函數(shù)調(diào)用來執(zhí)行,因此,我們在編寫代碼時(shí),通用強(qiáng)大的構(gòu)造器能賦予代碼很大的靈活性和控制力。本文的大部分內(nèi)容解釋了如何利用函數(shù)作為第一類對象的特性獲益。首先瀏覽一下對象中我們能使用的功能。JavaScript中對象有以下幾種常用功能。

          • 對象可通過字面量來創(chuàng)建{}。

          • 對象可以賦值給變量、數(shù)組項(xiàng),或其他對象的屬性。

          1var ninja = {};  ?--- 為變量賦值一個(gè)新對象

          2ninjaArray.push({});   ?--- 向數(shù)組中增加一個(gè)新對象

          3ninja.data = {};  ?--- 給某個(gè)對象的屬性賦值為一個(gè)新對象

          • 對象可以作為參數(shù)傳遞給函數(shù)。

          1function hide(ninja){

          2  ninja.visibility = false;

          3}

          4hide({});  ?--- 一個(gè)新創(chuàng)建的對象作為參數(shù)傳遞給函數(shù)

          • 對象可以作為函數(shù)的返回值。

          1function returnNewNinja() {

          2 return {};  ?--- 從函數(shù)中返回了一個(gè)新對象

          3}

          • 對象能夠具有動(dòng)態(tài)創(chuàng)建和分配的屬性。

          1var ninja = {};

          2ninja.name = "Hanzo";  ?--- 為對象分配一個(gè)新屬性

          其實(shí),不同于很多其他編程語言,在JavaScript中,我們幾乎能夠用函數(shù)來實(shí)現(xiàn)同樣的事。

          1.1.1 函數(shù)是第一類對象

          JavaScript中函數(shù)擁有對象的所有能力,也因此函數(shù)可被作為任意其他類型對象來對待。當(dāng)我們說函數(shù)是第一類對象的時(shí)候,就是說函數(shù)也能夠?qū)崿F(xiàn)以下功能。

          • 通過字面量創(chuàng)建。

          1function ninjaFunction() {}

          • 賦值給變量,數(shù)組項(xiàng)或其他對象的屬性。

          1var ninjaFunction = function() {};  ?--- 為變量賦值一個(gè)新函數(shù)

          2ninjaArray.push(function(){});   ?--- 向數(shù)組中增加一個(gè)新函數(shù)

          3ninja.data = function(){};  ?--- 給某個(gè)對象的屬性賦值為一個(gè)新函數(shù)

          • 作為函數(shù)的參數(shù)來傳遞。

          1function call(ninjaFunction){

          2 ninjaFunction();

          3}

          4call(function(){});   ?--- 一個(gè)新函數(shù)作為參數(shù)傳遞給函數(shù)

          • 作為函數(shù)的返回值。

          1function returnNewNinjaFunction() {

          2 return function(){};   ?--- 返回一個(gè)新函數(shù)

          3}

          • 具有動(dòng)態(tài)創(chuàng)建和分配的屬性。

          1var ninjaFunction = function(){};

          2ninjaFunction.ninja = "Hanzo";  ?--- 為函數(shù)增加一個(gè)新屬性

          對象能做的任何一件事,函數(shù)也都能做。函數(shù)也是對象,唯一的特殊之處在于它是可調(diào)用的(invokable),即函數(shù)會被調(diào)用以便執(zhí)行某項(xiàng)動(dòng)作。

          {JavaScript中的函數(shù)式編程!} 

          • 把函數(shù)作為第一類對象是函數(shù)式編程(functional programming)的第一步,函數(shù)式編程是一種編程風(fēng)格,它通過書寫函數(shù)式(而不是指定一系列執(zhí)行步驟,就像那種更主流的命令式編程)代碼來解決問題。函數(shù)式編程可以讓代碼更容易測試、擴(kuò)展及模塊化。不過這是一個(gè)很大的話題,因此本文僅對這個(gè)特性做了肯定。如果你對如何在JavacScript中利用函數(shù)式編程感興趣,推薦閱讀Luis Atencio著(由Manning出版社2016年出版)的《JavaScript函數(shù)式編程》,購買方式見www.manning.com/ books/functional-programming- in-JavaScript。

          第一類對象的特點(diǎn)之一是,它能夠作為參數(shù)傳入函數(shù)。對于函數(shù)而言,這項(xiàng)特性也表明:如果我們將某個(gè)函數(shù)作為參數(shù)傳入另一個(gè)函數(shù),傳入函數(shù)會在應(yīng)用程序執(zhí)行的未來某個(gè)時(shí)間點(diǎn)才執(zhí)行。大家所知道的更一般的概念是回調(diào)函數(shù)(callback function)。下面我們來學(xué)習(xí)這個(gè)重要概念。

          1.1.2 回調(diào)函數(shù)

          每當(dāng)我們建立了一個(gè)將在隨后調(diào)用的函數(shù)時(shí),無論是在事件處理階段通過瀏覽器還是通過其他代碼,我們都是在建立一個(gè)回調(diào)(callback)。這個(gè)術(shù)語源自于這樣一個(gè)事實(shí),即在執(zhí)行過程中,我們建立的函數(shù)會被其他函數(shù)在稍后的某個(gè)合適時(shí)間點(diǎn)“再回來調(diào)用”。

          有效運(yùn)用JavaScript的關(guān)鍵在于回調(diào)函數(shù),相信你已經(jīng)在代碼中使用了很多回調(diào)函數(shù)——不論是單擊一次按鈕、從服務(wù)端接收數(shù)據(jù),還是UI動(dòng)畫的一部分。

          本節(jié)我們會看一些實(shí)際使用回調(diào)函數(shù)的典型例子,例如處理事件、簡單的排序集合。這部分內(nèi)容會有點(diǎn)復(fù)雜,所以在深入學(xué)習(xí)之前,先透徹、完整地理解回調(diào)函數(shù)的概念,用最簡單的形式來展現(xiàn)它。下面我們用一個(gè)簡單例子來闡明這個(gè)概念,此例中的函數(shù)完全沒什么實(shí)際用處,它的參數(shù)接收另一個(gè)函數(shù)的引用,并作為回調(diào)調(diào)用該函數(shù):

          1function useless(ninjaCallback) {

          2 return ninjaCallback();

          3}

          這個(gè)函數(shù)可能沒什么用,但它反映了函數(shù)的一種能力,即將函數(shù)作為另一個(gè)函數(shù)的參數(shù),隨后通過參數(shù)來調(diào)用該函數(shù)。

          我們可以在清單1.1中測試一下這個(gè)名為useless的函數(shù)。

          清單1.1 簡單的回調(diào)函數(shù)例子

          1var text = "Domo arigato!";

          2report("Before defining functions");

          3function useless(ninjaCallback) {

          4  report("In useless function");

          5  return ninjaCallback();

          6}  ?--- 函數(shù)定義,參數(shù)為一個(gè)回調(diào)函數(shù),其函數(shù)體內(nèi)會立即調(diào)用該回調(diào)函數(shù)

          7function getText() {

          8 report("In getText function");

          9 return text;

          10}  ?--- 簡單的函數(shù)定義,僅返回一個(gè)全局變量

          11report("Before making all the calls");

          12assert(useless(getText) === text,

          13     "The useless function works! " + text);   ?--- 把gerText作為回調(diào)函數(shù)傳入上面的useless函數(shù)

          14report("After the calls have been made");

          在這個(gè)代碼清單中,我們使用自定義函數(shù)report(在本文附錄B中定義)來輸出代碼執(zhí)行過程中的信息,這樣一來我們就能通過這些信息來跟蹤程序的執(zhí)行過程。我們還使用了第1章中的斷言函數(shù)assert。該函數(shù)通常使用兩個(gè)參數(shù)。第一個(gè)參數(shù)是用于斷言的表達(dá)式。本例中,我們需要確定使用參數(shù)getText調(diào)用useless函數(shù)返回的值與變量text是否相等(useless(getText) === text)。若第一個(gè)參數(shù)的執(zhí)行結(jié)果為true,斷言通過;反之,斷言失敗。第二個(gè)參數(shù)是與斷言相關(guān)聯(lián)的信息,通常會根據(jù)通過/失敗來輸出到日志上。(附錄B中概括地探討了測試,以及我們對assert函數(shù)和report函數(shù)的簡單實(shí)現(xiàn))。

          這段代碼執(zhí)行完畢后,執(zhí)行結(jié)果如圖1.1所示。可以看到,使用getText參數(shù)調(diào)用useless回調(diào)函數(shù)后,得到了期望的返回值。

          圖1.1 清單1.1中代碼的執(zhí)行結(jié)果

          我們還可以看看這個(gè)簡單的回調(diào)函數(shù)具體是如何執(zhí)行的。如圖1.2所示,getText函數(shù)作為參數(shù)傳入了useless函數(shù)。從該圖中可以看到,在useless函數(shù)體內(nèi),通過callback參數(shù)可以取得getText函數(shù)的引用。隨后,回調(diào)函數(shù)callback()的調(diào)用讓getText函數(shù)得到執(zhí)行,而我們作為參數(shù)傳入的getText函數(shù)則通過useless函數(shù)被回調(diào)。

          圖1.2 執(zhí)行useless(getText)調(diào)用后的執(zhí)行流。getText作為參數(shù)傳入useless函數(shù)并調(diào)用。useless函數(shù)體內(nèi)對傳入函數(shù)進(jìn)行調(diào)用,本例中觸發(fā)了getText函數(shù)的執(zhí)行(即我們對getText函數(shù)進(jìn)行回調(diào))。

          完成這個(gè)過程是很容易的,原因就在于JavaScript的函數(shù)式本質(zhì)讓我們能把函數(shù)作為第一類對象。更進(jìn)一步說,我們的代碼可以寫成如下形式:

          1<pre class="代碼無行號"><code>var text = 'Domo arigato!';

          2function useless(ninjaCallback) {

          3 return ninjaCallback();

          4}

          5assert(useless(<strong>function () { return text;}</strong>) === text,  ?--- 直接以參數(shù)形式定義回調(diào)函數(shù)

          6    "The useless function works! " + text); </code></pre>

          JavaScript的重要特征之一是可以在表達(dá)式出現(xiàn)的任意位置創(chuàng)建函數(shù),除此之外這種方式能使代碼更緊湊和易于理解(把函數(shù)定義放在函數(shù)使用處附近)。當(dāng)一個(gè)函數(shù)不會在代碼的多處位置被調(diào)用時(shí),該特性可以避免用非必須的名字污染全局命名空間。

          在回調(diào)函數(shù)的前述例子中,我們調(diào)用的是我們自己的回調(diào)。除此之外瀏覽器也會調(diào)用回調(diào)函數(shù),回想一下第2章中的下述例子:

          1document.body.addEventListener("mousemove", function() {

          2

          3 var second = document.getElementById("second")

          4;

          5 addMessage(second, "Event: mousemove"

          6);

          7});

          上例同樣是一個(gè)回調(diào)函數(shù),作為mousemove事件的事件處理器,當(dāng)事件發(fā)生時(shí),會被瀏覽器調(diào)用。

          {注意 } 

          本小節(jié)介紹的回調(diào)函數(shù)是其他代碼會在隨后的某個(gè)合適時(shí)間點(diǎn)“回過來調(diào)用”的函數(shù)。你已經(jīng)學(xué)習(xí)了我們自己的代碼調(diào)用回調(diào)(useless函數(shù)例子),也看到了當(dāng)某事件發(fā)生時(shí)瀏覽器發(fā)起調(diào)用(mousemove例子)。注意這些很重要,不同于我們的例子,一些人認(rèn)為回調(diào)會被異步調(diào)用,因此第一個(gè)例子不是一個(gè)真正的回調(diào)。這里之所以提到這些是以防萬一你偶爾會遇見這類激烈的爭論。

          現(xiàn)在讓我們看一個(gè)回調(diào)函數(shù)的用法,它能極大地簡化集合的排序。

          使用比較器排序

          一般情況下只要我們拿到了一組數(shù)據(jù)集,就很可能需要對它進(jìn)行排序。假如有一組隨機(jī)序列的數(shù)字?jǐn)?shù)組:0, 3, 2, 5, 7, 4, 8, 1。也許這個(gè)順序沒什么問題,但很可能早晚需要重新排列它。

          通常來說,實(shí)現(xiàn)排序算法并不是編程任務(wù)中最微不足道的;我們需要為手中的工作選擇最佳算法,實(shí)現(xiàn)它以適應(yīng)當(dāng)前的需要(使這些選項(xiàng)是按照特定順序排列),并且需要小心仔細(xì)不能引入故障。除此之外,唯一特定于應(yīng)用程序的任務(wù)是排列順序。幸運(yùn)的是,所有的JavaScript數(shù)組都能用sort方法。利用該方法可以只定義一個(gè)比較算法,比較算法用于指示按什么順序排列。

          這才是回調(diào)函數(shù)所要介入的!不同于讓排序算法來決定哪個(gè)值在前哪個(gè)值在后,我們將會提供一個(gè)函數(shù)來執(zhí)行比較。我們會讓排序算法能夠獲取這個(gè)比較函數(shù)作為回調(diào),使算法在其需要比較的時(shí)候,每次都能夠調(diào)用回調(diào)。該回調(diào)函數(shù)的期望返回值為:如果傳入值的順序需要被調(diào)換,返回正數(shù);不需要調(diào)換,返回負(fù)數(shù);兩個(gè)值相等,返回0。對于排序上述數(shù)組,我們對比較值做減法就能得到我們所需要的值。

          1<pre class="代碼無行號"><code>var values = [0, 3, 2, 5, 7, 4, 8, 1];

          2values.sort<strong>(function(value1, value2) {</strong>

          3 return value1 - value2;

          4<strong>}</strong>);</code></pre>

          沒有必要思考排序算法的底層細(xì)節(jié)(甚至是選擇了什么算法)。JavaScript引擎每次需要比較兩個(gè)值的時(shí)候都會調(diào)用我們提供的回調(diào)函數(shù)。

          函數(shù)式方式讓我們能把函數(shù)作為一個(gè)單獨(dú)實(shí)體來創(chuàng)建,正像我們對待其他類型一樣,創(chuàng)建它、作為參數(shù)傳入一個(gè)方法并將它作為一個(gè)參數(shù)來接收。函數(shù)就這樣顯示了它一等公民的地位。

          1.2 函數(shù)作為對象的樂趣

          本節(jié)我們會考察函數(shù)和其他對象類型的相似之處。也許讓你感到驚訝的相似之處在于我們可以給函數(shù)添加屬性:

          1var ninja = {};

          2ninja.name = "hitsuke";  ?--- 創(chuàng)建新對象并為其分配一個(gè)新屬性

          3var wieldSword = function(){};

          4wieldSword.swordType = "katana";  ?--- 創(chuàng)建新函數(shù)并為其分配一個(gè)新屬性

          我們再來看看這種特性所能做的更有趣的事:

          • 在集合中存儲函數(shù)使我們輕易管理相關(guān)聯(lián)的函數(shù)。例如,某些特定情況下必須調(diào)用的回調(diào)函數(shù)。

          • 記憶讓函數(shù)能記住上次計(jì)算得到的值,從而提高后續(xù)調(diào)用的性能。

          讓我們行動(dòng)起來吧。

          1.2.1 存儲函數(shù)

          某些例子中(例如,我們需要管理某個(gè)事件發(fā)生后需要調(diào)用的回調(diào)函數(shù)集合),我們會存儲元素唯一的函數(shù)集合。當(dāng)我們向這樣的集合中添加函數(shù)時(shí),會面臨兩個(gè)問題:哪個(gè)函數(shù)對于這個(gè)集合來說是一個(gè)新函數(shù),從而需要被加入到該集合中?又是哪個(gè)函數(shù)已經(jīng)存在于集合中,從而不需要再次加入到集合中?一般來說,管理回調(diào)函數(shù)集合時(shí),我們并不希望存在重復(fù)函數(shù),否則一個(gè)事件會導(dǎo)致同一個(gè)回調(diào)函數(shù)被多次調(diào)用。

          一種顯著有效的簡單方法是把所有函數(shù)存入一個(gè)數(shù)組,通過循環(huán)該數(shù)組來檢查重復(fù)函數(shù)。令人遺憾的是,這種方法的性能較差,尤其作為一個(gè)“忍者”要把事情干得漂亮而不僅是做到能用。我們可以使用函數(shù)的屬性,用適當(dāng)?shù)膹?fù)雜度來實(shí)現(xiàn)它,如清單1.2所示。

          清單1.2 存儲唯一函數(shù)集合

          1var store = {

          2 nextId: 1,  ?--- 跟蹤下一個(gè)要被復(fù)制的函數(shù)

          3 cache: {},  ?--- 使用一個(gè)對象作為緩存,我們可以在其中存儲函數(shù)

          4 add: function(fn) { 

          5   if (!fn.id) {

          6    fn.id = this.nextId++;

          7    this.cache[fn.id] = fn;

          8    return true;

          9  }

          10 }  ?--- 僅當(dāng)函數(shù)唯一時(shí),將該函數(shù)加入緩存

          11};

          12function ninja(){}

          13assert(store.add(ninja), 

          14     "Function was safely added.");

          15assert(!store.add(ninja),

          16     "But it was only added once.");   ?--- 測試上面代碼按預(yù)期工作

          在這個(gè)清單中,我們創(chuàng)建了一個(gè)對象賦值給變量store,這個(gè)變量中存儲的是唯一的函數(shù)集合。這個(gè)對象有兩個(gè)數(shù)據(jù)屬性:其一是下一個(gè)可用的id,另外一個(gè)緩存著已經(jīng)保存的函數(shù)。函數(shù)通過add()方法添加到緩存中。

          1add: function(fn) {

          2  if (!fn.id) {

          3   fn.id = this.nextId++;

          4   this.cache[fn.id] = fn;

          5   return true;

          6  }

          7...

          在add函數(shù)內(nèi),我們首先檢查該函數(shù)是否已經(jīng)存在id屬性。如果當(dāng)前的函數(shù)已經(jīng)有id屬性,我們則假設(shè)該函數(shù)已經(jīng)被處理過了,從而忽略該函數(shù),否則為該函數(shù)分配一個(gè)id(同時(shí)增加nextId)屬性,并將該函數(shù)作為一個(gè)屬性增加到cache上,id作為屬性名。緊接著該函數(shù)的返回值為true,從而可得知調(diào)用了add()后,函數(shù)是什么時(shí)候被添加到存儲中的。

          在瀏覽器中運(yùn)行該程序后,頁面顯示:測試程序嘗試兩次添加ninja()函數(shù),而該函數(shù)只被添加一次到存儲中,如圖1.3所示。第9章展示了用于操作合集的更好技術(shù),它利用了ES6的新的對象類型集合(Set)。

          圖1.3 給函數(shù)附加一個(gè)屬性后,我們就能夠引用該屬性。本例通過這種方式可以確保該ninja函數(shù)僅被添加到函數(shù)中一次

          另外一種有用的技巧是當(dāng)使用函數(shù)屬性時(shí),可以通過該屬性修改函數(shù)自身。這個(gè)技術(shù)可以用于記憶前一個(gè)計(jì)算得到的值,為之后計(jì)算節(jié)省時(shí)間。

          1.2.2 自記憶函數(shù)

          如同前面所提到的,記憶化(memoization)是一種構(gòu)建函數(shù)的處理過程,能夠記住上次計(jì)算結(jié)果。在這個(gè)果殼里,當(dāng)函數(shù)計(jì)算得到結(jié)果時(shí)就將該結(jié)果按照參數(shù)存儲起來。采用這種方式時(shí),如果另外一個(gè)調(diào)用也使用相同的參數(shù),我們則可以直接返回上次存儲的結(jié)果而不是再計(jì)算一遍。像這樣避免既重復(fù)又復(fù)雜的計(jì)算可以顯著地提高性能。對于動(dòng)畫中的計(jì)算、搜索不經(jīng)常變化的數(shù)據(jù)或任何耗時(shí)的數(shù)學(xué)計(jì)算來說,記憶化這種方式是十分有用的。

          看看下面的這個(gè)例子,它使用了一個(gè)簡單的(也的確是效率不高的)算法來計(jì)算素?cái)?shù)。盡管這是一個(gè)復(fù)雜計(jì)算的簡單例子,但它經(jīng)常被應(yīng)用到大計(jì)算量的場景中(例如可以引申到通過字符串生成MD5算法),這里不便展示。

          從外表來說,這個(gè)函數(shù)和任何普通函數(shù)一樣,但在內(nèi)部我們會構(gòu)建一個(gè)結(jié)果緩存,它會保存函數(shù)每次計(jì)算得到的結(jié)果,如清單1.3所示。

          清單1.3 計(jì)算先前得到的值

          1function isPrime(value) {

          2 if (!isPrime.answers) {

          3  isPrime.answers = {};

          4 }  ?--- 創(chuàng)建緩存

          5 if (isPrime.answers[value] !== undefined) {

          6  return isPrime.answers[value];

          7 }  ?--- 檢查緩存的值

          8 var prime = value !== 0 && value !== 1; // 1 is not a prime

          9 for (var i = 2; i < value; i++) {

          10   if (value % i === 0) {

          11    prime = false;

          12    break;

          13   }

          14 }

          15 return isPrime.answers[value] = prime;   ?--- 存儲計(jì)算的值

          16}

          17assert(isPrime(5), "5 is prime!");

          18assert(isPrime.answers[5], "The answer was cached!");   ?--- 測試該函數(shù)是否正常工作

          在isPrime函數(shù)中,首先通過檢查它的answers屬性來確認(rèn)是否已經(jīng)創(chuàng)建了一個(gè)緩存,如果沒有創(chuàng)建,則新建一個(gè):

          1if (!isPrime.answers) {

          2  isPrime.answers = {};

          3}

          只有第一次函數(shù)調(diào)用才會創(chuàng)建這個(gè)初始空對象,之后這個(gè)緩存就已經(jīng)存在了。然后我們會檢查參數(shù)中傳的值是否已經(jīng)存儲到緩存中:

          1if (isPrime.answers[value] !== undefined) {

          2 return isPrime.answers[value];

          3}

          這個(gè)緩存會針對參數(shù)中的值value來存儲該值是否為素?cái)?shù)(true或false)。如果我們在緩存中找到該值,函數(shù)會直接返回。

          1return isPrime.answers[value] = prime;

          這個(gè)緩存是函數(shù)自身的一個(gè)屬性,所以只要該函數(shù)還存在,緩存也就存在。

          最后的測試結(jié)果可以看到記憶函數(shù)生效了。

          1assert(isPrime(5), "5 is prime!");

          2assert(isPrime.answers[5], "The answer was cached!");

          這個(gè)方法具有兩個(gè)優(yōu)點(diǎn)。

          • 由于函數(shù)調(diào)用時(shí)會尋找之前調(diào)用所得到的值,所以用戶最終會樂于看到所獲得的性能收益。

          • 它幾乎是無縫地發(fā)生在后臺,最終用戶和頁面作者都不需要執(zhí)行任何特殊請求,也不需要做任何額外初始化,就能順利進(jìn)行工作。

          當(dāng)然這種方法并不是像玫瑰和提琴一樣完美,還是要權(quán)衡利弊。

          • 任何類型的緩存都必然會為性能犧牲內(nèi)存。

          • 純粹主義者會認(rèn)為緩存邏輯不應(yīng)該和業(yè)務(wù)邏輯混合,函數(shù)或方法只需要把一件事做好。但不必?fù)?dān)心,在第8章你會了解到如何解決這類問題。

          • 對于這類問題很難做負(fù)載測試或估計(jì)算法復(fù)雜度,因?yàn)榻Y(jié)果依賴于函數(shù)之前的輸入。

          現(xiàn)在你看到了函數(shù)作為第一類公民的一些實(shí)例,接下來看看不同的函數(shù)定義的方式。

          1.3 函數(shù)定義

          JavaScript函數(shù)通常由函數(shù)字面量(function literal)來創(chuàng)建函數(shù)值,就像數(shù)字字面量創(chuàng)建一個(gè)數(shù)字值一樣。要記住這一點(diǎn),作為第一類對象,函數(shù)是可以用在編程語言中的值,就像例句字符串或數(shù)字的值。無論你是否意識到了這一點(diǎn),你一直都是這樣做的。

          JavaScript提供了幾種定義函數(shù)的方式,可以分為4類。

          • 函數(shù)定義(function declarations)和函數(shù)表達(dá)式(function expressions)——最常用,在定義函數(shù)上卻有微妙不同的的兩種方式。人們通常不會獨(dú)立地看待它們,但正如你將看到的,意識到兩者的不同能幫我們理解函數(shù)何時(shí)能夠被調(diào)用。

            1function myFun(){ return 1;}

          • 箭頭函數(shù)(通常被叫做lambda函數(shù))——ES6新增的JavaScript標(biāo)準(zhǔn),能讓我們以盡量簡潔的語法定義函數(shù)。

            1myArg => myArg*2

          • 函數(shù)構(gòu)造函數(shù)—— 一種不常使用的函數(shù)定義方式,能讓我們以字符串形式動(dòng)態(tài)構(gòu)造一個(gè)函數(shù),這樣得到的函數(shù)是動(dòng)態(tài)生成的。這個(gè)例子動(dòng)態(tài)地創(chuàng)建了一個(gè)函數(shù),其參數(shù)為a和b,返回值為兩個(gè)數(shù)的和。

            1new Function('a', 'b', 'return a + b')

          • 生成器函數(shù)——ES6新增功能,能讓我們創(chuàng)建不同于普通函數(shù)的函數(shù),在應(yīng)用程序執(zhí)行過程中,這種函數(shù)能夠退出再重新進(jìn)入,在這些再進(jìn)入之間保留函數(shù)內(nèi)變量的值。我們可以定義生成器版本的函數(shù)聲明、函數(shù)表達(dá)式、函數(shù)構(gòu)造函數(shù)。

            1function* myGen(){ yield 1; }

          理解這幾種方式的不同很重要,因?yàn)楹瘮?shù)創(chuàng)建的方式很大程度地影響了函數(shù)可被調(diào)用的時(shí)間、函數(shù)的行為以及函數(shù)可以在哪個(gè)對象上被調(diào)用。

          這一節(jié)中,我們將會探索函數(shù)定義、函數(shù)表達(dá)式和箭頭函數(shù)。你將學(xué)到它們的語法和它們的工作方式,我們也將會在本文中多次回顧它們的細(xì)節(jié)。另一方面,生成器函數(shù)則有一點(diǎn)獨(dú)特,它不同于普通函數(shù)。在第6章我們會再來學(xué)習(xí)它們的細(xì)節(jié)。

          剩下的JavaScript特性——函數(shù)構(gòu)造函數(shù)我們將全部跳過。盡管它具有某些有趣的應(yīng)用場景,尤其是在動(dòng)態(tài)創(chuàng)建和執(zhí)行代碼時(shí),但我們依然認(rèn)為它是JavaScript語言的邊緣功能。如果你想知道更多關(guān)于函數(shù)構(gòu)造函數(shù)的信息,請?jiān)L問http://mng.bz/ZN8e。

          讓我們先用最簡單、最傳統(tǒng)的方式定義函數(shù)吧:函數(shù)聲明和函數(shù)表達(dá)式。

          1.3.1 函數(shù)聲明和函數(shù)表達(dá)式

          JavaScript中定義函數(shù)最常用的方式是函數(shù)聲明和函數(shù)表達(dá)式。這兩種技術(shù)非常相似,有時(shí)甚至難以區(qū)分,但在后續(xù)章節(jié)中你將看到,它們之間還是存在著微妙的差別。

          函數(shù)聲明

          JavaScript定義函數(shù)的最基本方式是函數(shù)聲明(見圖1.4)。正如你所見,每個(gè)函數(shù)聲明以強(qiáng)制性的function開頭,其后緊接著強(qiáng)制性的函數(shù)名,以及括號和括號內(nèi)一列以逗號分隔的可選參數(shù)名。函數(shù)體是一列可以為空的表達(dá)式,這些表達(dá)式必須包含在花括號內(nèi)。除了這種形式以外,每個(gè)函數(shù)聲明還必須包含一個(gè)條件:作為一個(gè)單獨(dú)的JavaScript語句,函數(shù)聲明必須獨(dú)立(但也能夠被包含在其他函數(shù)或代碼塊中,在下一小節(jié)中你將會準(zhǔn)確理解其含義)。

          圖1.4 函數(shù)聲明是獨(dú)立的,是獨(dú)立的JavaScript代碼塊(它可以被包含在其他函數(shù)中)

          清單1.4展示了兩條函數(shù)聲明例子。

          清單1.4 函數(shù)聲明示例

          1function samurai() {

          2 return "samurai here";  ?--- 在全局代碼中定義samurai函數(shù)

          3}

          4function ninja() {  ?--- 在全局代碼中定義ninja函數(shù)

          5 function hiddenNinja() {

          6  return "ninja here";

          7 }  ?--- 在ninja函數(shù)內(nèi)定義hiddenNinja函數(shù)

          8 return hiddenNinja();

          9}

          如果你對函數(shù)式語言沒有太多了解,仔細(xì)看一看,你可能會發(fā)現(xiàn)你并不習(xí)慣這種使用方式: 一個(gè)函數(shù)被定義在另一個(gè)函數(shù)之中!

          1function ninja() {

          2 function hiddenNinja() {

          3   return "ninja here";

          4 }

          5 return hiddenNinja();

          6}

          在JavaScript中,這是一種非常通用的使用方式,這里用它作為例子是為了再次強(qiáng)調(diào)JavaScript中函數(shù)的重要性。

          {注意 } 

          讓函數(shù)包含在另一個(gè)函數(shù)中可能會因?yàn)楹雎宰饔糜虻臉?biāo)識符解析而引發(fā)一些有趣的問題,但現(xiàn)在可以先留下這個(gè)問題,第5章會重新回顧這個(gè)問題的細(xì)節(jié)。

          函數(shù)表達(dá)式

          正如我們多次所提到的,JavaScript中的函數(shù)是第一類對象,除此以外也就意味著它們可以通過字面量創(chuàng)建,可以賦值給變量和屬性,可以作為傳遞給其他函數(shù)的參數(shù)或函數(shù)的返回值。正因?yàn)楹瘮?shù)有如此的基礎(chǔ)結(jié)構(gòu),所以JavaScript能讓我們把函數(shù)和其他表達(dá)式同等看待。例如,如下例子中我們可以使用數(shù)字字面量:

          1var a = 3;

          2myFunction(4);

          同樣,在相同位置可以用函數(shù)字面量:

          1var a = function() {};

          2myFunction(function(){});

          這種總是其他表達(dá)式的一部分的函數(shù)(作為賦值表達(dá)式的右值,或者作為其他函數(shù)的參數(shù))叫作函數(shù)表達(dá)式。函數(shù)表達(dá)式非常重要,在于它能準(zhǔn)確地在我們需要使用的地方定義函數(shù),這個(gè)過程能讓代碼易于理解。清單1.5展示了函數(shù)聲明和函數(shù)表達(dá)式的不同之處。

          清單1.5 函數(shù)聲明和函數(shù)表達(dá)式

          1<pre class="代碼無行號"><code>function myFunctionDeclaration(){  ?--- 獨(dú)立的函數(shù)聲明

          2 function innerFunction() {}  ?--- 內(nèi)部函數(shù)聲明

          3}

          4var myFunc = function(){};  ?--- 函數(shù)表達(dá)式作為變量聲明賦值語句中的一部分

          5myFunc(function(){  ?--- 函數(shù)表達(dá)式作為一次函數(shù)調(diào)用中的參數(shù)

          6  return function(){};  ?--- 函數(shù)表達(dá)式作為函數(shù)返回值

          7});

          8(function <strong>namedFunctionExpression</strong> () {

          9})();  ?--- 作為函數(shù)調(diào)用的一部分,命名函數(shù)表達(dá)式會被立即調(diào)用

          10+function(){}();

          11-function(){}();

          12!function(){}();

          13~function(){}();  ?--- 函數(shù)有達(dá)式可以作為一元操作符的參數(shù)立即調(diào)用</code></pre>

          示例代碼的開頭是標(biāo)準(zhǔn)函數(shù)聲明,其包含一個(gè)內(nèi)部函數(shù)聲明:

          1function myFunctionDeclaration(){

          2 function innerFunction() {}

          3}

          從這個(gè)示例中你能夠看到,函數(shù)聲明是如何作為JavaScript代碼中的獨(dú)立表達(dá)式的,但它也能夠包含在其他函數(shù)體內(nèi)。與之比較的是函數(shù)表達(dá)式,它通常作為其他語句的一部分。它們被放在表達(dá)式級別,作為變量聲明(或者賦值)的右值:

          1var myFunc = function(){};

          或者作為另一個(gè)函數(shù)調(diào)用的參數(shù)或返回值。

          1myFunc(function() {

          2 return function(){};

          3});

          函數(shù)聲明和函數(shù)表達(dá)式除了在代碼中的位置不同以外,還有一個(gè)更重要的不同點(diǎn)是:對于函數(shù)聲明來說,函數(shù)名是強(qiáng)制性的,而對于函數(shù)表達(dá)式來說,函數(shù)名則完全是可選的。

          函數(shù)聲明必須具有函數(shù)名是因?yàn)樗鼈兪仟?dú)立語句。一個(gè)函數(shù)的基本要求是它應(yīng)該能夠被調(diào)用,所以它必須具有一種被引用方式,于是唯一的方式就是通過它的名字。

          從另一方面來看,函數(shù)表達(dá)式也是其他JavaScript表達(dá)式的一部分,所以我們也就具有了調(diào)用它們的替代方案。例如,如果一個(gè)函數(shù)表達(dá)式被賦值給了一個(gè)變量,我們可以用該變量來調(diào)用函數(shù)。

          1var doNothing = function(){};

          2doNothing();

          或者,如果它是另外一個(gè)函數(shù)的參數(shù),我們可以在該函數(shù)中通過相應(yīng)的參數(shù)名來調(diào)用它。

          1function doSomething(action) {

          2 action();

          3}

          立即函數(shù)

          函數(shù)表達(dá)式可以放在初看起來有些奇怪的位置上,例如通常認(rèn)為是函數(shù)標(biāo)識符的位置。接下來仔細(xì)看看這個(gè)構(gòu)造(如圖1.5所示)。

          圖1.5 標(biāo)準(zhǔn)函數(shù)的調(diào)用和函數(shù)表達(dá)式的立即調(diào)用的對比

          當(dāng)想進(jìn)行函數(shù)調(diào)用時(shí),我們需要使用能夠求值得到函數(shù)的表達(dá)式,其后跟著一對函數(shù)調(diào)用括號,括號內(nèi)包含參數(shù)。在最基本的函數(shù)調(diào)用中,我們把求值得到函數(shù)的標(biāo)識符作為左值(如圖1.5所示)。不過用于被括號調(diào)用的表達(dá)式不必只是一個(gè)簡單的標(biāo)識符,它可以是任何能夠求值得到函數(shù)的表達(dá)式。例如,指定一個(gè)求值得到函數(shù)的表達(dá)式的最簡單方式是使用函數(shù)表達(dá)式。如圖1.5中右圖所示,我們首先創(chuàng)建了一個(gè)函數(shù),然后立即調(diào)用這個(gè)新創(chuàng)建的函數(shù)。這種函數(shù)叫作立即調(diào)用函數(shù)表達(dá)式(IIFE),或者簡寫為立即函數(shù)。這一特性能夠模擬JavaScript中的模塊化,故可以說它是JavaScript開發(fā)中的重要理念。第11章中會集中討論IIFE的應(yīng)用。

          {加括號的函數(shù)表達(dá)式!} 

          • 還有一件可能困擾你的是上面例子中我們立即調(diào)用的函數(shù)表達(dá)式方式:函數(shù)表達(dá)式被包裹在一對括號內(nèi)。為什么這樣做呢?其原因是純語法層面的。JavaScript解析器必須能夠輕易區(qū)分函數(shù)聲明和函數(shù)表達(dá)式之間的區(qū)別。如果去掉包裹函數(shù)表達(dá)式的括號,把立即調(diào)用作為一個(gè)獨(dú)立語句function() {}(3),JavaScript開始解析時(shí)便會結(jié)束,因?yàn)檫@個(gè)獨(dú)立語句以function開頭,那么解析器就會認(rèn)為它在處理一個(gè)函數(shù)聲明。每個(gè)函數(shù)聲明必須有一個(gè)名字(然而這里并沒有指定名字),所以程序執(zhí)行到這里會報(bào)錯(cuò)。為了避免錯(cuò)誤,函數(shù)表達(dá)式要放在括號內(nèi),為JavaScript解析器指明它正在處理一個(gè)函數(shù)表達(dá)式而不是語句。

          • 還有一種相對簡單的替代方案(function(){}(3))也能達(dá)到相同目標(biāo)(然而這種方案有些奇怪,故不常使用)。把立即函數(shù)的定義和調(diào)用都放在括號內(nèi),同樣可以為JavaScript解析器指明它正在處理函數(shù)表達(dá)式。

          表1.5中最后4個(gè)表達(dá)式都是立即調(diào)用函數(shù)表達(dá)式主題的4個(gè)不同版本,在JavaScript庫中會經(jīng)常見到這幾種形式:

          1+function(){}();

          2-function(){}();

          3!function(){}();

          4~function(){}();

          不同于用加括號的方式區(qū)分函數(shù)表達(dá)式和函數(shù)聲明,這里我們使用一元操作符+、-、!和~。這種做法也是用于向JavaScript引擎指明它處理的是表達(dá)式,而不是語句。從計(jì)算機(jī)的角度來講,注意應(yīng)用一元操作符得到的結(jié)果沒有存儲到任何地方并不重要,只有調(diào)用IIFE才重要。現(xiàn)在我們已經(jīng)學(xué)會了JavaScript中兩種基本的函數(shù)定義方式(函數(shù)聲明和函數(shù)表達(dá)式)的細(xì)節(jié)。接下來開始探索JavaScript標(biāo)準(zhǔn)中的新增特性:箭頭函數(shù)。

          1.3.2 箭頭函數(shù)

          注意:

          箭頭函數(shù)是JavaScript標(biāo)準(zhǔn)中的ES6新增項(xiàng)(瀏覽器兼容性可參考http://mng.bz/8bnH)。

          由于JavaScript中會使用大量函數(shù),增加簡化創(chuàng)建函數(shù)方式的語法十分有意義,也能讓我們的開發(fā)者生活更愉快。在很多方式中,箭頭函數(shù)是函數(shù)表達(dá)式的簡化版。一起來回顧一下本文開始的排序例子。

          1var values = [0, 3, 2, 5, 7, 4, 8, 1];

          2values.sort(function(value1,value2){

          3 return value1 – value2;

          4});

          這個(gè)例子中,數(shù)組對象的排序方法的參數(shù)傳入了一個(gè)回調(diào)函數(shù)表達(dá)式,JavaScript引擎會調(diào)用這個(gè)回調(diào)函數(shù)以降序排序數(shù)組。現(xiàn)在來看看如何用箭頭函數(shù)來做完全相同的工作:

          1var values = [0, 3, 2, 5, 7, 4, 8, 1];

          2

          3values.sort((

          4

          5value1,value2) => value1 – value2

          6

          7);

          看到這是多么簡潔了吧?

          這種寫法不會產(chǎn)生任何因?yàn)闀鴮慺unction關(guān)鍵字、大括號或者return語句導(dǎo)致的混亂。箭頭函數(shù)語句有著比函數(shù)表達(dá)式更為簡單的方式:函數(shù)傳入兩個(gè)參數(shù)并返回其差值。注意這個(gè)新操作符——胖箭頭符號=>(等號后面跟著大于號)是定義箭頭函數(shù)的核心。

          現(xiàn)在來解析箭頭函數(shù)的語法,首先看看它的最簡形式:

          1param => expression

          這個(gè)箭頭函數(shù)接收一個(gè)參數(shù)并返回表達(dá)式的值,如下面的清單1.6就使用了這種語法。

          清單1.6 比較箭頭函數(shù)和函數(shù)表達(dá)式

          1var greet = name => "Greetings " + name;  ?--- 定義箭頭函數(shù)

          2

          3assert(greet("Oishi") === "Greetings Oishi", "Oishi is properly greeted")

          4;

          5

          6var anotherGreet = function(nam

          7e){

          8 return "Greetings " + n

          9ame;

          10};  ?--- 定義

          11函數(shù)表達(dá)式

          12assert(anotherGreet("Oishi") === "Greetings O

          13ishi",

          14     "Again, Oishi is properly greeted");

          稍作欣賞,使用箭頭函數(shù)的代碼即簡潔又清楚。這是箭頭函數(shù)的最簡語法,但一般情況下,箭頭函數(shù)會被定義成兩種方式,如圖1.6所示。

          稍作欣賞,使用箭頭函數(shù)的代碼即簡潔又清楚。這是箭頭函數(shù)的最簡語法,但一般情況下,箭頭函數(shù)會被定義成兩種方式,如圖1.6所示。

          圖1.6 箭頭函數(shù)的語法

          如你所見,箭頭函數(shù)的定義以一串可選參數(shù)名列表開頭,參數(shù)名以逗號分隔。如果沒有參數(shù)或者多余一個(gè)參數(shù)時(shí),參數(shù)列表就必須包裹在括號內(nèi)。但如果只有一個(gè)參數(shù)時(shí),括號就不是必須的。參數(shù)列表之后必須跟著一個(gè)胖箭頭符號,以此向我們和JavaScript引擎指示當(dāng)前處理的是箭頭函數(shù)。

          胖箭頭操作符后面有兩種可選方式。如果要?jiǎng)?chuàng)建一個(gè)簡單函數(shù),那么可以把表達(dá)式放在這里(可以是數(shù)學(xué)運(yùn)算、其他的函數(shù)調(diào)用等),則該函數(shù)的返回值即為此表達(dá)式的返回值。例如,第一個(gè)箭頭函數(shù)的示例如下:

          1var greet = name => "Greetings " + name;

          這個(gè)箭頭函數(shù)的返回值是字符串“Greetings”和參數(shù)name的結(jié)合。在其他案例中,當(dāng)箭頭函數(shù)沒那么簡單從而需要更多代碼時(shí),箭頭操作符后則可以跟一個(gè)代碼塊,例如:

          1var greet = name => {

          2 var helloString = 'Greetings ';

          3 return helloString + name;

          4};

          這段代碼中箭頭函數(shù)的返回值和普通函數(shù)一樣。如果沒有return語句,返回值是undefined;反之,返回值就是return表達(dá)式的值。

          在本文中我們會多次回顧箭頭函數(shù)。除此之外,我們還會展示箭頭函數(shù)的一些額外功能,它能幫助我們規(guī)避一些在很多標(biāo)準(zhǔn)函數(shù)中可能遇到的難以捉摸的缺陷。箭頭函數(shù)和很多其他函數(shù)一樣,可以通過接收參數(shù)來執(zhí)行任務(wù)。接下來看看當(dāng)向函數(shù)內(nèi)傳入?yún)?shù)后,該參數(shù)值發(fā)生了什么。

          本文摘自《JavaScript忍者秘籍(第2版)》

          《JavaScript忍者秘籍 第2版》

          [美] John,Resig(萊西格),Bear,Bibeault(貝比奧特),Josip ... 著

          點(diǎn)擊封面購買紙書

          JavaScript 正以驚人的速度成為各種應(yīng)用程序的通用語言,包括 Web、桌面、云和移動(dòng)設(shè)備上的應(yīng)用程序。當(dāng)成為 JavaScript 專業(yè)開發(fā)者時(shí),你將擁有可應(yīng)用于所有這些領(lǐng)域的、強(qiáng)大的技能集。

          《JavaScript 忍者秘籍(第2版)》使用實(shí)際的案例清晰地詮釋每一個(gè)核心概念和技術(shù)。本書向讀者介紹了如何掌握 JavaScript 核心的概念,諸如函數(shù)、閉包、對象、原型和 promise,同時(shí)還介紹了 JavaScript API, 包括 DOM、事件和計(jì)時(shí)器。你將學(xué)會測試、跨瀏覽器開發(fā),所有這些都是高級JavaScript開發(fā)者應(yīng)該掌握的技能。

          小福利

          關(guān)注【異步社區(qū)】服務(wù)號,轉(zhuǎn)發(fā)本文至朋友圈或 50 人以上微信群,截圖發(fā)送至異步社區(qū)服務(wù)號后臺,并在文章底下留言,分享你的JavaScript開發(fā)經(jīng)驗(yàn)或者本書的試讀體驗(yàn),我們將選出3名讀者贈(zèng)送《JavaScript 忍者秘籍(第2版)》1本,趕快積極參與吧!

          活動(dòng)截止時(shí)間:2018 年3月15日

          在“異步社區(qū)”后臺回復(fù)“關(guān)注”,即可免費(fèi)獲得2000門在線視頻課程;推薦朋友關(guān)注根據(jù)提示獲取贈(zèng)書鏈接,免費(fèi)得異步圖書一本。趕緊來參加哦!

          掃一掃上方二維碼,回復(fù)“關(guān)注”參與活動(dòng)!

          閱讀原文

          TML: HyperText Markup Language 超文本標(biāo)記語言

          HTML代碼不區(qū)分大小寫, 包括HTML標(biāo)記、屬性、屬性值都不區(qū)分大小寫;

          任何空格或回車鍵在代碼中都無效,插入空格或回車有專用的標(biāo)記,分別是 、<br>

          HTML標(biāo)記中不要有空格,否則瀏覽器可能無法識別。

          如何添加注釋(comment:評論;注釋)

          <!-- -->
          <comment></comment>
          <!-- --> 不能留有空格


          字符集

          <meta http-equiv="Content-Type" content="text/html;charset=#"/>


          <base target="_blank">

          可以將a鏈接的默認(rèn)屬性設(shè)置為_blank屬性

          單個(gè)標(biāo)簽要有最好有結(jié)束符(可以沒有結(jié)束符)

          <br/> <img src="" width="" /> 

          便于兼容XHTML(XHTML必須要有結(jié)束符)

          HTML標(biāo)簽的屬性值可以有引號,可以沒有引號,為了提高代碼的可讀性,推薦使用引號(單引號和雙引號),盡管屬性值是整數(shù),也推薦加上引號。

          <marquee behavior="slide"></marquee> 

          便于兼容XHTML(XHTML必須要有引號)

          <marquee behavior=slide></marquee>

          經(jīng)過測試,以上程序都可以正確運(yùn)行


          HTML標(biāo)簽涉及到的顏色值格式:

          color_name 規(guī)定顏色值為顏色名稱的文本顏色(比如 "red")。

          hex_number 規(guī)定顏色值為十六進(jìn)制值的文本顏色(比如 "#ff0000")。

          rgb_number 規(guī)定顏色值為 rgb 代碼的文本顏色(比如 "rgb(255,0,0)")。

          transparent 透明色 color:transparent

          rgba(紅0-255,綠0-255,藍(lán)0-255,透明度0-1)

          opacity屬性: 就是葫蘆娃兄弟老六(技能包隱身)

          css:

          div{opacity:0.1} /*取值為0-1*/

          英文(顏色值)不區(qū)分大小寫

          HTML中顏色值:采用十六進(jìn)制兼容性最好(十六進(jìn)制顯示顏色效果最佳)

          CSS中顏色值:不存在兼容性

          紅色 #FF0000

          綠色 #00FF00

          藍(lán)色 #0000FF

          黑色: #000000

          灰色 #CCCCCC

          白色 #FFFFFF

          青色 #00FFFF

          洋紅 #FF00FF

          黃色 #FFFF00


          請問后綴 html 和 htm 有什么區(qū)別?

          答: 1. 如果一個(gè)網(wǎng)站有 index.html和index.htm,默認(rèn)情況下,優(yōu)先訪問.html

          2. htm后綴是為了兼容以前的DOS系統(tǒng)8.3的命名規(guī)范

          XHTML與HTML之間的關(guān)系?

          XHTML是EXtensible HyperText Markup Language的英文縮寫,即可擴(kuò)展的超文本標(biāo)記語言.

          XHTML語言是一種標(biāo)記語言,它不需要編譯,可以直接由瀏覽器執(zhí)行.

          XHTML是用來代替HTML的, 是2000年w3c公布發(fā)行的.

          XHTML是一種增強(qiáng)了的HTML,它的可擴(kuò)展性和靈活性將適應(yīng)未來網(wǎng)絡(luò)應(yīng)用更多的需求.

          XHTML是基于XML的應(yīng)用.

          XHTML更簡潔更嚴(yán)謹(jǐn).

          XHTML也可以說就是HTML一個(gè)升級版本.(w3c描述它為'HTML 4.01')

          XHTML是大小寫敏感的,XHTML與HTML是不一樣的;HTML不區(qū)分大小寫,標(biāo)準(zhǔn)的XHTML標(biāo)簽應(yīng)該使用小寫.

          XHTML屬性值必須使用引號,而HTML屬性值可用引號,可不要引號

          XHTML屬性不能簡寫:如checked必須寫成checked="checked"

          單標(biāo)記<br>, XHTML必須有結(jié)束符<br/>,而HTML可以使用<br>,也可以使用<br/>

          除此之外XHTML和HTML基本相同.


          網(wǎng)頁寬度設(shè)置多少為最佳?

          960px


          target屬性值理解

          _self 在當(dāng)前窗口中打開鏈接文件,是默認(rèn)值

          _blank 開啟一個(gè)新的窗口打開鏈接文件

          _parent 在父級窗口中打開文件,常用于框架頁面

          _top 在頂層窗口中打開文件,常用語框架頁面


          字符集:

          charset=utf-8

          Gb2312 簡單中文字符集, 最常用的中文字符

          Gbk 簡繁體字符集, 中文字符集

          Big5 繁體字符集, 臺灣等等

          Utf-8 世界性語言的字符集

          ANSI編碼格式編碼格式的擴(kuò)展字符集有g(shù)b2312和gbk

          單位問題:

          HTML屬性值數(shù)值型的一般不帶單位, CSS必須帶單位;


          強(qiáng)制刷新

          ctrl+F5


          主站蜘蛛池模板: 国产在线不卡一区二区三区 | 国产一区二区三区免费在线观看| 国产午夜精品免费一区二区三区| 日本精品一区二区三区在线视频| 高清无码一区二区在线观看吞精| 亲子乱AV视频一区二区| 91精品一区二区| 国产精品第一区揄拍无码| 国产丝袜视频一区二区三区 | 国产一区二区在线观看| 国产伦精品一区二区三区视频猫咪| 国产一区二区不卡在线播放| 无码精品一区二区三区| 色婷婷一区二区三区四区成人网 | 精品亚洲AV无码一区二区三区| 中文字幕日韩精品一区二区三区| 国产在线一区二区三区av| 久久久不卡国产精品一区二区| 国产精品视频一区麻豆| 亚洲国产精品自在线一区二区| 一区二区在线视频观看| 日本免费一区尤物| 久久一区二区三区精华液使用方法| 亚洲一区二区三区影院 | 国产午夜精品一区二区三区| 国产AV国片精品一区二区| 后入内射国产一区二区| 91一区二区在线观看精品| 内射女校花一区二区三区| 国产乱码精品一区二区三区中文| 国产激情一区二区三区四区 | 日韩一区二区久久久久久| 日本高清成本人视频一区| 伊人精品视频一区二区三区| 一区二区在线视频免费观看| 波多野结衣的AV一区二区三区| 在线观看国产一区| 精品无码人妻一区二区三区品| 久久4k岛国高清一区二区| 韩国福利一区二区美女视频| 亚洲国产欧美一区二区三区|