Dreamweaver基礎教程:學習JavaScript


簡介

直接寫入 HTML 輸出流:

document.write("<h1>這是一個標題</h1>");
document.write("<p>這是一個段落。</p>");

注:只能在 HTML 輸出中使用 document.write,如果在文檔加載后使用該方法,會覆蓋整個文檔
對事件的反應:

<button type="button" onclick="alert('歡迎!')">點我!</button>

注:alert() 函數對於代碼測試非常方便,onclick 事件只是眾多事件之一。

改變 HTML 內容:

x=document.getElementById("demo");  //查找元素
x.innerHTML="Hello JavaScript";    //改變內容

注:document.getElementById("some id")這個方法是 HTML DOM 中定義的,DOM (Document Object Model)(文檔對象模型)是用於訪問 HTML 元素的正式 W3C 標准。

改變 HTML 圖像:
動態地改變 HTML <image> 的來源(src):

<script>
function changeImage()
{
    var s = document.getElementById('myimage');
    s.src = s.src.match('bulboff')?"/images/pic_bulbon.gif":"/images/pic_bulboff.gif";
}
</script>
<img loading="lazy" id="myimage" onclick="changeImage()" src="/images/pic_bulboff.gif" width="100" height="180">

改變 HTML 樣式:

x=document.getElementById("demo")  //找到元素 
x.style.color="#ff0000";           //改變樣式

驗證輸入:

if isNaN(x) { alert("不是數字"); }

用法

標簽:在 HTML 頁面中插入 JavaScript,請使用 <script> 標簽
外部的 JavaScript:外部文件通常包含被多個網頁使用的代碼,文件擴展名是 .js,請在 <script> 標簽的 "src" 屬性中設置該 .js 文件

可以在 HTML 文檔中放入不限數量的腳本,腳本可位於 HTML 的 <body> 或 <head> 部分中,或者同時存在於兩個部分中
通常的做法是把函數放入 部分中,或者放在頁面底部。

輸出

JavaScript 可以通過不同的方式來輸出數據:

  • 使用 window.alert() 彈出警告框。
  • 使用 document.write() 方法將內容寫到 HTML 文檔中。
  • 使用 innerHTML 寫入到 HTML 元素。
  • 使用 console.log() 寫入到瀏覽器的控制台。

語法

JavaScript 是一個腳本語言,輕量級,但功能強大的編程語言。

字面量

在編程語言中,一般固定值稱為字面量,如 3.14。

  • 數字(Number)字面量 可以是整數或者是小數,或者是科學計數(e),如 123e5 。
  • 字符串(String)字面量 可以使用單引號或雙引號:
"John Doe"
'John Doe'
  • 表達式字面量 用於計算,如5 + 6 、5 * 10 。

  • 數組(Array)字面量 定義一個數組:

 [40, 100, 1, 5, 25, 10] 。
  • 對象(Object)字面量 定義一個對象:
{firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"}
  • 函數(Function)字面量 定義一個函數:
function myFunction(a, b) { return a * b;}

變量

JavaScript 使用關鍵字 var 來定義變量, 使用等號來為變量賦值:

var x, length;
x = 5;
length = 6;

注:變量是一個名稱,字面量是一個值。變量通常是可變的,字面量是一個恆定的值。

操作符

JavaScript語言有多種類型的運算符:

類型 實例 描述
賦值,算術和位運算符 = + - * / 在 JS 運算符中描述
條件,比較及邏輯運算符 == != < > 在 JS 比較運算符中描述

語句

在 HTML 中,JavaScript 語句向瀏覽器發出的命令,語句是用分號分隔:

x = 5 + 6;
y = x * 10;

關鍵字

JavaScript 關鍵字用於標識要執行的操作,和其他任何編程語言一樣,JavaScript 保留了一些關鍵字為自己所用。
注:基本上,編程通用的關鍵字盡量不要使用即可

注釋

不是所有的 JavaScript 語句都是"命令",注釋后的內容將會被瀏覽器忽略
單行注釋以 // 開頭,多行注釋以 /* 開始,以 */ 結尾。

數據類型

JavaScript 有多種數據類型:數字,字符串,數組,對象等等:

var length = 16;                                  // Number 通過數字字面量賦值
var points = x * 10;                              // Number 通過表達式字面量賦值
var lastName = "Johnson";                         // String 通過字符串字面量賦值
var cars = ["Saab", "Volvo", "BMW"];              // Array  通過數組字面量賦值
var person = {firstName:"John", lastName:"Doe"};  // Object 通過對象字面量賦值

函數

JavaScript 語句可以寫在函數內,函數可以重復引用,引用一個函數 = 調用函數(執行函數內的語句):

function myFunction(a, b) {
    return a * b;                                // 返回 a 乘以 b 的結果
}

注:JavaScript 對大小寫是敏感的,使用 Unicode 字符集

函數表達式

JavaScript 函數可以通過一個表達式定義:

var x = function (a, b) {return a * b};
var z = x(4, 3);

以上函數實際上是一個 匿名函數 (函數沒有名稱),函數存儲在變量中,不需要函數名稱,通常通過變量名來調用

Function() 構造函數

函數可以通過內置的 JavaScript 函數構造器(Function())定義:

var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);

