目录

简介

直接写入 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

Dreamweaver基础教程:学习JavaScript的更多相关文章

  1. .Net程序员之Python基础教程学习----列表和元组 [First Day]

    一. 通用序列操作: 其实对于列表,元组 都属于序列化数据,可以通过下表来访问的.下面就来看看序列的基本操作吧. 1.1 索引: 序列中的所有元素的下标是从0开始递增的. 如果索引的长度的是N,那么所 ...

  2. objective-c基础教程——学习小结

    objective-c基础教程——学习小结   提纲: 简介 与C语言相比要注意的地方 objective-c高级特性 开发工具介绍(cocoa 工具包的功能,框架,源文件组织:XCode使用介绍) ...

  3. javascript入门视频第一天 小案例制作 零基础开始学习javascript

    JavaScript 是我们网页设计师必备的技能之一.我们主要用javascript来写的是网页特效.我们从零基础开始学习javascript入门. 但是,好的同学刚开始不知道怎么学习,接触js,因此 ...

  4. javascript基础教程学习总结(1)

    摘自javascript基础教程 开始: 1.将脚本放在哪里: 1.1 放在html和<html>之间 范例: <!DOCTYPE html PUBLIC "-//W3C/ ...

  5. jascript基础教程学习总结(2)

    摘自:javascript基础教程 用链接对用户进行重定向: js001.html 这个HTML页面基于链接对用户进行重定向 <!DOCTYPE html PUBLIC "-//W3C ...

  6. Python基础教程学习笔记:第一章 基础知识

    Python基础教程 第二版 学习笔记 1.python的每一个语句的后面可以添加分号也可以不添加分号:在一行有多条语句的时候,必须使用分号加以区分 2.查看Python版本号,在Dos窗口中输入“p ...

  7. SpringCloud基础教程学习记录

    这个学习记录是学习自翟永超前辈的SpringCloud的基础教程. 自己写这个教程的目的主要是在于,想要更凝练总结一些其中的一些实用点,顺便做个汇总,这样自己在复习查看的时候更加方便,也能顺着自己的思 ...

  8. JavaScript基础 :学习javascript的原因

    JavaScript是世界上最流行的脚本语言,因为你在电脑.手机.平板上浏览的所有的网页,以及无数基于HTML5的手机App,交互逻辑都是由JavaScript驱动的. 简单地说,JavaScript ...

  9. 【学习笔记】Python基础教程学习笔记

    教程视频网盘共享:http://pan.baidu.com/s/1hrTrR5E 03-python基础.if判断 print 输出数据 print("hahahah")----- ...

  10. .Net程序员之Python基础教程学习----函数和异常处理[Fifth Day]

       今天主要记录,Python中函数的使用以及异常处理. 一.函数:    1.函数的创建以及调用. def Add(val1,val2): return val1+val2; print Add( ...

随机推荐

  1. 2.1 Windows驱动开发:内核链表与结构体

    在Windows内核中,为了实现高效的数据结构操作,通常会使用链表和结构体相结合的方式进行数据存储和操作.内核提供了一个专门用于链表操作的数据结构LIST_ENTRY,可以用来描述一个链表中的每一个节 ...

  2. Vite4+Typescript+Vue3+Pinia 从零搭建(1) - 项目初始化

    项目代码同步至码云 weiz-vue3-template 前提准备 1. node版本 Node.js版本 >= 12,如果有老项目需要旧版本的,推荐用 nvm 管理node版本. PS C:\ ...

  3. 【奶奶看了都会】云服务器部署开源ChatGLM-6B,让你也能拥有自己的ChatGPT

    1.背景 大家好啊,我是小卷. 最近ChatGPT不仅发布了GPT-4,而且解除封印可以联网了.不得不赞叹AI更新迭代的速度真快,都跟不上节奏了.但是大家也注意到了吧,随着ChatGPT的每次更新,O ...

  4. 零基础入门学习Java课堂笔记 ——day05

    面向对象(上) 面向过程:我打算列个计划表一步一步来 面向对象:我喜欢先分析分类,把复杂的问题简单化 1.什么是面向对象!!? 面向对象的本质就是:以类的方式组织代码,以对象的方式组织数据 封装 继承 ...

  5. CTAS建表时报错ORA-65114

    环境: Oracle 19.16 多租户架构 1.问题现象: SQL> create table T1 as select * from v$active_session_history * E ...

  6. Mysql 创建外键、索引的问题

    总结: 创建外键的列,要求必须创建索引,通常我们只需要创建外键就可,索引他会自动创建.若是索引那里已经存在了组合索引,那么组合索引前面的第一列已经有了索引,所以创建外键的时候不会自动创建,但是后面的列 ...

  7. .NET Core开发实战(第34课:MediatR:轻松实现命令查询职责分离模式(CQRS))--学习笔记(下)

    34 | MediatR:轻松实现命令查询职责分离模式(CQRS) 实际上我们在定义我的查询的时候,也可以这样定义,例如我们定义一个 MyOrderQuery,把订单的所有名称都输出出去 namesp ...

  8. Linux-使用cat查看文件后出现乱码,整个终端显示包括shell提示符都是乱码

    问题描述:在bash下用cat显示二进制文件后会出现乱码,整个终端显示包括shell提示符都是乱码,这个跟语言环境无关. 解决办法: 恢复的话,大致有以下几种方法:方法一:盲打输入echo -e '\ ...

  9. 摸鱼快报:golang net/http中的雕虫小技

    以后会开一个板块,摸鱼快报,快速记录这几周开发中雕虫小技. 1. 向开发环境localhost:3000种植cookie 前端使用Create React App脚手架,默认以localhost:30 ...

  10. golang微服务实践:服务注册与服务发现 - Etcd的使用

    为什么? 为什么会有服务注册和服务发现?在它以前我们是怎么做的? 举个例子: 比如我们做MySQL读写分离,就在本地配置一个文件,然后程序读取这个配置文件里的数据进行数据库读写分离的设置. 但是随着业 ...