JavaScript
JavaScript
1. 初识 JavaScript
- JavaScript 是一种运行在==客户端==的==脚本语言==
- 脚本语言:不需要编译,运行的过程中由 JS 解释器(JS 引擎)逐行来进行解释并执行
- 现在也可以基于 Node.js 技术进行服务器端编程
- 作用
- 表单动态校验(密码强度检测)(==JS最初的目的==,以减轻服务器的压力)
- 网页特效
- 服务端开发(Node.js)
- 桌面程序(Electron)
- App(Cordova)
- 控制硬件-物联网(Ruff)
- 游戏开发(cocos2d-JS)
2. 浏览器执行 JS 过程
- 浏览器分成两部分:渲染引擎和 JS 引擎
- 渲染引擎:用来解析 HTML 和 CSS,俗称内核,比如 chrome 浏览器的 blink,老版本的 webkit
- JS 引擎:也成为 JS 解释器,用来读取网页中的 JavaScript 代码,对其处理后运行,比如 chrome 浏览器的 V8
- 浏览器本身并不会执行 JS 代码,而是通过==内置 JavaScript 引擎(解释器)来执行 JS 代码。JS 引擎执行代码时逐行解释每一句源码(转换成机器语言),然后有计算机去执行==,所以 JavaScript 语言归为脚本语言,会逐行解释执行
3. JavaScript 的组成
- JavaScript 组成
- JavaScript 语法:ECMAScript
- 页面文档对象模型:DOM
- 浏览器对象模型:BOM
- ECMAScript 是由 ECMA 国际(原欧洲计算机制造商协会)进行标准化的一门编程语言,这种语言在万维网上应用广泛,它往往被称为 JavaScript 或 JScript,但实际上后两者是 ECMAScript 语言的实现和扩展。==ECMAScript 规定了 JS 的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套 JS 语法工业标准==
- DOM(Document Object Model) 文档对象模型,是 W3C 组织推荐的处理可拓展标记语言的==标准编程接口==。通过 DOM 提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)
- BOM(Browser Object Model) 是指浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的==对象结构==。通过 BOM 可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等。
4. JavaScript 的书写位置
JS 有三种书写位置,分别为行内、内嵌和外部
1. 行内式的 JS
写在
<body></body>
内,或者写在标签元素元素的内部,比如:<input type="button" value="alert(1)" onclick="alert(1)" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2. 可以将单行或者少量 JS 代码写在 HTML 标签的事件属性中(以 on 开头的属性),如onclick
3. 注意单双引号:在 ==HTML 中推荐使用双引号==,==JS 中推荐使用单引号==
4. 可读性差,在 HTML 编写 JS 大量代码时,不方便阅读
5. 引号易错,引号多层嵌套匹配时,非常容易弄混
6. 特殊情况下使用
### 1. 内嵌式的 JS
1. 写在 \<head\>\</head\> 内
- ```html
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 内嵌式 JS,写在 <head> 里面 -->
<script>
alert(111)
</script>
</head>
可以将多行 JS 代码写道
<script>
标签中内嵌 JS 是学习时常用的方式
3. 外部 JS 文件
实例:
<script src="xxx.js"></script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2. 利于 HTML 页面代码结构化,把大段 JS 代码独立到 HTML 页面之外,既美观,也方便文件级别的复用
3. 引用外部 JS 文件 `<script>` 标签中间不可以写代码
4. 适合于 JS 代码量比较大的情况
---
## 5. JavaScript 的注释
### 1. 单行注释
1. //
### 2. 多行注释
1. /* ... */
2. 快捷键:shift + alt + a
3. 也可以修改 vscode 中多行注释的快捷键,例如为:ctrl + shift + /
---
## 6. JavaScript 常用的输入输出语句
### 1. 常见的输入输出语句
1. | 方法 | 说明 | 归属 |
| ---------------- | ------------------------------ | ------ |
| alert(msg) | 浏览器弹出警示框 | 浏览器 |
| console.log(msg) | 浏览器控制台打印输出信息 | 浏览器 |
| prompt(info) | 浏览器弹出输入框,用户可以输入 | 浏览器 |
- `console.log()` 在 F12 中查看
---
## 7. 变量
### 1. 声明
1. ```javascript
var age;使用
var
关键字声明变量后,计算机会自动为变量分配内存空间在 JS 中,变量==不声明直接赋值使用==是可以的
8. JavaScript 的数据类型(简单)
1. 数据的具体类型
JavaScript 是一种==弱类型或者说是动态语言==。其不用提前声明变量的类型,在程序运行的过程中,类型会被自动确定。
如上所示,由于变量具有动态类型,所以相同的变量可以用作不同的类型,即类型随时可变
var x = 10; // x 从 int 变成了 字符串型 x = 'string'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#### 1. 简单的数据类型
1. | 简单数据类型 | 说明 | 默认值 |
| ------------ | --------------------------------------------------------- | --------- |
| Number | 数字型,包括 int、float 和 double。 | 0 |
| Boolean | | false |
| String | | "" |
| Undefined | `var a;` 声明了变量 a 但是没有赋值,此时 a 就是 undefined | undefined |
| Null | `var a = null;` 声明了变量 a 为空值 | null |
##### 1. 数字型
1. 对于数字型来说,0 开头的数字代表为无符号八进制数,0x 开头的数字代表十六进制
2. 最大值:`Number.MAX_VALUE`
3. 最小值:`Number.MIN_VALUE`
4. 数字型的三个特殊值:
- `Infinity 或者是 Number.MAX_VALUE * 2` 代表无穷大,大于任何值
- `-Infinity 或者是 Number.MIN_VALUE * 2` 代表无穷小,小于任何值
- `NaN` Not a Number,代表一个非数值
5. `isNaN()` 用来判断是否是非数字
##### 2. 字符串型
1. JS 可以用单引号嵌套双引号,反之亦可,总之尽量要==外双内单或者外单内双==
2. | 转义符 | 解释说明 |
| ------ | -------------------- |
| \n | 换行,n 表示 newline |
| \t | tab 表示缩进 |
| \b | 空格,b 表示 blank |
3. 获取字符串的长度:
- `"字符串".length`
4. 字符串的拼接:+
- 字符型与其他类型拼接,其他类型将==自动转换==成字符串型(null + ".." = "null..",其他类型同理),注意与其他语言语言区别
#### 2. 获取变量的数据类型
1. `typeof 变量`,返回数据类型
- `null` 返回的类型为 `object`
- `prompt()` 函数返回的类型为字符串型
#### 3. 数据类型的转换
##### 1. 转换成字符串类型
1. | 方式 | 说明 |
| ----------------- | ---------------------------- |
| ==toString()== | 转成字符串 |
| String() 强制转换 | 转成字符串 |
| 加号拼接字符串 | 和字符串拼接的结果都是字符串 |
##### 2. 转换成数字型
1. | 方式 | 说明 |
| ---------------------- | ------------------------------------------------------------ |
| ==parseInt(string)== | 将 string 类型转成 int 类型,从第一个字符(同时也是数字)开始,取连续的数字,如果开头不是数字,则返回 NaN |
| ==parseFloat(string)== | 将 string 类型转成 float 类型 |
| Number() 强制转换函数 | 将 string 类型转换为==数值==型,如果待转换的变量不是包含纯数字的字符串,则返回 NaN |
| js 隐式转换(- * / ) | 利用算术运算隐式转换为数值型 |
##### 3. 转换成布尔型
1. | 方式 | 说明 |
| --------- | ------------------ |
| Boolean() | 其他类型转成布尔值 |
- 代表==空、否定==的值都会被转换成 false:
- ""、0、NaN、null、undefined
- 其余的值都会转换成 true
---
## 9. 运算符
### 1. 算术运算符
1. 浮点运算时,由于精度问题,从而得出并非想要的结果:
1. ```javascript
console.log(0.1 + 0.2); // 0.30000....结尾有个4
- 同样的,浮点数也不能直接拿来比较
2. 递增和递减运算符
- JavaScript 中有
++
和--
3. 比较运算符
===
和!==
要求值和数据类型都要比较
4. 逻辑运算符
&&
和||
都有短路运算(逻辑中断)
10. 流程控制
1. if分支
- 没啥可说的,和 Java 一样
2. 三元表达式
- 语法结构:
- `条件表达式1 ? 表达式1 : 表达式2
- 为真返回表达式1的值,否则为表达式2的值
3. switch 语句
- 同 java
- case 相比的条件是
===
,即全等于
11. 循环
pass
12. 数组
数组的创建方式:
var arr = new Array(); var arr = [];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2. 一个数组内可以存放多种==不同的类型==元素
3. 数组的访问同其他语言
4. 数组新增元素:
1. 直接修改长度,给 `length` 属性直接赋值
2. 直接对某个下标进行赋值,==可以跨越赋值,中间没有赋值的用 `undefined` 的填充==
---
## 13. 函数
### 1. 定义符
1. `function` 开头,类似于 python 中的 `def`
### 2. 返回值
1. 和 java 一样,返回一个值。
- 由于函数定义时不用指定返回类型,所以返回没有报错
2. 如果没有 `return` ,则默认返回 `undefined`
### 3. arguments
1. `arguments` 是函数的一个==内置对象==,该对象中==存储了传递的所有实参==
2. `arguments` 展示形式是一个伪数组,因此可以遍历,==但是其不是真正的数组==,其类型为 `object`。其具有一下特点:
1. 具有 `length` 属性
2. 按索引方式存储数据
3. 不具有数组的一些方法,比如 `push()` 和 `pop()` 方法
### 4. 函数声明
1. 第一种就是使用 `function` 来定义
2. 使用函数表达式(匿名函数):
1. ```javascript
var fun = function(){...};
fun();
14. 作用域
1. 概念
- 一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的==可用性的代码范围==就是这个名字的==作用域==。
- 其目的在于提高程序的可靠性,同时减少命名冲突
2. 作用域的范围
- es6 之前:
- 全局作用域:整个
<script>
标签,或者是一个单独的 js 文件 - 局部作用域:在函数内部
- 全局作用域:整个
- 变量的作用域:
- 全局变量:在全局作用域中的变量,以及一个特殊情况:
- 在函数内部没有声明,但是直接赋值的变量是全局变量
- 局部变量:在局部作用域中的变量
- 全局变量:在全局作用域中的变量,以及一个特殊情况:
3. 执行效率
- 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源
- 当函数执行结束时自动销毁,比较节约
4. JS 没有块级作用域(ES6 之前),在 ES6 时增加了
在其他语言中,例如 Java 的
if
语句:if(){ ... }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- `if` 之外的代码不能使用内部定义的变量,该作用域即块作用域
### 5. 作用域链
1. 如果函数中还嵌套函数,那么作用域里面又会新增作用域
2. 根据在内部函数可以访问外部函数变量的这种机制,用==链式查找==决定哪些数据能被内部函数访问,就成为作用域链
3. 例如:
- ```javascript
var num = 1;
function f1(){
var num = 2;
function f2(){
console.log(num);
}
f2();
}结果为 2,从内到外,形成一个链子,从内开始,就近原则。这里
num = 1
就是1级链,num = 2
就是2级链。从2级链找,没有找到就向上找,直到找到为止。
15. 预解析
1. 预解析
例子:
console.log(num); var num = 10; // 输出的结果不是报错,而是 undefined 类
1
2
3
4
5
6
7
- ```javascript
fun();
var fun = function(){
console.log(22);
}
// 报错,和单独定义一个函数不同
JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行:
- JavaScript 引擎会把 JS 中==所有的
var
还有function
提升到当前作用域的最前面==。 - 代码执行就是按照书写代码的顺序从上往下执行
- JavaScript 引擎会把 JS 中==所有的
预解析同时也分为==变量预解析(变量提升)==和==函数预解析(函数提升)==
- 就是把所有的变量声明提升到当前作用域最前面,==但是不提升赋值操作==
- 同样的,函数提升就是把所有的函数声明提到当前作用域的最前面,==但是不调用函数==
案例1:
var num = 10; fun(); function fun(){ console.log(num); var num = 20; } // 输出的结果为 undefined
1
2
3
4
5
6
7
8
9
10
11
预解析后的结果如下:
- ```javascript
var num;
function fun(){
var num;
console.log(num);
num = 10;
}
fun();==Java 中不能函数中定义函数,c ++ 中需要定义结构体或类,再在其中定义成员变量,Python 和 JavaScript 里面可以嵌套定义==
在 Java 中,似乎没有这种预解析
16. 对象
1. 对象的创建
// 创建一个空对象 var obj = {}; // 或者 var obj = new Object();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2. ```javascript
// 属性和方法的创建是以键值对的形式表示
var obj = {
name: 'cjy',
age: 20,
...
// 方法
sayHello: function(){
console.log('hello');
...
}
}
// 或者
// 属性和方法的创建以赋值的形式表示
var obj = new Object();
obj.name = 'cjy';
obj.age = 18;
obj.sex = '男';
...
obj.sayHello = function(){
console.log('hello');
...
}
2. 使用对象的方法和属性
==对象名.属性名 或者 对象名[‘属性名’]==
对象名.方法名()
3. 一次性创建多个对象
利用类似函数的方法创建对象,把这个函数成为构造函数(类似 Java中的类
// 构造函数名一般是大驼峰命名法 // 构造函数不需要 return,就可以返回结果,因为其会自动返回 function 构造函数名字(形参1, 形参2...){ this.属性 = 形参1; ... this.方法 = function(){ ... } } var obj = new 构造函数名();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
### 4. 遍历对象属性
1. `for...in` 遍历对象
2. ```javascript
for(var k in obj){
// 输出的是属性/方法名
console.log(k);
// 输出对应属性的值或者方法的具体内容
console.log(obj[k])
}
17. 内置对象
1. 对象分类
- JavaScript 中的对象分为三种:自定义对象、内置对象、浏览器对象。前面两种是 JS 的基础内容,属于 ECMAScript;==第三个浏览器对象是 JS 独有的==。
- 内置对象不用关心实现过程,注重于使用即可
2. 文档查询
- MDN,包括 HTML, CSS 和万维网(HTTP 等),以及 HTML5 应用的 API
3. Math 对象
1. 取最大值函数 max()
Max.max([value1[, value2, value3...]])
- 如果给定的参数中有非数字,则返回
NaN
- 如果没有参数,则结果为
-Infinity
- 如果给定的参数中有非数字,则返回
2. 封装自己的数学对象
var myMath = { PI: 3.141592651, max: function(){ var max = arguments[0]; for(var i = 1; i < arguments.length; i++){ if(argument[i] > max){ max = arguments[i] } } return max; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2. 然后就和普通的调用对象的属性一样即可,本质上就是对象和对象的属性的使用
#### 3. 绝对值和取整
1. `Math.floor()` 向上取整
2. `Math.ceil()` 向下取整
3. `Math.round()` 四舍五入取整,负数的话,.5反而往大的取
4. `Math.abs()` 取绝对值,会有隐式转换
#### 4. 随机数
1. `Math.random()` 函数返回一个浮点,伪随机数在范围[0, 1)
2. `getRandomInt(min, max)` 得到两个数之间的随机整数,左闭右开
### 4. 日期对象
#### 1. 创建一个日期对象
1. ```javascript
var date = new Date();
console.log(date);
// 输出
// Sat Dec 18 2021 18:47:45 GMT+0800 (中国标准时间)
2. 参数常用的写法
数字型
1
2
3
4var date1 = new Date(2021, 12, 18);
console.log(date1);
// 输出
// Tue Jan 18 2022 00:00:00 GMT+0800 (中国标准时间)- 注意,这里显示的月数比输入的月数大一个月
字符串型
1
2
3
4var date2 = new Date('2021-12-18 18:56:36')
console.log(date2);
// 输出
// Sat Dec 18 2021 18:56:36 GMT+0800 (中国标准时间)
3. 日期格式化
方法名 说明 代码 getFullYear() 获取当年 dObj.getFullYear() getMonth() 获取当月(0 - 11),因此数字型的时候多一个月,0 代表 1 月 dObj.getMonth() getDate() 获取当天日期 dObj.getDate() getDay() 获取星期几(周日 0 到 周六 6) dObj.getDay() getHours() 获取当前小时 dObj.getHours() getMinutes() 获取当前分钟 dObj.getMinutes() getSeconds() 获取当前秒钟 dObj.getSeconds() 时分秒格式化
1
2
3
4
5
6
7
8
9
10
11// 格式化返回一个时分秒
function getNowTime(){
var time = new Date();
var hour = time.getHours();
hour = hour < 10 ? '0' + hour : hour;
var minutes = time.getMinutes();
minutes = minutes < 10 ? '0' + minutes : minutes;
var seconds = time.getSeconds();
seconds = seconds < 10 ? '0' + seconds : seconds;
return hour + ':' + minutes + ':' + seconds;
}
4. 时间戳
dObj.valueOf()
或者dObj.getTime()
或者还可以这样写:
1
var date1 = +new Date();
H5 新增的
1
console.log(Date.now());
5. 倒计时
// 倒计时 // 将两个时间转换成时间戳,然后计算差值 function countDown(date){ var nowDate = +new Date(); // var expectedDate = +new Date(date); var expectedDate = date.getTime(); console.log(expectedDate); // 先算出所需要的天数(整数部分),然后用取余取到小数部分,再将其转换成对应的时间,然后再取余,再向下重复步骤 var SecondsSpan = (expectedDate - nowDate) / 1000; var seconds = parseInt(SecondsSpan % 60); seconds = seconds < 10 ? '0' + seconds : seconds var minutes = parseInt(SecondsSpan / 60 % 60); minutes = minutes < 10 ? '0' + minutes : minutes var hours = parseInt(SecondsSpan /60 / 60 % 24); hours = hours < 10 ? '0' + hours : hours var days = parseInt(SecondsSpan / 24 / 60 / 60); days = days < 10 ? '0' + days : days console.log(days + '天' + hours + '时' + minutes + '分' + seconds + '秒'); } var inputDate = prompt('请输入日期'); inputDate = new Date(inputDate); countDown(inputDate);
1
2
3
4
5
6
7
8
9
10
11
12
13
### 5. 数组对象
#### 1.检测是否为数组
1. `instanceof` 其可以用来检测是否为数组
```javascript
var arr = [];
console.log(arr instanceof Array);
// 输出 trueArray.isArray()
也可用用来判断传入的值是否为一个数组(H5 新增的方法)1
2var arr = [];
console.log(Array.isArray(arr));
2. 添加数组元素
push()
在我们数组的==末尾==添加一个或者多个数组元素1
2
3
4
5var arr = [];
arr.push(1, 2, [1, 2, 3]);
console.log(arr.length);
// 长度为3,数组内可以嵌套数组
// push() 的返回值为新的数组的长度unshift()
在数组的开头添加元素,和push()
一样
3. 删除数组元素
pop()
删除数组的最后一个元素,返回被删除的元素shitf()
删除数组的第一个元素,返回被删除的元素splice(pos, len)
从pos
开始(索引),向后删除len
个元素
4. 数组翻转和排序
数组翻转
1
2
3var arr = [1, 2, 3];
arr.reverse();
console.log(arr);数组排序
1
2
3var arr = [1, 5, 2, 4];
arr.sort();
// 冒泡排序,从小到大实际上没有指明比较函数时,默认会把里面的内容转换成 Unicode 位点进行排序,所以需要另写
1
2
3
4
5
6
7var arr1 = [13, 4, 77, 1, 7];
arr1.sort(function(a, b){
// 这个函数表示按照升序的顺序排列
// 降序的话就是 b - a
return a - b;
});
console.log(arr1);具体详见手册
5. 数组索引方法
方法名 说明 返回值 indexOf(‘要查找的内容’, [索引号]) 数组中从索引号向后查找给定元素的第一个索引 如果存在则返回索引号,如果不存在,则返回 -1 lastIndexOf() 在数组中的最后一个的索引 同上
6. 数组转字符串
方法名 说明 返回值 toString() 把数组转换成字符串,生成的字符串用逗号分隔每一项 返回一个字符串 join(‘分割符’) 自定义分割符,把所有元素转换成一个字符串,生成的字符串用分割符分割每一项 var arr = [1, 2, 3]; console.log(arr.toString()); // 结果为 1,2,3
1
2
3
4
5
3. ```javascript
var arr = [1, 2, '3'];
console.log(arr.join('-'));
// 输出 1-2-3
7. 数组的其他方法
方法名 说明 返回值 concat() 连接两个或多个数组,==不影响连接的数组== 返回连接后的新数组 slice(begin, end) 数组从 begin
截取,到end
结束返回截取后的新数组,原数组不会改变 splice(begin, len) 数组从 begin
截取,向后截取len
个元素返回被截取的新数组,==数组被改变==
6. 字符串对象
1. 基本包装类型
基本包装类型就是把简单数据类型包装成为了复杂数据类型,例如:
1
2
3var temp = 'xxx';
// 等价于
var temp = new String('xxx');过程:
- 先创立一个临时变量,假设为
temp
- 然后把这个临时变量赋值给别的变量,这里假设为
str
- 然后销毁这个临时变量
这里用代码表示一下
1
2
3
4
5
6// 以这个为例
var str = 'xxx'
// 过程:
var temp = 'xxx'
var str = temp;
temp = null;- 先创立一个临时变量,假设为
2. 字符串不可变
- 里面的值不可变,内容变了,实际上是所在的地址发生了变化,在内存中开辟了新的空间
3. 根据字符返回位置
- 和数组一样,两个方法
4. 根据位置返回字符
方法名 说明 使用 charAt(index) 返回指定位置的字符(index 字符串的索引号) str.charAt(0) charCodeAt(index) 获取指定位置处字符的 ASCII 码(index 索引号) str.charCodeAt(0) str[index] 获取指定位置处字符 HTML5,IE8+ 支持和 charAt()
等效
5. 字符串的操作方法
方法名 说明 concat(str1, str2 …) 一般用 +
偏多substr(start, length) 从 start 开始(索引号),length 为取的个数 slice(start, end) 从 start 开始,截取到 end 位置,end 那一个取不到 substring(start, end) 和 slice 差不多,但不接受负数 replace(‘被替换的字符串’, ‘替换成的字符串’) 只替换第一次出现的 split(‘分割符’) 字符串转成数组,和 join 的作用相反
18. 数据类型
1. 简单数据类型
- 简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型。
- string, number, boolean, undefined,null这些是简单的数据类型。
- null 为 Object 类型,其为历史遗留问题。
2. 复杂数据类型
- 基本上需要
new
的变量都算复杂数据类型,例如 Object, Array, Date… - 注意 JS 没有堆栈这种概念。
19. Web API
1. Web APIs 和 JS 基础的关联性
- 概述:
- Webn APIs 阶段:
- Web APIs 是 W3C 组织的标准。
- Web APIs 主要学习 DOM 和 BOM。
- Web APIs 是 JS 中独有的部分。
- 主要学习页面交互功能。
2. 概念
1. Web API
- Web API 是浏览器提供的一套操作浏览器功能和页面元素的 API(BOM 和 DOM)。
2. DOM
- DOM 为文档对象模型(Document Object Model),是 W3C 组织推荐的处理 HTML 或者 XML 的标准编程接口,本质是将文档当作一个对象看待,其顶级对象为 document。
- W3C 已经定义了一系列的 DOM 接口,通过这些 DOM 接口可以改变页面的内容、结构和样式。
- DOM 树:
20. DOM
1. 获取元素
1. 常见的获取元素的方法
- 根据 ID 获取。
- 根据标签名获取
- 通过 HTML5 新增方法获取
- 特殊元素获取
2. 通过 ID 获取
- 使用
getElementById()
来获取。 - 语法:
var element = document.getElementById('id')
。 - 返回 element 对象(本质就是 Object),找不到返回为
null
。 - 注意的是,
getElementById(id)
的使用必须在id
所在的标签之后才行。 console.dir(element)
打印元素对象所拥有的属性值。
3. 根据标签名获取
- 使用
getElementsByTagName()
来获取带有指定标签名的对象的集合。 - 语法:
var elements = document.getElementsByTagName('tagName')
- 注意获取的内容是动态的,即页面中元素发生变化时,它获取的结果也可能有所不同。
- 如果页面中,一个对应元素都没有,那么就会返回
[]
,注意不是null
。 - 同样的,如果想获取一个父 element 下的子 element,语法:
父element.getElementByTagName('tagName')
。
4. 使用 HTML5 新增方法(尽量使用这个)
- 即根据类名来获取:
document.getElementsByClassName('className')
。 - 根据指定选择器返回第一个元素对象:
document.querySelector('选择器')
。
选择器有三个:标签,id(#),类选择器(.) - 相应的,有获取全部的:
document.querySelectorAll('选择器')
5. 获取 body 和 html 标签
- 获取 body 元素对象:
var bodyEle = document.body
- 获取 html 元素对象:
var htmlEle = document.documentElement
2. 事件基础
1. 事件一般编写流程
- 代码:
1
2
3
4
5
6
7
8js
// 获取事件源/控件
var obj = document.getElementById('obj');
// 决定事件类型和完成事件处理程序
obj.事件类型 = function(){
...
// 如果这里想对 Obj 进行操作,可以使用 this
}
2. 常见的鼠标事件
鼠标事件 触发条件 onclick 左键点击 onmouseover 鼠标经过触发 onmouseout 鼠标离开出发 onfocus 获得鼠标焦点触发 onblur 失去鼠标焦点时触发 onmousemove 鼠标移动触发 onmouseup 鼠标弹起触发 onmousedown 鼠标按下触发
3. 操作元素
1. 改变元素内容
- 第一种方法:
element.innerText
,从起始位置到终止位置的内容,但它不识别 HTML 标签,同时空格和换行也会去掉。 - 第二种方法:
element.innerHTML
,第一个提到的所有去掉的内容全部保留。 - 以上两个属性是可读的。
2. 修改元素属性
- 获取元素
- 注册事件:在匿名函数中修改某元素的属性
3. 修改表单元素的属性操作
- 利用 DOM 可以操作如下表单的属性:
type、value、checked、selected、disabled
4. 修改样式属性操作
- 行内样式操作:
element.style.属性
用于修改小样式,小修小改。 - 类名样式操作:
element.className = 'newClassName'
这样子就可以把需要较多变化的 CSS 写在类选择器中,然后使用这个类即可。
如果想保留多个类,那就使用多类名选择器:
element.className = 'oldClassName newClassName'
注意不用加.
5. 两种获取属性值的方法
element.属性
element.getAttribute('属性')
;
6. 区别
- 第一种方法获取内置属性值(元素本身自带的属性)。
- 第二种方法主要获得自定义的属性(标准),获得程序员自定义的属性。
7. 两种设置属性值的方法
element.属性 = '值'
element.setAttribute('属性', '值')
8. 区别
- 第一种方法无法设置 className,而第二种可以。
9. 移除属性
element.removeAttribute
10. H5 自定义属性(IE 11 以上支持)
- H5 规定,自定义属性的格式为:
data-自定义属性名 = "属性值"
- 同时,获取自定义元素又有了新的方法:
element.dataset.自定义属性名
或者element.dataset['自定义属性名']
注意,自定义属性名前必须有data-
。
dataset 是一个集合,里面存放了所有以data-
开头的自定义属性。
此外,如果自定义属性名由多个单词组成,例如data-my-attribute
。此时就要使用myAttribute
来获取(大驼峰命名法)。
4. 节点操作
1. 利用节点关系来获取元素
- 通过 DOM 提供的 API 获取元素逻辑性不强,繁琐。所以还可以使用节点的层级关系来获取元素。
- 使用层次关系获取,逻辑性强但兼容性差,不过这个用的多。
2. 节点的概述
- 一般的,一个节点至少拥有 nodeType、nodeName 和 nodeValue 这三个基本属性。
- nodeType:
- 元素节点为 1,元素就是元素节点。
- 属性节点为 2
- 文本节点为 3(包含文字、空格、换行,这里的换行不是
<br>
) - 实际开发中主要操作元素节点。
3. 父子节点
- 父级节点:
node.parentNode
- 子节点:
parentNode.childNodes(标准)
,得到的是集合,注意其包含所有的节点,即包含元素节点和文本节点。
因此如果要用这个来获取元素节点,比较麻烦,一般不提倡使用。 - 子节点 2:
parentNode.children(非标准)
,它是一个只读属性,只返回子元素节点的集合;虽然它是非标准,但是各个浏览器基本支持。
4. 父节点的第一个元素和最后一个元素
- 第一个子节点(包含文本节点):
parentNode.firstChild
。 - 最后一个节点(包含文本节点):
parentNode.lastChild
。 - 第一个元素子节点:
parentNode.firstElementChild
。 - 最后一个元素子节点:
parentNode.lastElementChild
。 - 后两个方法 IE9 以上支持,代替方案:
parentNode.children[...]
5. 兄弟节点
node.nextSibiling
返回下一个兄弟节点(包含文本节点)node.previousSibiling
返回上一个兄弟节点,找不到返回null
,同样包含所有的节点。node.nextElementSibling
返回当前元素下一个兄弟元素节点,找不到则返回null
。- 同样的,有:
node.previousElementSibiling
。
6. 创建节点
document.createElement('tagName')
,动态创建元素节点。- 或者用
element.innerHTML
- 注意,如果用
document.write()
,其直接将内容写入页面的内容流,文档流执行完毕后,会导致页面全部重绘。 - 使用
element.innerHTML
来创建大量元素时,因为本质是字符串拼接,所以效率低于document.createElement('tagName')
。 - 需要注意的是,如果
element.innerHTML
采用数组形式转字符串(拼接join()
),则效率达到最高;但结构复杂且占一个数组空间。
7. 添加节点
node.appendChild(child)
,类似 CSS 里面的after
伪元素。node.insertBefore(child, 指定元素)
,在某个元素前,类似 CSS 的before
伪元素。
8. 删除节点
- 删除父节点的一个子节点
node.removeChild(child)
。 - 补充:阻止链接跳转:
href = "javascript:void(0)"
或者href = "javascript:;"
。
9. 复制节点
node.cloneNode(Boolean boolean)
如果为空,或者为false
,则为浅拷贝,表示只复制标签,但不复制内容。
改为true
就是深拷贝。
21. 事件高级
1. 注册事件
- 传统方式——以
on
开头的事件
特点:注册事件的唯一性,即只能设置一个事件函数。 - 方法监听注册方式(推荐)。
使用addEventListener()
。同一个元素同一个事件可以注册多个监听器。 - 方法监听注册方式(常用):
eventTarget.addEventListener(type, listener, [useCapture])
type:事件类型字符串,比如click
,mouseover
,注意不要加on
listener:事件处理函数
useCapture(可选):boolean 类型,默认false
,表示在事件冒泡阶段调用事件处理函数,为true
表示在事件捕获阶段调用事件处理函数。具体解释见 DOM 事件流。
2. 删除事件(解绑事件)
- 传统删除方式——
element.onxxx = null
- 方法监听删除方式:
eventTarget.removeEventListener(type, listener)
3. DOM 事件流
- 事件流描述的是从页面中接收事件的顺序。
- 事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即 DOM 事件流。
- 传统的注册方式和
attachEvent(deprecated)
只能得到冒泡阶段。 - 一般出现在父子 element 的事件。例如,如果夫 element 的事件和子 element 事件都是捕获阶段发生,那么父 element 的事件将会先于子 element 事件发生。冒泡阶段同理。
- 实际开发中,很少使用事件捕获,一般更关注事件冒泡。
4. 事件对象
监听函数中,如果添加了
event
参数,则这个event
就是一个事件对象。1
element.onclick = function(event){...}
只有出现了事件(
onclick
等等),后面event
形参才会变成事件对象(由系统创建和传递)。event
是事件一系列相关数据的集合,和事件相关。这个
event
名字可以改,改成e
也行。事件对象的常见属性和方法:
事件对象属性方法 说明 e.target 返回触发事件的对象。
注意 this 返回的是绑定事件的对象。e.srcElement 返回触发事件的对象(非标准) e.type 返回事件的类型,比如 click… e.cancelBubble 该属性阻止冒泡(非标准) e.preventDefault() 该方法阻止默认事件(默认行为),标准,比如不让链接跳转。 e.stopPropagation() 阻止冒泡,标准
5. 事件委托(代理、委派)
- 原理:不要给每个子节点单独设置监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点,然后如果要获取那个子节点触发了事件,那就使用
e.target
来获取。
6. 常用的鼠标事件
事件基础中提到的表格。
禁止鼠标右键菜单:
contextmenu
主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单:1
2
3document.addEventListener('contextmenu', function(e){
e.preventDefault();
})禁止鼠标选中
1
2
3document.addEventListener('selectstart', function(e){
e.preventDefault();
})
7. 常用的键盘事件
常见的键盘事件:
键盘事件 触发条件 onkeyup 某个键盘按键被松开时触发 onkeydown 某个键盘按键被按下时触发 onkeypress 某个键盘按键被按下时触发(但它不识别功能键,例如 ctrl shift 等) down 优先于 press 执行。
keyboardEvent(键盘事件对象)中有一个
keyCode
属性,其值为按下的键的 ASCII 值。
需要注意的是,keyup 和 keydown 两个是不区分大小写的。
22. BOM
1. BOM 概述
- BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window。
- BOM 由一系列相关的对象构成,并且每个对象都提供了很多方法和属性。
- BOM 缺乏标准。
- BOM 将浏览器当作对象模型,把浏览器当作一个对象处理,顶级对象为 window。
- BOM 主要学习的是浏览器窗口交互的一些对象。
2. BOM 构成
- BOM 包含 DOM:
- window 对象是浏览器的顶级对象,其:
既是 JS 访问浏览器窗口的一个接口;又是一个全局对象,定义在全剧作用域中的变量、函数都会变成 window 对象的属性和方法。
3. window 常见的事件
1. 窗口加载事件
window.onload = function(){}
或者window.addEventListener("load", function(){})
。
window.onload
表示窗口(页面)加载事件,当文档内容(各节点)完全加载完成时会触发该事件(包括图片、脚本文件、CSS 等),就调用的处理函数。- 有了上述方法,JS 代码就可以写在页面元素的上方。
document.addEventListener('DOMContentLoaded', function(){})
;
DOMContentLoaded 事件触发时,仅当 DOM 加载完成时触发,不包含图片,CSS,flash 等。
2. 调整窗口大小事件
window.onresize = function(){}
和window.addEventListener("resize", function(){})
。
只要浏览器窗口大小发生变化,其就会触发事件。
3. 定时器
window.setTimeout(调用/回调函数, [延迟的毫秒数])
。该定时器在定时器到期后执行函数。(window
可以省略)window.clearTimeout(timeID)
,停止定时器。setInterval(回调函数, [间隔的毫秒数])
,这个方法每隔一段时间重复调用一个函数,注意第一次调用之前还会等一次间隔。- 同理
window.clearIntervel(timeID)
来实现定时器的清除。
4. this
指向
- 一般情况下,
this
指向函数的调用者。
5. JS 执行机制
1. JS 是单线程的
- JS 语言的一大特点就是单线程,因为 JS 这门脚本语言的使命就是处理页面交互中元素的修改,对某个 DOM 元素进行添加和删除操作,不能同时进行。应该先进行添加,后删除。
2. 同步任务与异步任务
同步任务:都在主线程上执行,形成一个执行栈。
异步任务:JS 的异步是通过回调函数实现的。
常见的异步任务:
- 普通事件:click、resize 等
- 资源加载:load、error 等
- 定时器:包括 setInterval、setTimeout 等。
JS 的执行机制:
- 先执行执行栈中的同步任务
- 异步任务(回调函数)放入任务队列中
- 一旦执行栈中的所有同步任务执行完毕,系统就会按照次序读取任务列表中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
- 异步事件一般会交给异步进程处理,当需要执行异步任务时,异步进程就会将异步事件放入任务队列中等待执行。
- 由于主线程不断的重复获取任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环。
6. location
对象
1. location
对象的定义
window
对象提供了一个location
属性用于获取或设置窗体的 URL,并且可以用于解析 URL。因为这个属性返回的是一个对象,所以我们将这个属性也称为location
对象。
2. location
对象常见的属性
对象属性 返回值 href 获取或设置整个 URL host 返回主机/域名 port 端口号,没有就返回空字符串 pathname 返回路径 search 返回参数(开头为 ?) hash 返回片段 # 后的内容(带 # 号),常见于锚点
3. location
对象的方法
方法 返回值 assign() 和 href 一样,重定向(跳转) replace() 替换当前页面,因为不记录历史,所以不能后退页面 reload(boolean) 重新加载页面,相当于刷新按钮或者 f5,如果参数为 true 就强制刷。
7. navigator
对象
navigator
对象包含有关浏览器的信息,它有很多属性,最常用的就是userAgent
,该属性返回 HTTP 头部user-agent
值。
8. history
对象
window
对象提供了一个history
对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的 URL。history 对象方法 作用 back() 后退功能 forward() 前进功能 go(参数) 前进后退功能,1 为前进一个页面,-1 为后退一个页面