注:在 JavaScript 中,需要避免使用 new 關鍵字,建議使用函數表達式替換函數構造器(Function())

自調用函數

函數表達式可以 "自調用",自調用表達式會自動調用,如果表達式后面緊跟 () ,則會自動調用:

(function () {
    var x = "Hello!!";      // 我將調用自己
})();

箭頭函數

箭頭函數表達式的語法比普通函數表達式更簡潔:

(參數1, 參數2, …, 參數N) => { 函數聲明 }

(參數1, 參數2, …, 參數N) => 表達式(單一)
// 相當於:(參數1, 參數2, …, 參數N) =>{ return 表達式; }

(單一參數) => {函數聲明}
單一參數 => {函數聲明}

() => {函數聲明}
// ES5
var x = function(x, y) {
     return x * y;
}
 
// ES6
const x = (x, y) => x * y;

注:當使用箭頭函數的時候,箭頭函數會默認綁定外層 this 的值,所以在箭頭函數中 this 的值和外層的 this 是一樣的。

arguments 對象

JavaScript 函數有個內置的對象 arguments 對象,argument 對象包含了函數調用的參數數組
創建一個函數用來統計所有數值的和:

x = sumAll(1, 123, 500, 115, 44, 88);
 
function sumAll() {
    var i, sum = 0;
    for (i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }
    return sum;
}

使用構造函數調用函數

如果函數調用前使用了 new 關鍵字, 則是調用了構造函數:

// 構造函數:
function myFunction(arg1, arg2) {
    this.firstName = arg1;
    this.lastName  = arg2;
}
 
// This    creates a new object
var x = new myFunction("John","Doe");
x.firstName;                             // 返回 "John"

注:構造函數中 this 關鍵字沒有任何的值,this 的值在函數調用實例化對象(new object)時創建。

作為函數方法調用函數

在 JavaScript 中, 函數是對象,有它的屬性和方法。

call() 和 apply() 是預定義的函數方法, 兩個方法可用於調用函數,兩個方法的第一個參數必須是對象本身

function myFunction(a, b) {
    return a * b;
}
myObject = myFunction.call(myObject, 10, 2);     // 返回 20

myArray = [10, 2];
myObject = myFunction.apply(myObject, myArray);  // 返回 20

call() 和 apply()兩者的區別在於第二個參數: apply傳入的是一個參數數組,也就是將多個參數組合成為一個數組傳入,而call則作為call的參數傳入(從第二個參數開始)。

注:通過 call() 或 apply() 方法可以設置 this 的值, 且作為已存在對象的新方法調用。

閉包

參考函數自我調用:

var add = (function () {
    var counter = 0;
    return function () {return counter += 1;}
})();
 
add();
add();
add();
 
// 計數器為 3

變量 add 指定了函數自我調用的返回字值,自我調用函數只執行一次,設置計數器為 0,並返回函數表達式。

add變量可以作為一個函數使用,它可以訪問函數上一層作用域的計數器,這個叫作 JavaScript 閉包

它使得函數擁有私有變量變成可能,計數器受匿名函數的作用域保護,只能通過 add 方法修改。

注:閉包是一種保護私有變量的機制,在函數執行時形成私有的作用域,保護里面的私有變量不受外界干擾,形成一個不銷毀的棧環境

對象

JavaScript 對象是擁有屬性和方法的數據。

對象定義

定義和創建 JavaScript 對象:

