1. JavaScript 输出
1.1 JavaScript 显示数据
JavaScript 可以通过不同的方式来输出数据:
- 使用 window.alert() 弹出警告框。
- 使用 document.write() 方法将内容写到 HTML 文档中。
- 使用 innerHTML 写入到 HTML 元素。
- 使用 console.log() 写入到浏览器的控制台。
1.2 window.alert()
<!DOCTYPE html>
<html>
<body>
<h1>我的第一个页面</h1>
<p>我的第一个段落。</p>
<script>
window.alert(5 + 6);
</script>
</body>
</html>
1.3 操作 HTML 元素
<!DOCTYPE html>
<html>
<body>
<h1>我的第一个 Web 页面</h1>
<p id="demo">我的第一个段落</p>
<script>
document.getElementById("demo").innerHTML = "段落已修改。";
</script>
</body>
</html>
1.4 写到 HTML 文档
<!DOCTYPE html>
<html>
<body>
<h1>我的第一个页面</h1>
<p id="demo">我的第一个段落。</p>
<script>
document.write(Date.now())
</script>
</body>
</html>
使用 document.write() 仅仅向文档输出写内容。
如果在文档已完成加载后执行 document.write,整个 HTML 页面将被覆盖。
<!DOCTYPE html>
<html>
<body>
<h1>我的第一个页面</h1>
<p >我的第一个段落。</p>
<button onclick="myFuntion()">button</button>
<script>
function myFuntion(){
document.write(Date())
}
</script>
</body>
</html>
点击后
2. 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 通过对象字面量赋值
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。
**引用数据类型(对象类型):**对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。
2.1 JavaScript 拥有动态类型
var x; // x 为 undefined
var x = 5; // 现在 x 为数字
var x = "John"; // 现在 x 为字符串
变量的数据类型可以使用 typeof 操作符来查看:
typeof "John" // 返回 string
typeof 3.14 // 返回 number
typeof false // 返回 boolean
typeof [1,2,3,4] // 返回 object
typeof {name:'John', age:34} // 返回 object
2.2 JavaScript 数组
下面的代码创建名为 cars 的数组:
var cars=new Array();
cars[0]="Saab";
cars[1]="Volvo";
cars[2]="BMW";
或者 (condensed array):
var cars=new Array("Saab","Volvo","BMW");
或者 (literal array):
var cars=["Saab","Volvo","BMW"];
数组下标是基于零的,所以第一个项目是 [0],第二个是 [1],以此类推。
2.3 JavaScript 对象
对象由花括号分隔。在括号内部,对象的属性以名称和值对的形式 (name : value) 来定义。属性由逗号分隔:
var person={firstname:"John", lastname:"Doe", id:5566};
对象属性有两种寻址方式:
name=person.lastname;
name=person["lastname"];
2.2 Undefined 和 Null
Undefined 这个值表示变量不含有值。
可以通过将变量的值设置为 null 来清空变量。
cars=null;
person=null;
2.3 声明变量类型
声明新变量时,可以使用关键词 “new” 来声明其类型:
var carname=new String;
var x= new Number;
var y= new Boolean;
var cars= new Array;
var person= new Object;
JavaScript 变量均为对象。当您声明一个变量时,就创建了一个新的对象。
3. JavaScript 对象
在 JavaScript中,几乎所有的事物都是对象。
对象也是一个变量,但对象可以包含多个值(多个变量),每个值以 name:value 对呈现。
var car = {name:"Fiat", model:500, color:"white"};
3.1 对象方法
-
对象的方法定义了一个函数,并作为对象的属性存储。
-
对象方法通过添加 () 调用 (作为一个函数)。
var person = {
"name":"ryuKiMu",
"age": 21,
"getName" :function(){
return this.name
},
}
console.log(person.getName());
4. JavaScript 函数
函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。
4.1 JavaScript 函数语法
函数就是包裹在花括号中的代码块,前面使用了关键词 function:
function functionname()
{
// 执行代码
}
4.2 JavaScript 作用域
JavaScript 函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它。
函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。
JavaScript 变量的生命期从它们被声明的时间开始。
-
局部变量会在函数运行以后被删除。
-
全局变量会在页面关闭后被删除。
在 HTML 中, 全局变量是 window 对象: 所有数据变量都属于 window 对象。
4.3 向未声明的 JavaScript 变量分配值
如果您把值赋给尚未声明的变量,该变量将被自动作为 window 的一个属性。
carname="Volvo"; //将声明 window 的一个属性 carname。
非严格模式下给未声明变量赋值创建的全局变量,是全局对象的可配置属性,可以删除。
console.log(window.var2); // 2
delete var2;
console.log(delete var2); // true
console.log(var2); // 已经删除 报错变量未定义
5. JavaScript 事件
HTML 事件可以是浏览器行为,也可以是用户行为。
以下是 HTML 事件的实例:
- HTML 页面完成加载
- HTML input 字段改变时
- HTML 按钮被点击
在以下实例中,按钮元素中添加了 onclick 属性 (并加上代码):
<p id="demo"></p>
<button onclick="getElementById('demo').innerHTML=Date()">获取当前时间</button>
下一个实例中,代码将修改自身元素的内容 (使用 this.innerHTML):
<button onclick="this.innerHTML=Date()">获取当前时间</button>
5.1 常见的HTML事件
事件 | 描述 |
---|---|
onchange | HTML 元素改变 |
onclick | 用户点击 HTML 元素 |
onmouseover | 鼠标指针移动到指定的元素上时发生 |
onmouseout | 用户从一个 HTML 元素上移开鼠标时发生 |
onkeydown | 用户按下键盘按键 |
onload | 浏览器已完成页面的加载 |
6. JavaScript 字符串
JavaScript 字符串用于存储和处理文本。
- 字符串的索引从 0 开始,这意味着第一个字符索引值为 [0],第二个为 [1], 以此类推
- 可以使用内置属性 length 来计算字符串的长度
- 可以使用索引位置来访问字符串中的每个字符
var name = "ryukimu"
var charName = name[5]
var nameLength = name.length
console.log("第六个字符为"+charName);
console.log("name的字符长度为"+nameLength);
6.1 转义字符
代码 | 输出 |
---|---|
’ | 单引号 |
" | 双引号 |
\ | 反斜杠 |
\n | 换行 |
\r | 回车 |
\t | tab(制表符) |
\b | 退格符 |
\f | 换页符 |
6.2 字符串可以是对象
通常, JavaScript 字符串是原始值,可以使用字符创建,但我们也可以使用 new 关键字将字符串定义为一个对象。
var name = "ryukimu"
var newName = new String("ryukimu")
console.log(typeof name)
console.log(typeof newName)
console.log(newName)
6.3 字符串属性
属性 | 描述 |
---|---|
constructor | 返回创建字符串属性的函数 |
length | 返回字符串的长度 |
prototype | 允许您向对象添加属性和方法 |
6.4 字符串方法
方法 | 描述 |
---|---|
charAt() | 返回指定索引位置的字符 |
charCodeAt() | 返回指定索引位置字符的 Unicode 值 |
concat() | 连接两个或多个字符串,返回连接后的字符串 |
fromCharCode() | 将 Unicode 转换为字符串 |
indexOf() | 返回字符串中检索指定字符第一次出现的位置 |
lastIndexOf() | 返回字符串中检索指定字符最后一次出现的位置 |
localeCompare() | 用本地特定的顺序来比较两个字符串 |
match() | 找到一个或多个正则表达式的匹配 |
replace() | 替换与正则表达式匹配的子串 |
search() | 检索与正则表达式相匹配的值 |
slice() | 提取字符串的片断,并在新的字符串中返回被提取的部分 |
split() | 把字符串分割为子字符串数组 |
substr() | 从起始索引号提取字符串中指定数目的字符 |
substring() | 提取字符串中两个指定的索引号之间的字符 |
toLocaleLowerCase() | 根据主机的语言环境把字符串转换为小写,只有几种语言(如土耳其语)具有地方特有的大小写映射 |
toLocaleUpperCase() | 根据主机的语言环境把字符串转换为大写,只有几种语言(如土耳其语)具有地方特有的大小写映射 |
toLowerCase() | 把字符串转换为小写 |
toString() | 返回字符串对象值 |
toUpperCase() | 把字符串转换为大写 |
trim() | 移除字符串首尾空白 |
valueOf() | 返回某个字符串对象的原始值 |
7. null和undefined
null
- 在 JavaScript 中 null 表示 “什么都没有”。
- null是一个只有一个值的特殊类型。表示一个空对象引用。
- 你可以设置为 null 来清空对象
var person = null; // 值为 null(空), 但类型为对象
undefined
-
在 JavaScript 中, undefined 是一个没有设置值的变量。
-
typeof 一个没有值的变量会返回 undefined。
var person; // 值为 undefined(空), 类型是undefined
undefined 和 null 的区别
- null 和 undefined 的值相等,但类型不等:
typeof undefined // undefined
typeof null // object
null === undefined // false
null == undefined // true
8. JavaScript 类型转换
Number() 转换为数字, String() 转换为字符串, Boolean() 转换为布尔值。
在 JavaScript 中有 6 种不同的数据类型:
- string
- number
- boolean
- object
- function
- symbol
3 种对象类型:
- Object
- Date
- Array
2 个不包含任何值的数据类型:
- null
- undefined
JavaScript 变量可以转换为新变量或其他数据类型:
- 通过使用 JavaScript 函数
- 通过 JavaScript 自身自动转换
8.1 将数字转换为字符串
全局方法 String() 可以将数字转换为字符串,该方法可用于任何类型的数字,字母,变量,表达式
var a = 123
var b = String(a)
console.log(a);
console.log(b);
//Number 方法 toString() 也是有同样的效果。
var c = b.toString(a);
console.log(c);
8.2 将字符串转换为数字
全局方法 Number() 可以将字符串转换为数字。
字符串包含数字(如 “3.14”) 转换为数字 (如 3.14).
空字符串转换为 0。
其他的字符串会转换为 NaN (不是个数字)。
var a = "123"
var b = ""
var c = "一二三"
var toNumber = Number(a)
console.log(toNumber);
toNumber = Number(b)
console.log(toNumber);
toNumber = Number(c)
console.log(toNumber);
8.3 一元运算符 +
Operator + 可用于将变量转换为数字:
var a = "123"
var b = +a
console.log(b);
9. JavaScript 正则表达式
正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。
搜索模式可用于文本搜索和文本替换。
-
正则表达式是由一个字符序列形成的搜索模式。
-
当你在文本中搜索数据时,你可以用搜索模式来描述你要查询的内容。
-
正则表达式可以是一个简单的字符,或一个更复杂的模式。
-
正则表达式可用于所有文本搜索和文本替换的操作。
语法:
/正则表达式主体/修饰符(可选)
使用字符串方法:
在 JavaScript 中,正则表达式通常用于两个字符串方法 : search() 和 replace()。
-
search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串,并返回子串的起始位置。
-
replace() 方法用于在字符串中用一些字符串替换另一些字符串,或替换一个与正则表达式匹配的子串。
9.1 search() 方法使用正则表达式
var str = "ryukimu"
// /mu/i 是一个正则表达式,mu是一个正则表达式主体 (用于检索),i是一个修饰符 (搜索不区分大小写):
var n = str.search(/mu/i)
//search()方法使用字符串使用字符串作为参数。字符串参数会转换为正则表达式:
var m = str.search("mu")
console.log("mu字符串在第"+n+"位开始");
console.log("mu字符串在第"+m+"位开始");
9.2 replace() 方法使用正则表达式
//使用正则表达式且不区分大小写将字符串中的mu替换为OOO:
var str = "ryukimu"
var n = str.replace(/mu/i,"OOO")
console.log(n);
//replace() 方法将接收字符串作为参数将字符串中的mu替换为OOO:
var n = str.replace("mu","OOO")
console.log(n);
9.3 正则表达式修饰符
修饰符 可以在全局搜索中不区分大小写:
修饰符 | 描述 |
---|---|
i | 执行对大小写不敏感的匹配。 |
g | 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。 |
m | 执行多行匹配。 |
9.4 正则表达式模式
方括号用于查找某个范围内的字符:
表达式 | 描述 |
---|---|
[abc] | 查找方括号之间的任何字符。 |
[0-9] | 查找任何从 0 至 9 的数字。 |
(x|y) | 查找任何以 | 分隔的选项。 |
元字符是拥有特殊含义的字符:
元字符 | 描述 |
---|---|
\d | 查找数字。 |
\s | 查找空白字符。 |
\b | 匹配单词边界。 |
\uxxxx | 查找以十六进制数 xxxx 规定的 Unicode 字符。 |
量词:
量词 | 描述 |
---|---|
n+ | 匹配任何包含至少一个 n 的字符串。 |
n* | 匹配任何包含零个或多个 n 的字符串。 |
n? | 匹配任何包含零个或一个 n 的字符串。 |
9.5 使用 test()/exec()
- test() 方法是一个正则表达式方法。
- test() 方法用于检测一个字符串是否匹配某个模式,如果字符串中含有匹配的文本,则返回 true,否则返回 false。
- 以下实例用于搜索字符串中的字符 “mu”:
- exec()返回一个数组,其中存放匹配的结果。如果未找到匹配,则返回值为 null。
- 以下实例用于搜索字符串中的字母 “mu”:
var str = "ryukimu"
var patt = /mu/.test(str)
console.log(patt); //true
patt = /mu/.exec(str)
console.log(patt); //Array["mu"]
字符串中含有 “mu”,所以该实例输出为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t1lYsIuc-1656422702036)(C:\Users\MU\AppData\Roaming\Typora\typora-user-images\image-20220628150007972.png)]
10.JavaScript 错误
try 语句测试代码块的错误。
catch 语句处理错误。
throw 语句创建自定义错误。
finally 语句在 try 和 catch 语句之后,无论是否有触发异常,该语句都会执行。
10.1 JavaScript try 和 catch
try 语句允许我们定义在执行时进行错误测试的代码块。
catch 语句允许我们定义当 try 代码块发生错误时,所执行的代码块。
JavaScript 语句 try 和 catch 是成对出现的。
try {
... //异常的抛出
} catch(e) {
... //异常的捕获与处理
} finally {
... //结束处理
}
var x = "a"
try {
if(x == "") throw "值是空的";
if(isNaN(x)) throw "值不是一个数字";
x = Number(x);
if(x > 10) throw "太大";
if(x < 5) throw "太小";
}
catch(err) {
console.log("错误: " + err + ".");
}
finally {
console.log("finally");
}
11. JavaScript 变量提升
变量提升这个问题,通常发生在var声明的变量里,就是说当使用var声明一个变量的时候,该变量会被提升到作用域的顶端,但是赋值的部分并不会被提升。如:
console.log(a)
var a = 'bar'
在声明a的语句之前,就可以输出a,值为undefined;这就是变量提升。
为了避免这些问题,通常我们在每个作用域开始前声明这些变量,这也是正常的 JavaScript 解析步骤,易于我们理解
12. JavaScript this 关键字
面向对象语言中 this 表示当前对象的一个引用。
但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。
- 在方法中,this 表示该方法所属的对象。
- 如果单独使用,this 表示全局对象。
- 在函数中,this 表示全局对象。
- 在函数中,在严格模式下,this 是未定义的(undefined)。
- 在事件中,this 表示接收事件的元素。
- 类似 call() 和 apply() 方法可以将 this 引用到任何对象。
12.1 方法中的 this
在对象方法中, this 指向调用它所在方法的对象。
fullName 方法所属的对象就是 person。
var person = {
firstName: "John",
lastName : "Doe",
id : 5566,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
12.2 单独使用 this
单独使用 this,则它指向全局(Global)对象。
在浏览器中,window 就是该全局对象为 [object Window]:
12.3 事件中的 this
<button onclick="this.style.display='none'" >点击消失</button>
12.4 对象方法中绑定
下面实例中,this 是 person 对象,person 对象是函数的所有者:
var person = {
firstName : "John",
lastName : "Doe",
id : 5566,
myFunction : function() {
return this;
}
};
12.5 显式函数绑定
在 JavaScript 中函数也是对象,对象则有方法,apply 和 call 就是函数对象的方法。这两个方法异常强大,他们允许切换函数执行的上下文环境(context),即 this 绑定的对象。
在下面实例中,当我们使用 person2 作为参数来调用 person1.fullName 方法时, this 将指向 person2, 即便它是 person1 的方法:
var person1= {
fullName:function(){
return this.firstName + " " + this.lastName;
}
}
var person2= {
firstName:"ryu",
lastName:"kimu",
}
console.log(person1.fullName.call(person2)); //ryu kimu
13. JavaScript let 和 const
-
ES2015(ES6) 新增加了两个重要的 JavaScript 关键字: let 和 const。
-
let 声明的变量只在 let 命令所在的代码块内有效。
-
const 声明一个只读的常量,一旦声明,常量的值就不能改变。
-
在 ES6 之前,JavaScript 只有两种作用域: 全局变量 与 函数内的局部变量。
13.1 JavaScript 块级作用域(Block Scope)
在 ES6 之前,是没有块级作用域的概念的。
ES6 可以使用 let 关键字来实现块级作用域。
let 声明的变量只在 let 命令所在的代码块 {} 内有效,在 {} 之外不能访问。
{
let x = 1
var y = 2
}
console.log(x); // x is not defined
console.log(y); //2
-
使用了 var 关键字,它声明的变量是全局的,包括循环体内与循环体外。
-
使用 let 关键字, 它声明的变量作用域只在循环体内,循环体外的变量不受影响。
-
在函数体内使用 var 和 let 关键字声明的变量,作用域都是 局部的
-
使用 var 关键字声明的全局作用域变量属于 window 对象,let不属于window对象
13.2 变量提升
- JavaScript 中,var 关键字定义的变量可以在使用后声明,也就是变量可以先使用再声明
- let 关键字定义的变量则不可以在使用后声明,也就是变量需要先声明再使用。
13.3 const 关键字
const
用于声明一个或多个常量,声明时必须进行初始化,且初始化后值不可再修改:
const
定义常量与使用let
定义的变量相似:
- 二者都是块级作用域
- 都不能和它所在作用域内的其他变量或函数拥有相同的名称
两者还有以下两点区别:
const
声明的常量必须初始化,而let
声明的变量不用const
定义常量的值不能通过再赋值修改,也不能再次声明。而let
定义的变量值可以修改。
13.4 const并非真正的常量
- const 的本质: const 定义的变量并非常量,并非不可变,它定义了一个常量引用一个值。
- 使用 const 定义的对象或者数组,其实是可变的。
下面的代码并不会报错:
// 创建常量对象
const car = {type:"Fiat", model:"500", color:"white"};
// 修改属性:
car.color = "red";
// 添加属性
car.owner = "Johnson";
但是不能对常量对象重新赋值:
const car = {type:"Fiat", model:"500", color:"white"};
car = {type:"Volvo", model:"EX60", color:"red"}; // 错误
14.javascript:void(0)
javascript:void(0) 中最关键的是 void 关键字, void 是 JavaScript 中非常重要的关键字,该操作符指定要计算一个表达式但是不返回值。
<a href="javascript:void(0)">单击此处什么也不会发生</a>
href="#"与href="javascript:void(0)"的区别
-
包含了一个位置信息,默认的锚是#top 也就是网页的上端。
-
而javascript:void(0), 仅仅表示一个死链接。
-
在页面很长的时候会使用 # 来定位页面的具体位置,格式为:# + id。
-
如果你要定义一个死链接请使用 javascript:void(0) 。
15. JavaScript 异步编程
异步的概念
异步(Asynchronous, async)是与同步(Synchronous, sync)相对的概念。
传统单线程编程中,程序的运行是同步的(同步不意味着所有步骤同时运行,而是指步骤在一个控制流序列中按顺序执行)。而异步的概念则是不保证同步的概念,也就是说,一个异步过程的执行将不再与原有的序列有顺序关系。
简单来理解就是:同步按你的代码顺序执行,异步不按照代码顺序执行,异步的执行效率更高。
异步就是从主线程发射一个子线程来完成任务。
15.1 什么时候用异步编程
-
用子线程读取一个大文件或者发出一个网络请求等一些比较耗时的操作。
-
因为子线程独立于主线程,所以即使出现阻塞也不会影响主线程的运行。
-
但是子线程有一个局限:一旦发射了以后就会与主线程失去同步,我们无法确定它的结束,如果结束之后需要处理一些事情,比如处理来自服务器的信息,我们是无法将它合并到主线程中去的。
-
为了解决这个问题,JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。
15.2 回调函数
- 回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。
- 这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。
setTimeout(()=>{
console.log(1);
},3000)
console.log(2);
16. JavaScript Promise
实现分三次输出字符串,第一次间隔 1 秒,第二次间隔 4 秒,第三次间隔 3 秒:
setTimeout(function () {
console.log("First");
setTimeout(function () {
console.log("Second");
setTimeout(function () {
console.log("Third");
}, 3000);
}, 4000);
}, 1000);
这段程序实现了这个功能,但是它是用 “函数瀑布” 来实现的。可想而知,在一个复杂的程序当中,用 “函数瀑布” 实现的程序无论是维护还是异常处理都是一件特别繁琐的事情,而且会让缩进格式变得非常冗赘。
接下来学习promise
16.1 构造 Promise
Promise 是一个 ECMAScript 6 提供的类,目的是更加优雅地书写复杂的异步任务。
new Promise(function (resolve, reject) {
// 要做的事情...
});
用 Promise 来实现上面同样的功能
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);
});
16.2 Promise 的使用
Promise 构造函数只有一个参数,是一个函数,这个函数在构造之后会直接被异步运行,所以我们称之为起始函数。起始函数包含两个参数 resolve 和 reject。
当 Promise 被构造时,起始函数会被异步执行:
new Promise(function (resolve, reject) {
console.log("Run");
});
这段程序会直接输出 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");
});
//结果:
//a / b = 0
//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。
16.3 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");
});
这种返回值为一个 Promise 对象的函数称作 Promise 函数,它常常用于开发基于异步操作的库。
可以将这段代码变得更好看:
async function asyncFunc() {
await print(1000, "First");
await print(4000, "Second");
await print(3000, "Third");
}
asyncFunc();
异步函数 async function 中可以使用 await 指令,await 指令后必须跟着一个 Promise,异步函数会在这个 Promise 运行中暂停,直到其运行结束再继续运行。
异步函数实际上原理与 Promise 原生 API 的机制是一模一样的
17. JavaScript 函数
17.1 函数表达式
JavaScript 函数可以通过一个表达式定义。
函数表达式可以存储在变量中:
var x = function (a, b) {return a * b};
在函数表达式存储在变量后,变量也可作为一个函数使用:
var x = function (a, b) {return a * b};
var z = x(4, 3);
以上函数实际上是一个 匿名函数 (函数没有名称)。
函数存储在变量中,不需要函数名称,通常通过变量名来调用。
17.2 Function() 构造函数
函数通过关键字 function 定义。
函数同样可以通过内置的 JavaScript 函数构造器(Function())定义。
var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);
上面实例可以写成:
var myFunction = function (a, b) {return a * b};
var x = myFunction(4, 3);
17.3 函数提升
提升(Hoisting)是 JavaScript 默认将当前作用域提升到前面去的行为。
提升(Hoisting)应用在变量的声明与函数的声明。
因此,函数可以在声明之前调用:
myFunction(5);
function myFunction(y) {
return y * y;
}
使用表达式定义函数时无法提升
17.4 自调用函数
-
函数表达式可以 “自调用”。
-
自调用表达式会自动调用。
-
如果表达式后面紧跟 () ,则会自动调用。
-
不能自调用声明的函数。
-
通过添加括号,来说明它是一个函数表达式:
(()=>{
console.log("自调用函数");
})()
实际上是一个 匿名自我调用的函数 (没有函数名)。
17.5 函数参数
ES6 函数可以自带参数
function myFunction(x, y = 10) {
// y is 10 if not passed or undefined
return x + y;
}
myFunction(0, 2) // 输出 2
myFunction(5); // 输出 15, y 参数的默认值
arguments 对象
-
JavaScript 函数有个内置的对象 arguments 对象。
-
argument 对象包含了函数调用的参数数组。
-
通过这种方式你可以很方便的找到最大的一个参数的值:
x = findMax(1, 123, 500, 115, 44, 88);
function findMax() {
var i, max = arguments[0];
if(arguments.length < 2) return max;
for (i = 0; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
18. JavaScript 闭包
-
JavaScript 闭包。它使得函数拥有私有变量变成可能。
-
闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。
-
直观的说就是形成一个不销毁的栈环境。
-
闭包就是一个函数引用另一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点,不必要的闭包只会增加内存消耗。
-
或者说闭包就是子函数可以使用父函数的局部变量,还有父函数的参数。
-
闭包其实是利用了一个变量退出作用域的时候,暂时没有被销毁,它的值还在,如果后面有变量也叫这个名字,那这个数据会被重新利用起来。你会发现,后面你使用的这个名字一样的变量是有初值的。
<body>
<p>局部变量计数。</p>
<button type="button" onclick="myFunction()">计数!</button>
<p id="demo">0</p>
<script>
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
function myFunction(){
document.getElementById("demo").innerHTML = add();
}
</script>
19. JavaScript 类
类是用于创建对象的模板。
函数声明和类声明之间的一个重要区别在于, 函数声明会提升,类声明不会。
我们使用 class 关键字来创建一个类,类体在一对大括号 {} 中,我们可以在大括号 {} 中定义类成员的位置,如方法或构造函数。
每个类中包含了一个特殊的方法 constructor(),它是类的构造函数,这种方法用于创建和初始化一个由 class 创建的对象。
创建一个类的语法格式如下:
class ClassName {
constructor() { ... }
}
使用类
class site{
constructor(name,url){
this.name = name
this.url = url
}
}
let net = new site("谷歌","https://www.google.com")
console.log(net.name,net.url);
创建对象时会自动调用构造函数方法 constructor()。
19.1 类继承
-
JavaScript 类继承使用 extends 关键字。
-
继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。
-
super() 方法用于调用父类的构造函数。
-
当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类(父类),新建的类称为派生类(子类)。
class get1 {
constructor(firstName,age){
this.firstName = firstName
this.age = age
}
showAge(){
return this.age
}
}
class get2 extends get1{
constructor(firstName,age,lastName){
super(firstName,age)
this.lastName = lastName
}
show(){
return "my name is " + this.firstName + this.lastName+",This year at the age of " + this.showAge()
}
}
let a = new get2("ryu",18,"kimu")
console.log(a.show());
//my name is ryukimu,This year at the age of 18
super() 方法引用父类的构造方法。
通过在构造方法中调用 super() 方法,我们调用了父类的构造方法,这样就可以访问父类的属性和方法。
继承对于代码可复用性很有用。
19.2 getter 和 setter
类中我们可以使用 getter 和 setter 来获取和设置值
getter 和 setter 可以使得我们对属性的操作变的很灵活
类中添加 getter 和 setter 使用的是 get 和 set 关键字
class name{
constructor(firstName){
this.firstName = firstName
}
get _getName(){
return this.firstName
}
set _setName(firstName){
this.firstName=firstName
}
}
let getAndSet = new name("ryu")
console.log(getAndSet._getName); //ryu
getAndSet._setName = "chou"
console.log(getAndSet._getName);
要使用 setter,请使用与设置属性值时相同的语法,虽然 set 是一个方法,但需要不带括号
19.3 JavaScript 静态方法
静态方法是使用 static 关键字修饰的方法,又叫类方法,属于类的,但不属于对象,在实例化对象之前可以通过 类名.方法名 调用静态方法。
静态方法不能在对象上调用,只能在类中调用。
class say {
static sayHi(){return "Hi"}
}
console.log(say.sayHi());
let hi = new say()
console.log(hi.sayHi());
实例对象调用静态方法会报错
20. JavaScript Dom
20.1 DOM - 改变 HTML
20.1.1 改变 HTML 输出流
在 JavaScript 中,document.write() 可用于直接向 HTML 输出流写内容。
document.write("I am superman")
20.1.2 改变 HTML 内容
修改 HTML 内容的最简单的方法是使用 innerHTML 属性。
document.getElementById("demo1").innerHTML = "疾风剑豪"
let demo = document.getElementById("demo2")
demo.innerHTML="亚索"
20.1.3 改变 HTML 属性
如需改变 HTML 元素的属性,请使用这个语法:
document.getElementById(id).attribute=新属性值
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<a href="https://www.baidu.com" id="demo">SITE</a>
<button onclick="changeFunction()">chanage site</button>
<script>
var change = document.getElementById("demo")
function changeFunction(){
this.change.href = "https://www.google.com";
}
</script>
</body>
</html>
20.2 DOM - 改变CSS
如需改变 HTML 元素的样式,请使用这个语法:
document.getElementById(id).style.property=新样式
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<div id="demo" style="background-color: blue;width: 300px;height: 300px;"></div>
<script>
let change = document.getElementById("demo")
change.style.backgroundColor="green"
</script>
</body>
</html>
21. JavaScript高级
21.1 JavaScript prototype(原型对象)
所有的 JavaScript 对象都会从一个 prototype(原型对象)中继承属性和方法。
对象的构造器(constructor):
function person(name,age,sex){
this.name = name
this.age = age
this.sex = sex
}
let p1 = new person("zhangSan",18,"boy")
let p2 = new person("xiaohong",20,"girl")
console.log(p1);
console.log(p2);
//已存在构造器的对象中是不能添加新的属性:
//要添加一个新的属性需要在在构造器函数中添加
prototype 继承
所有的 JavaScript 对象都会从一个 prototype(原型对象)中继承属性和方法:
Date
对象从Date.prototype
继承。Array
对象从Array.prototype
继承。Person
对象从Person.prototype
继承。
所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。
JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
Date
对象, Array
对象, 以及 Person
对象从 Object.prototype
继承。
添加属性和方法
要在所有已经存在的对象添加新的属性或方法,使用 prototype 属性就可以给对象的构造函数添加新的属性:
person.prototype.country = "China"
21.2 JavaScript Number 对象
所有 JavaScript 数字均为 64 位
小数的最大位数是 17,但是浮点运算并不总是 100% 准确:
八进制和十六进制
如果前缀为 0,则 JavaScript 会把数值常量解释为八进制数,如果前缀为 0 和 “x”,则解释为十六进制数。
数字方法
方法 | 描述 |
---|---|
Number.parseFloat() | 将字符串转换成浮点数,和全局方法 parseFloat() 作用一致。 |
Number.parseInt() | 将字符串转换成整型数字,和全局方法 parseInt() 作用一致。 |
Number.isFinite() | 判断传递的参数是否为有限数字。 |
Number.isInteger() | 判断传递的参数是否为整数。 |
Number.isNaN() | 判断传递的参数是否为 isNaN()。 |
Number.isSafeInteger() | 判断传递的参数是否为安全整数。 |
21.3 JavaScript Math(算数) 对象
Math 对象
Math(算数)对象的作用是:执行普通的算数任务。
Math 对象提供多种算数值类型和函数。无需在使用这个对象之前对它进行定义。
var x=Math.PI; //3.141592653589793
var y=Math.sqrt(16); //4
算数方法
Math 对象的 round 方法对一个数进行四舍五入
var x = 5.6
console.log(Math.round(x));
Math 对象的 rondom求一个0-0.999…的随机数,将其*10并对其四舍五入课获得一到十的随机数
console.log(Math.round(Math.random()*10));