var person = {
    //屬性
    firstName: "John",
    lastName : "Doe",
    id : 5566,
    //方法
    fullName : function() 
	{
       return this.firstName + " " + this.lastName;
    }

對象屬性

可以說 "JavaScript 對象是變量的容器",或者說"JavaScript 對象是鍵值對的容器"。
鍵值對通常寫法為 name : value (鍵與值以冒號分割),鍵值對在 JavaScript 對象通常稱為 對象屬性

可以通過兩種方式訪問對象屬性:

//方法1
person.lastName;
//方法2
person["lastName"];

對象方法

對象的方法定義了一個函數,並作為對象的屬性存儲
對象方法通過添加 () 調用 (作為一個函數):

name = person.fullName();

如果把函數當成屬性訪問(不添加()),它將作為一個定義函數的字符串返回:

name = person.fullName;

作用域

在 JavaScript 中, 作用域為可訪問變量,對象,函數的集合。

局部作用域

變量在函數內聲明,變量為局部作用域,只能在函數內部訪問:

// 此處不能調用 carName 變量
function myFunction() {
    var carName = "Volvo";
    // 函數內可調用 carName 變量
}

不同的函數可以使用相同名稱的變量,局部變量在函數開始執行時創建,函數執行完后局部變量會自動銷毀
注:函數參數只在函數內起作用,是局部變量

全局變量

變量在函數外定義,即為全局變量,全局變量有全局作用域—— 網頁中所有腳本和函數均可使用

var carName = " Volvo";
 
// 此處可調用 carName 變量
function myFunction() {
    // 函數內可調用 carName 變量
} 

如果變量在函數內沒有聲明(沒有使用 var 關鍵字),該變量為全局變量

// 此處可調用 carName 變量
 
function myFunction() {
    carName = "Volvo";
    // 此處可調用 carName 變量
}

變量生命周期

JavaScript 變量生命周期在它聲明時初始化,局部變量在函數執行完畢后銷毀,全局變量在頁面關閉后銷毀

HTML 中的全局變量

在 HTML 中, 全局變量是 window 對象:所有數據變量都屬於 window 對象。

//此處可使用 window.carName
 
function myFunction() {
    carName = "Volvo";
}

事件

HTML 事件是發生在 HTML 元素上的事情, JavaScript 可以觸發這些事件。

HTML 事件

HTML 事件可以是瀏覽器行為,也可以是用戶行為,以下是 HTML 事件的實例:

  • HTML 頁面完成加載
  • HTML input 字段改變時
  • HTML 按鈕被點擊

HTML 元素中可以添加事件屬性,使用 JavaScript 代碼來添加 HTML 元素:

<!-- 單引號 -->
<some-HTML-element some-event='JavaScript 代碼'>

<!-- 雙引號 -->
<some-HTML-element some-event="JavaScript 代碼">

常見的HTML事件

下面是一些常見的HTML事件的列表:

事件 描述
onchange HTML 元素改變
onclick 用戶點擊 HTML 元素
onmouseover 用戶在一個HTML元素上移動鼠標
onmouseout 用戶從一個HTML元素上移開鼠標
onkeydown 用戶按下鍵盤按鍵
onload 瀏覽器已完成頁面的加載

更多事件列表: JavaScript 參考手冊 - HTML DOM 事件

typeof, null, 和 undefined

typeof 操作符

可以使用 typeof 操作符來檢測變量的數據類型

typeof "John"                // 返回 string
typeof 3.14                  // 返回 number
typeof false                 // 返回 boolean
typeof [1,2,3,4]             // 返回 object
typeof {name:'John', age:34} // 返回 object

*注:在JavaScript中,數組是一種特殊的對象類型,因此 typeof [1,2,3,4] 返回 object。 *

null

null是一個只有一個值的特殊類型,表示一個空對象引用(用 typeof 檢測 null 返回是object),可以設置為 null 來清空對象:

var person = null;           // 值為 null(空), 但類型為對象

也可以設置為 undefined 來清空對象:

var person = undefined;     // 值為 undefined, 類型為 undefined

undefined

在 JavaScript 中, undefined 是一個沒有設置值的變量,typeof 一個沒有值的變量會返回 undefined

var person;                  // 值為 undefined(空), 類型是undefined

任何變量都可以通過設置值為 undefined 來清空, 類型為 undefined:

person = undefined;          // 值為 undefined, 類型是undefined

undefined 和 null 的區別

null 和 undefined 的值相等,但類型不等:

typeof undefined             // undefined
typeof null                  // object
null === undefined           // false
null == undefined            // true

類型轉換

數據類型

在 JavaScript 中有 6 種不同的數據類型:

  • string
  • number
  • boolean
  • object
  • function
  • symbol

3 種對象類型:

  • Object
  • Date
  • Array

2 個不包含任何值的數據類型:

  • null
  • undefined

typeof 操作符

可以使用 typeof 操作符來查看 JavaScript 變量的數據類型:

typeof "John"                 // 返回 string
typeof 3.14                   // 返回 number
typeof NaN                    // 返回 number
typeof false                  // 返回 boolean
typeof [1,2,3,4]              // 返回 object
typeof {name:'John', age:34}  // 返回 object
typeof new Date()             // 返回 object
typeof function () {}         // 返回 function
typeof myCar                  // 返回 undefined (如果 myCar 沒有聲明)
typeof null                   // 返回 object

constructor 屬性

constructor 屬性返回所有 JavaScript 變量的構造函數:

"John".constructor                 // 返回函數 String()  { [native code] }
(3.14).constructor                 // 返回函數 Number()  { [native code] }
false.constructor                  // 返回函數 Boolean() { [native code] }
[1,2,3,4].constructor              // 返回函數 Array()   { [native code] }
{name:'John', age:34}.constructor  // 返回函數 Object()  { [native code] }
new Date().constructor             // 返回函數 Date()    { [native code] }
function () {}.constructor         // 返回函數 Function(){ [native code] }

可以使用 constructor 屬性來查看對象是否為數組 (包含字符串 "Array")、日期 (包含字符串 "Date")

function isArray(myArray) {
    return myArray.constructor.toString().indexOf("Array") > -1;
}
function isDate(myDate) {
    return myDate.constructor.toString().indexOf("Date") > -1;
}

JavaScript 類型轉換

  • 全局方法 String():可以將數字、字母、變量、表達式、布爾值、日期轉換為字符串
  • Number 方法 toString():可以將數字轉換為字符串。
  • Boolean 方法 toString():可以將布爾值轉換為字符串,"false"、"true"。
  • Date 方法 toString():可以將日期對象轉換為字符串,返回 “Thu Jul 17 2014 15:38:19 GMT+0200 (W. Europe Daylight Time)”。
  • 全局方法 Number():可以將字符串、布爾值、日期轉換為數字,空字符串轉換為 0,其他的字符串會轉換為 NaN (不是個數字),布爾值對應0和1,日期返回 1404568027739(毫秒數)
  • 一元運算符 +:Operator + 可用於將變量轉換為數字,如果變量不能轉換,則值為 NaN (不是一個數字)。
  • **日期方法 getTime() **:可將日期轉換為數字,返回 1404568027739(毫秒數)。

正則表達式

語法

/正則表達式主體/修飾符(可選)

其中修飾符是可選的:

var patt = /runoob/i
  • /runoob/i 是一個正則表達式。
  • runoob 是一個正則表達式主體 (用於檢索)。
  • i 是一個修飾符 (搜索不區分大小寫)。

使用字符串方法

在 JavaScript 中,正則表達式通常用於兩個字符串方法 : search() 和 replace()。

  • search() 方法:用於檢索字符串中指定的子字符串,或檢索與正則表達式相匹配的子字符串,並返回子串的起始位置。
var str = "Visit Runoob!"; 
var n = str.search(/Runoob/i); //不區分大小
var n = str.search("Runoob");
  • replace() 方法:用於在字符串中用一些字符替換另一些字符,或替換一個與正則表達式匹配的子串。
var str = document.getElementById("demo").innerHTML; 
var txt = str.replace(/microsoft/i,"Runoob"); //不區分大小
var txt = str.replace("Microsoft","Runoob");

使用 RegExp 對象

在 JavaScript 中,RegExp 對象是一個預定義了屬性和方法的正則表達式對象。

  • test() 方法:用於檢測一個字符串是否匹配某個模式,如果字符串中含有匹配的文本,則返回 true,否則返回 false。
var patt = /e/;
patt.test("The best things in life are free!");

//以上兩行代碼可以合並為一行:
/e/.test("The best things in life are free!");
  • **exec() 方法:用於檢索字符串中的正則表達式的匹配,該函數返回一個存放匹配結果的數組,未找到匹配則返回值為 null。
/e/.exec("The best things in life are free!");

參考 JavaScript RegExp 參考手冊

表單

表單驗證

判斷表單字段(fname)值是否存在, 如果不存在,就彈出信息,阻止表單提交:

function validateForm() {
    var x = document.forms["myForm"]["fname"].value;
    if (x == null || x == "") {
        alert("需要輸入名字。");
        return false;
    }
}
<form name="myForm" action="demo_form.php" onsubmit="return validateForm()" method="post">
名字: <input type="text" name="fname">
<input type="submit" value="提交">
</form>

多表單使用同一驗證函數可以使用以下方法:

function validateForm(form) {
    var x = form.name.value;
    if (x == null || x == "") {
        alert("輸入不能為空!");
        return false;
    }
}

所有表單調用時都使用:

onsubmit="return validateForm(this)"

onsubmit="validateForm()" 能夠調用 validateForm() 對表單進行驗證,但是在驗證不通過的情況下,並不能阻止表單提交。
onsubmit="return validateForm()" 當驗證不通過時,返回 false,可以阻止表單提交。

onsubmit="return validateForm()" 相當於復寫了 onsubmit 的默認方法(默認返回 true),根據 validateForm() 的結果返回 true 或 false,當驗證不通過時,返回 false,onsubmit="return false;" 阻止表單提交。

this 的多種指向:

  • 在對象方法中, this 指向調用它所在方法的對象。
  • 單獨使用 this,它指向全局(Global)對象。
  • 函數使用中,this 指向函數的所屬者。
  • 嚴格模式下函數是沒有綁定到 this 上,這時候 this 是 undefined。
  • 在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素
  • apply 和 call 允許切換函數執行的上下文環境(context),即 this 綁定的對象,可以將 this 引用到任何對象。

let 和 const

let關鍵字

塊級作用域(Block Scope)

使用 var 關鍵字聲明的變量不具備塊級作用域的特性,它在 {} 外依然能被訪問到

{ 
    var x = 2; 
}
// 這里可以使用 x 變量

let 聲明的變量只在 let 命令所在的代碼塊 {} 內有效,在 {} 之外不能訪問

{ 
    let x = 2;
}
// 這里不能使用 x 變量

重新定義變量

使用 var 關鍵字重新聲明變量可能會帶來問題,在塊中重新聲明變量也會重新聲明塊外的變量:

var x = 10;
// 這里輸出 x 為 10
{ 
    var x = 2;
    // 這里輸出 x 為 2
}
// 這里輸出 x 為 2

let 關鍵字可以解決這個問題,它只在 let 命令所在的代碼塊 {} 內有效:

var x = 10;
// 這里輸出 x 為 10
{ 
    let x = 2;
    // 這里輸出 x 為 2
}
// 這里輸出 x 為 10

使用全局變量

使用 var 關鍵字聲明的全局作用域變量屬於 window 對象:

var carName = "Volvo";
// 可以使用 window.carName 訪問變量

使用 let 關鍵字聲明的全局作用域變量不屬於 window 對象:

let carName = "Volvo";
// 不能使用 window.carName 訪問變量

重置變量

  • 使用 var 關鍵字聲明的變量在任何地方都可以修改
  • 在相同的作用域或塊級作用域中,不能使用 let 關鍵字來重置 var 關鍵字聲明的變量
  • 在相同的作用域或塊級作用域中,不能使用 let 關鍵字來重置 let 關鍵字聲明的變量
  • 在相同的作用域或塊級作用域中,不能使用 var 關鍵字來重置 let 關鍵字聲明的變量
  • let 關鍵字在不同作用域,或不同塊級作用域中是可以重新聲明賦值的

const 關鍵字

const 用於聲明一個或多個常量,聲明時必須進行初始化,且初始化后值不可再修改
const定義常量與使用let 定義的變量相似:

  • 二者都是塊級作用域
  • 都不能和它所在作用域內的其他變量或函數擁有相同的名稱

兩者還有以下兩點區別:

  • const聲明的常量必須初始化,而let聲明的變量不用
  • const 定義常量的值不能通過再賦值修改,也不能再次聲明。而 let 定義的變量值可以修改。

注:const 定義的變量並非不可改變,比如使用const聲明對象,可以改變對象值。可以使用Object.freeze()方法來 凍結變量 ,被凍結后的對象只能進行讀操作。

重置變量

  • 使用 var 關鍵字聲明的變量在任何地方都可以修改
  • 在相同的作用域或塊級作用域中,不能使用 const 關鍵字來重置 var 和 let關鍵字聲明的變量
  • 在相同的作用域或塊級作用域中,不能使用 const 關鍵字來重置 const 關鍵字聲明的變量
  • const 關鍵字在不同作用域,或不同塊級作用域中是可以重新聲明賦值的

JSON

JSON 是用於存儲和傳輸數據的格式,通常用於服務端向網頁傳遞數據 。

語法規則

  • 數據為 鍵/值 對
  • 數據由逗號分隔
  • 大括號保存對象
  • 方括號保存數組
{"sites":[
    {"name":"Runoob", "url":"www.runoob.com"}, 
    {"name":"Google", "url":"www.google.com"},
    {"name":"Taobao", "url":"www.taobao.com"}
]}

JSON 字符串和 JavaScript 對象互轉

要實現從JSON字符串轉換為JS對象,使用 JSON.parse() 方法:

var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //結果是 {a: 'Hello', b: 'World'}  一個對象

要實現從JS對象轉換為JSON字符串,使用 JSON.stringify() 方法:

var json = JSON.stringify({a: 'Hello', b: 'World'}); //結果是 '{"a": "Hello", "b": "World"}'  一個JSON格式的字符串

void(0) 含義

javascript:void(0) 中最關鍵的是 void 關鍵字, void 是 JavaScript 中非常重要的關鍵字,該操作符指定要計算一個表達式但是不返回值

void(alert("Warnning!"))

href="#"與href="javascript:void(0)"的區別

  • 包含了一個位置信息,默認的錨是#top 也就是網頁的上端。

  • javascript:void(0), 僅僅表示一個死鏈接。

在頁面很長的時候會使用 # 來定位頁面的具體位置,格式為:# + id,如果要定義一個死鏈接請使用 javascript:void(0)

<a href="javascript:void(0);">點我沒有反應的!</a>
<a href="#pos">點我定位到指定位置!</a>
<br>
...
<br>
<p id="pos">尾部定位點</p>

異步編程

異步的概念

異步(Asynchronous, async)是與同步(Synchronous, sync)相對的概念,同步按碼順序執行,異步不按照代碼順序執行,異步的執行效率更高。
通俗地解釋一下異步:異步就是從主線程發射一個子線程來完成任務

什么時候用異步編程

主線程作為一個線程,不能夠同時接受多方面的請求。當一個事件沒有結束時,界面將無法處理其他請求。

現在有一個按鈕,如果設置它的 onclick 事件為一個死循環,那么當這個按鈕按下,整個網頁將失去響應。

子線程有一個局限:一旦發射了以后就會與主線程失去同步,無法確定它的結束。

為了解決這個問題,JavaScript 中的異步操作函數往往通過回調函數來實現異步任務的結果處理

回調函數

回調函數就是一個函數,在啟動一個異步任務的時候就告訴它:等完成了這個任務之后要干什么

function print() {
    document.getElementById("demo").innerHTML="RUNOOB!";
}
setTimeout(print, 3000);

這段程序中的 setTimeout 就是一個消耗時間較長(3 秒)的過程,它的第一個參數是個回調函數,第二個參數是毫秒數,這個函數執行之后會產生一個子線程,子線程會等待 3 秒,然后執行回調函數 "print",在命令行輸出 "Time out"。

不必單獨定義一個函數 print ,常常將上面的程序寫成:

setTimeout(function () {
    document.getElementById("demo").innerHTML="RUNOOB!";
}, 3000);

異步 AJAX

除了 setTimeout 函數以外,異步回調廣泛應用於 AJAX 編程,參考:https://www.runoob.com/ajax/ajax-tutorial.html

XMLHttpRequest 常常用於請求來自遠程服務器上的 XML 或 JSON 數據,一個標准的 XMLHttpRequest 對象往往包含多個回調:

var xhr = new XMLHttpRequest();
 
xhr.onload = function () {
    // 輸出接收到的文字數據
    document.getElementById("demo").innerHTML=xhr.responseText;
}
 
xhr.onerror = function () {
    document.getElementById("demo").innerHTML="請求出錯";
}
 
// 發送異步 GET 請求
xhr.open("GET", "https://www.runoob.com/try/ajax/ajax_info.txt", true);
xhr.send();

XMLHttpRequest 的 onload 和 onerror 屬性都是函數,分別在它請求成功和請求失敗時被調用

如果使用完整的 jQuery 庫,也可以更加優雅的使用異步 AJAX:

$.get("https://www.runoob.com/try/ajax/demo_test.php",function(data,status){
    alert("數據: " + data + "\n狀態: " + status);
});

Promise

Promise 是一個 ECMAScript 6 提供的類,目的是更加優雅地書寫復雜的異步任務。由於 Promise 是 ES6 新增加的,一些舊的瀏覽器並不支持。

構造 Promise

現在新建一個 Promise 對象:

new Promise(function (resolve, reject) {
    // 要做的事情...
});

用 Promise 來實現三次輸出字符串,第一次間隔 1 秒,第二次間隔 4 秒,第三次間隔 3 秒:

new Promise(function (resolve, reject) {
    setTimeout(function () {
        console.log("First");
        resolve();
    }, 1000);
}).then(function () {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            console.log("Second");
            resolve();
        }, 4000);
    });
}).then(function () {
    setTimeout(function () {
        console.log("Third");
    }, 3000);
});

Promise 的使用

下面通過剖析這段 Promise "計時器" 代碼來講述 Promise 的使用:

Promise 構造函數只有一個參數,是一個函數,這個函數在構造之后會直接被異步運行——稱之為起始函數

**起始函數包含兩個參數 resolve 和 reject*8,當 Promise 被構造時起始函數會被異步執行:

new Promise(function (resolve, reject) {
    console.log("Run");
});

resolve 和 reject 都是函數,其中調用 resolve 代表一切正常reject 是出現異常時所調用的

new Promise(function (resolve, reject) {
    var a = 0;
    var b = 1;
    if (b == 0) reject("Divide zero");
    else resolve(a / b);
}).then(function (value) {
    console.log("a / b = " + value);
}).catch(function (err) {
    console.log(err);
}).finally(function () {
    console.log("End");
});

Promise 類有 .then() .catch().finally() 三個方法,這三個方法的參數都是一個函數:

  • .then() 可以將參數中的函數添加到當前 Promise 的正常執行序列;
  • .catch() 則是設定 Promise 的異常處理序列;
  • .finally() 是在 Promise 執行的最后一定會執行的序列。

.then() 傳入的函數會按順序依次執行,有任何異常都會直接跳到 catch 序列:

new Promise(function (resolve, reject) {
    console.log(1111);
    resolve(2222);
}).then(function (value) {
    console.log(value);
    return 3333;
}).then(function (value) {
    console.log(value);
    throw "An error";
}).catch(function (err) {
    console.log(err);
});

執行結果:

1111
2222
3333
An error
  • resolve() 中可以放置一個參數用於向下一個 then 傳遞一個值,then 中的函數也可以返回一個值傳遞給 then。如果 then 中返回的是一個 Promise 對象,那么下一個 then 將相當於對這個返回的 Promise 進行操作
  • reject() 參數中一般會傳遞一個異常給之后的 catch 函數用於處理異常
  • **resolve 和 reject 的作用域只有起始函數,不包括 then 以及其他序列。
  • **resolve 和 reject 並不能夠使起始函數停止運行,別忘了 return。

Promise 函數

可以將上面程序的核心部分寫成一個 Promise 函數:

function print(delay, message) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            console.log(message);
            resolve();
        }, delay);
    });
}

然后實現程序功能:

print(1000, "First").then(function () {
    return print(4000, "Second");
}).then(function () {
    print(3000, "Third");
});

異步函數

異步函數(async function)是 ECMAScript 2017 (ECMA-262) 標准的規范,可以上面實現程序功能的代碼變得更好看:

async function asyncFunc() {
    await print(1000, "First");
    await print(4000, "Second");
    await print(3000, "Third");
}
asyncFunc();

異步函數 async function 中可以使用 await 指令,await 指令后必須跟着一個 Promise,異步函數會在這個 Promise 運行中暫停,直到其運行結束再繼續運行。

異步函數實際上原理與 Promise 原生 API 的機制是一模一樣的,處理異常的機制將用 try-catch 塊實現:

async function asyncFunc() {
    try {
        await new Promise(function (resolve, reject) {
            throw "Some error"; // 或者 reject("Some error")
        });
    } catch (err) {
        console.log(err);
        // 會輸出 Some error
    }
}
asyncFunc();

如果 Promise 有一個正常的返回值,await 語句也會返回它:

async function asyncFunc() {
    let value = await new Promise(
        function (resolve, reject) {
            resolve("Return value");
        }
    );
    console.log(value);
}
asyncFunc();

輸出:

Return value


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM