JavaScript 编程基础
前置知识:HTML + CSS 基础 课程定位:前端编程入门,为后续 Node.js、Vue、大数据可视化打基础
目录
第一章 初识JavaScript
1.1 什么是JavaScript
JavaScript 是一种基于对象和事件驱动的客户端脚本语言,主要用于开发交互式网页。
主要应用领域:
- 表单动态校验
- 网页特效与动画
- 前端开发(Web + APP + 小程序)
- 服务端开发(Node.js)
- 桌面程序(Electron)
- 移动App(Cordova)
- 物联网(Ruff)
- 游戏开发(cocos2d-js)
- 数据库操作(MongoDB)
1.2 网页三要素与浏览器内核
网页三大组成部分:
- HTML:页面结构与内容
- CSS:页面样式与布局
- JavaScript:页面交互与行为
浏览器内核组成:
- 渲染引擎(排版引擎):解析 HTML 与 CSS,如 Chrome 的 Blink
- JS引擎:JavaScript 解释器,如 Chrome 的 V8 引擎
💡 JS代码执行特点:逐行解释执行,不需要预先编译。
1.3 JavaScript的特点
| 特点 | 说明 |
|---|---|
| 解释性脚本语言 | 不需要编译,逐行解释执行(对比:Java、C++是编译语言) |
| 跨平台 | 不依赖操作系统,只要有浏览器支持即可运行 |
| 支持面向对象 | 基于对象的编程,也支持函数式编程 |
| 弱类型 | 变量不需要声明类型,赋值时自动确定类型 |
| 简单性 | 语法相对简单,入门门槛低 |
1.4 JavaScript的组成
JavaScript 由三大部分组成:
JavaScript
├── ECMAScript(核心语法) —— 基本语法、数据类型、流程控制、函数、对象等
├── DOM(文档对象模型) —— 操作网页元素的接口
└── BOM(浏览器对象模型) —— 操作浏览器窗口的接口常用JS框架: React.js、Angular.js、Vue.js(尤雨溪)
1.5 常用开发工具
- VS Code(推荐):微软出品,轻量强大,插件丰富
- HBuilder:国产,前端开发友好
- Sublime Text:轻量快速
- DreamWeaver:可视化编辑
- WebStorm:JetBrains出品,功能强大
VS Code 推荐插件:
- Chinese (Simplified) —— 中文语言包
- Open in Browser —— 浏览器打开
1.6 JS代码的三种书写位置
(1)行内式
写在 HTML 标签的事件属性中(如 onclick、oninput、onmousemove)
<input type="button" value="提交" onclick="alert('你提交成功!')" />
<input type="text" onmousemove="console.log('鼠标移动了')" />(2)内嵌式(嵌入式)
将 JS 代码写在 <script> 标签中,放在 <head> 或 <body> 里
<script>
var a = 11;
var b = 22;
var c = a + b;
console.log(c);
</script>(3)外部式(外链式)
将 JS 代码写在单独的 .js 文件中,通过 script 标签引入
<script src="js/test.js"></script>⚠️ 注意:引入外部JS的script标签中间不能再写代码。
1.7 语法规则与注释
语法规则:
- JS 严格区分大小写
- 对空格、换行、缩进不敏感
- 每行结束的分号
;可以省略,但推荐加上
注释:
// 单行注释,快捷键:ctrl + /
/*
多行注释
快捷键:ctrl + shift + /
*/1.8 输入输出语句
| 语句 | 作用 | 示例 |
|---|---|---|
alert('信息') | 弹出警告框 | alert('这是警告框') |
console.log('信息') | 控制台输出(调试用) | console.log('调试信息') |
prompt('提示信息') | 弹出输入框,返回用户输入 | var age = prompt('请输入年龄') |
控制台使用: 按 F12 打开开发者工具 → Console(控制台)面板
1.9 变量
变量是内存中的一块空间,用于存储数据。
声明与赋值
// 声明变量
var age;
// 赋值
age = 18;
// 声明同时赋值(推荐)
var age = 18;⚠️ 可以不声明直接赋值,但不规范,不推荐。
变量命名规范
- 由**字母、数字、下划线、美元符号$**组成
- 严格区分大小写
- 不能以数字开头
- 不能是关键字、保留字
- 关键字:JS中已经被使用的单词(如 break、if、for 等)
- 保留字:未来可能成为关键字的单词
- 合理命名,"见其名知其意"
- 三种命名法:
// 小驼峰命名法(推荐,变量/函数用)
var mySchoolAddress = '重庆涪陵';
// 大驼峰命名法(类名/构造函数用)
var MySchoolAddress = '重庆涪陵';
// 下划线命名法
var my_school_address = '重庆涪陵';第二章 JS基础语法
2.1 数据类型
JS 是弱类型语言,变量不需要提前声明数据类型。
数据类型分类:
数据类型
├── 基本数据类型(值类型)
│ ├── Number 数值型
│ ├── String 字符串型
│ ├── Boolean 布尔型
│ ├── Null 空型
│ └── Undefined 未定义型
└── 引用数据类型(复杂类型)
└── Object 对象(1)Number 数值型
包括整数、浮点数(小数)、NaN、Infinity
// 整数
var age = 18;
// 浮点数
var price = 99.99;
// 最大值/最小值
var max = Number.MAX_VALUE;
var min = Number.MIN_VALUE;
// 无穷大/无穷小
var inf = Infinity;
var ninf = -Infinity;
// NaN:非数值(Not a Number)
// isNaN():判断是否为非数字,true=非数字,false=数字
console.log(isNaN('abcdefg')); // true(2)String 字符串型
用单引号 '' 或双引号 "" 包裹。
var str1 = '这是一个字符串';
var str2 = "这也是一个字符串";转义字符:
| 转义符 | 含义 |
|---|---|
\n | 换行 |
\' | 单引号 |
\" | 双引号 |
\\ | 反斜杠 |
字符串长度: length 属性
var str = 'hello world';
console.log(str.length); // 11访问字符串字符: 通过索引 [index],索引从0开始,超出返回 undefined
var str = '这是一个字符串';
console.log(str[0]); // '这'
console.log(str[100]); // undefined字符串拼接: 使用 + 号
var first = '520';
var second = '10';
var result = first + second; // '52010'(3)Boolean 布尔型
只有两个值:true(真)和 false(假)
(4)Null 空型
表示空值,专门用来表示一个空对象引用。
var a = null;
if (a === null) {
alert('这是null型');
}(5)Undefined 未定义型
声明了变量但没有赋值,默认值就是 undefined。
var test; // 声明但未赋值
alert(test); // undefined检测数据类型:typeof
var result = true;
console.log(typeof result); // 'boolean'2.2 数据类型转换
(1)转换为字符串类型
| 方法 | 说明 | 示例 |
|---|---|---|
+ "" | 拼接字符串(最常用) | var str = num + "" |
toString() | 转字符串 | var str = num.toString() |
String() | 强制转换 | var str = String(num) |
var num = 123;
var str1 = num + ''; // '123'
var str2 = num.toString(); // '123'
var str3 = String(num); // '123'(2)转换为数字类型
| 方法 | 说明 | 示例 |
|---|---|---|
parseInt() | 转整数 | parseInt('123.99') → 123 |
parseFloat() | 转浮点数 | parseFloat('123.99') → 123.99 |
Number() | 强制转换 | Number('123') → 123 |
| 算术隐式转换 | - * / 运算时自动转 | '12' - 1 → 11 |
var str = '111.000';
parseInt(str); // 111
parseFloat(str); // 111(3)转换为布尔型
Boolean() 函数转换,以下值会转为 false,其余都转 true:
0''(空字符串)nullundefinedNaN
2.3 运算符
(1)算术运算符
+ 加 - 减 * 乘 / 除 % 取模(取余数)(2)递增递减运算符
++ 自增,-- 自减
var i = 10;
i++; // 等同于 i = i + 1
i--; // 等同于 i = i - 1前置与后置的区别:
x++:返回计算前的值,然后再加1++x:先加1,然后返回计算后的值
var a = 10;
console.log(a++); // 10(先返回后加)
console.log(a); // 11
var b = 10;
console.log(++b); // 11(先加后返回)(3)比较运算符
结果为布尔值(true/false)
> 大于 < 小于 >= 大于等于 <= 小于等于
== 等于(只比较值,自动类型转换)
!= 不等于
=== 全等(值和类型都相等才为true)
!== 不全等console.log('' == 0); // true(自动类型转换)
console.log('' === 0); // false(类型不同)💡 推荐使用
===和!==,更严谨。
(4)逻辑运算符
结果为布尔值
| 运算符 | 含义 | 规则 |
|---|---|---|
&& | 与(和) | 两边都为true,结果才为true |
|| | 或 | 有一边为true,结果就为true |
! | 非(取反) | true变false,false变true |
(5)赋值运算符
= 赋值
+= x += y 等同于 x = x + y
-= x -= y 等同于 x = x - y
*= x *= y 等同于 x = x * y
/= x /= y 等同于 x = x / y
%= x %= y 等同于 x = x % y(6)三元运算符
条件表达式 ? 表达式1 : 表达式2条件为true执行表达式1,为false执行表达式2。
var score = 85;
var result = score >= 60 ? '及格' : '不及格';(7)运算符优先级
从高到低: 小括号 > 算术运算符 > 比较运算符 > 逻辑运算符 > 赋值运算符
2.4 流程控制
三种基本结构:顺序结构、分支结构、循环结构
(1)顺序结构
默认执行方式,代码从上到下逐行执行。
(2)分支结构
单分支 if:
if (条件表达式) {
// 条件为true时执行
}双分支 if...else:
if (条件表达式) {
// 条件为true时执行
} else {
// 条件为false时执行
}多分支 if...else if...else:
if (条件1) {
// 条件1为true
} else if (条件2) {
// 条件2为true
} else if (条件3) {
// 条件3为true
} else {
// 都不满足
}switch 语句:
switch (表达式) {
case 值1:
// 代码段1
break;
case 值2:
// 代码段2
break;
default:
// 都不匹配时执行
}⚠️ 注意:break 不能少,否则会发生 case 穿透。
(3)循环结构
for 循环: 适合循环次数已知的情况
for (初始化变量; 循环条件; 操作表达式) {
// 循环体
}
// 示例:打印1~100
for (var i = 1; i <= 100; i++) {
console.log(i);
}while 循环: 先判断条件再执行,适合次数未知
while (条件表达式) {
// 循环体
}do...while 循环: 无条件先执行一次,再判断条件
do {
// 循环体
} while (条件表达式);(4)continue 与 break
- continue:跳过本次循环,继续下一次
- break:终止整个循环
// 多层循环时,默认只跳过/终止最近一层
// 如需操作外层循环,需要加标签
outer: for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
if (j === 2) {
continue outer; // 跳过外层循环的本次
}
}
}2.5 数组
数组是值的有序集合。
特点:
- JS是弱类型,同一数组可存放多种类型元素
- 长度可动态调整
创建数组
// 方式1:字面量(推荐)
var arr1 = [];
var color = ['red', 'green', 'blue', 1, true, null];
// 方式2:new Array()
var arr2 = new Array();访问数组元素
通过数字索引访问,索引从0开始
var color = ['red', 'green', 'blue'];
console.log(color[0]); // 'red'
console.log(color[2]); // 'blue'数组长度
var arr = [1, 2, 3, 4, 5];
console.log(arr.length); // 5遍历数组
// 方式1:for循环(最常用)
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
// 方式2:for...in
for (var index in arr) {
console.log(arr[index]);
}
// 方式3:for...of(ES6)
for (var item of arr) {
console.log(item);
}修改数组
// 修改长度
arr.length = 10;
// 新增/修改元素(通过索引)
arr[0] = '新值';
arr[100] = '末尾新增'; // 中间会有空位二维数组
// 创建
var arr2d = [[1, 2], [3, 4], [5, 6]];
// 访问
console.log(arr2d[0][1]); // 2
// 遍历:双层for循环
for (var i = 0; i < arr2d.length; i++) {
for (var j = 0; j < arr2d[i].length; j++) {
console.log(arr2d[i][j]);
}
}2.6 函数
函数就是一段可重复使用的代码块,实现代码复用。
函数的声明与调用
// 声明函数
function 函数名(参数1, 参数2, ...) {
// 函数体
return 返回值;
}
// 调用函数
函数名(参数1, 参数2, ...);// 示例
function sayHi() {
console.log('hi');
}
sayHi();函数参数
- 形参:函数声明时的参数(占位符)
- 实参:函数调用时传入的参数(实际值)
// 形参:num1, num2
function getSum(num1, num2) {
var sum = 0;
for (var i = num1; i <= num2; i++) {
sum += i;
}
return sum;
}
// 实参:1, 100
getSum(1, 100);参数数量不匹配:
- 形参 < 实参:多余的实参会被忽略
- 形参 > 实参:多余的形参值为 undefined
返回值 return
function add(a, b) {
return a + b; // 终止函数并返回结果
}💡 如果函数没有指定 return,默认返回
undefinedreturn 可以提前终止函数执行
arguments 对象
接收所有实参,是一个伪数组(类数组对象)
function sum() {
var total = 0;
for (var i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
sum(1, 2, 3, 4, 5); // 15匿名函数
没有函数名的函数
// 立即执行函数(IIFE)
(function (a, b) {
console.log(a + b);
})(1, 2);函数表达式
将匿名函数赋值给变量,通过变量调用
var sayHi = function () {
console.log('hello world');
};
sayHi(); // 调用⚠️ 函数表达式必须写在调用之前。
回调函数
将函数作为参数传递给另一个函数
function calc(num1, num2, fn) {
return fn(num1, num2);
}
// 使用
calc(10, 20, function (a, b) {
return a + b;
});递归
函数自己调用自己
// 计算阶乘
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1);
}2.7 作用域与闭包
作用域
变量可访问的范围。
全局变量:
- 不在函数内声明的变量,或函数内省略 var 声明的变量
- 在整个页面生效
- 页面关闭时才销毁,比较占内存
局部变量:
- 函数内用 var 声明的变量
- 只能在当前函数内使用
- 函数执行完就销毁,节省内存
块级变量(ES6 let):
- 用 let 声明,仅在
{}内有效(if、for、while 等)
作用域链
由内向外查找变量: 当前函数内查找 → 上一级函数查找 → ... → 全局作用域
函数内部可以访问外部的变量,但外部不能访问函数内部的变量。
闭包
有权访问另一个函数作用域内变量的函数。
两个作用:
- 函数外部读取函数内部的变量
- 让变量常驻内存(不会被垃圾回收)
function outer() {
var count = 0;
return function () {
count++;
return count;
};
}
var counter = outer();
counter(); // 1
counter(); // 2第三章 对象编程
3.1 对象概述
面向对象编程(OOP):万物皆对象。
对象是一种数据类型,由属性和方法组成:
- 属性:事物的特征,通过
对象.属性访问 - 方法:事物的行为,通过
对象.方法名()访问
3.2 创建自定义对象的三种方式
方式1:字面量创建(最常用)
var car = {
color: 'red',
brand: 'BMW',
price: 300000,
run: function () {
console.log('车在跑');
}
};特点:
- 用大括号
{}包裹 - 每个成员是键值对
key: value - 成员之间用逗号分隔
方式2:new Object() 创建
var car = new Object();
car.color = 'red';
car.brand = 'BMW';
car.run = function () {
console.log('车在跑');
};方式3:构造函数创建(批量创建对象)
构造函数名首字母大写,使用 this 指代当前对象。
// 构造函数(模板)
function Car(color, brand) {
this.color = color;
this.brand = brand;
this.run = function () {
console.log(this.brand + '在跑');
};
}
// 创建实例
var car1 = new Car('red', 'BMW');
var car2 = new Car('blue', 'Audi');访问对象成员
// 访问属性
car.color; // 点语法(推荐)
car['color']; // 方括号语法(属性名含特殊字符时用)
// 访问方法
car.run();
car['run']();this 关键字
代表当前对象,谁调用就指向谁。
静态成员
不需要创建实例对象就能使用的属性和方法。
function Car() {}
Car.wheelCount = 4; // 静态属性
console.log(Car.wheelCount); // 直接通过构造函数访问3.3 遍历对象与成员判断
遍历对象:for...in
var person = {
name: '张三',
age: 18,
sayHi: function () {
console.log('hi');
}
};
for (var key in person) {
console.log(key); // 属性名/方法名
console.log(person[key]); // 属性值/方法
}判断成员是否存在:in 运算符
console.log('name' in person); // true
console.log('gender' in person); // false3.4 JSON数据格式
JSON(JavaScript Object Notation):JavaScript 对象标记法。
- 独立于语言,适用于多种编程语言
- 便于阅读和书写的数据交换格式
- 主要用于存储和传输数据
JSON 对象格式:
{
"name": "张三",
"age": 18,
"hobbies": ["读书", "运动"]
}⚠️ 注意:key 必须使用双引号,value 如果是字符串也用双引号。
3.5 内置对象
JS 自带的、直接使用的对象,不需要自己编写。
📖 推荐查阅文档:MDN 官方文档 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript
(1)Math 对象
数学相关运算,不需要实例化(不是构造函数)。
| 语法 | 作用 | 示例 |
|---|---|---|
Math.round(n) | 四舍五入到整数 | Math.round(4.5) → 5 |
Math.floor(n) | 向下取整 | Math.floor(4.9) → 4 |
Math.ceil(n) | 向上取整 | Math.ceil(4.1) → 5 |
Math.abs(n) | 绝对值 | Math.abs(-5) → 5 |
Math.random() | 0~1之间的随机浮点数 | [0.0, 1.0) |
Math.pow(x, y) | x的y次幂 | Math.pow(10, 2) → 100 |
Math.sqrt(n) | 开平方 | Math.sqrt(9) → 3 |
Math.max(a,b,...) | 最大值 | |
Math.min(a,b,...) | 最小值 |
生成指定范围随机整数:
// min ~ max 之间的随机整数(包含两端)
Math.floor(Math.random() * (max - min + 1) + min);
// 1 ~ max 之间的随机整数
Math.floor(Math.random() * max + 1);(2)Date 日期对象
需要实例化:new Date()
var date = new Date(); // 当前时间常用方法:
| 方法 | 说明 |
|---|---|
getFullYear() | 获取年份 |
getMonth() | 获取月份(0-11,注意+1) |
getDate() | 获取日期 |
getDay() | 获取星期几(0-6,0是周日) |
getHours() | 获取小时 |
getMinutes() | 获取分钟 |
getSeconds() | 获取秒数 |
getTime() | 获取时间戳(毫秒) |
valueOf() | 获取时间戳(毫秒) |
时间戳: 从1970-01-01 00:00:00到当前时间的毫秒数 1秒 = 1000毫秒
(3)Array 数组对象
数组类型检测:
var arr = [1, 2, 3];
arr instanceof Array; // true(方式1)
Array.isArray(arr); // true(方式2,推荐)添加/删除元素:
| 方法 | 作用 | 返回值 |
|---|---|---|
push(元素) | 末尾添加元素 | 新数组长度 |
unshift(元素) | 开头添加元素 | 新数组长度 |
pop() | 删除末尾一个元素 | 被删除的元素 |
shift() | 删除开头一个元素 | 被删除的元素 |
数组排序:
arr.reverse(); // 颠倒顺序
arr.sort(); // 排序(默认按字符编码,数字排序需传函数)
// 数字升序排序
arr.sort(function (a, b) {
return a - b;
});数组索引:
| 方法 | 作用 |
|---|---|
indexOf(元素) | 查找第一个匹配的索引,找不到返回-1 |
lastIndexOf(元素) | 查找最后一个匹配的索引,找不到返回-1 |
数组转字符串:
arr.toString(); // 用逗号连接
arr.join('分隔符'); // 用指定分隔符连接其他方法:
| 方法 | 作用 |
|---|---|
fill(值, start, end) | 用固定值填充数组 |
splice(开始, 删除个数, 插入元素) | 删除/插入/替换元素 |
slice(begin, end) | 截取数组(不改变原数组) |
concat(arr2, ...) | 合并多个数组(不改变原数组) |
遍历数组方法(6个):
// forEach:遍历每个元素,执行操作(无返回值)
arr.forEach(function (value, index, array) {
console.log(value);
});
// map:遍历每个元素,返回新数组
var newArr = arr.map(function (value) {
return value * 2;
});
// filter:过滤,返回符合条件的新数组
var result = arr.filter(function (value) {
return value > 10;
});
// reduce:累计计算
var sum = arr.reduce(function (prev, curr) {
return prev + curr;
}, 0);
// some:是否有至少一个满足条件(返回布尔值)
arr.some(function (value) {
return value > 10;
});
// every:是否全部满足条件(返回布尔值)
arr.every(function (value) {
return value > 10;
});(4)String 字符串对象
创建:
var str1 = new String('hello'); // 方式1
var str2 = 'hello'; // 方式2(推荐)属性:
length:字符串长度
根据字符找位置:
| 方法 | 作用 |
|---|---|
indexOf(value, start) | 从开头查找首次出现的位置,找不到返回-1 |
lastIndexOf(value, start) | 从末尾查找最后出现的位置,找不到返回-1 |
根据位置找字符:
| 方法 | 作用 |
|---|---|
str[index] | 方括号索引访问 |
str.charAt(index) | 获取指定位置的字符 |
str.charCodeAt(index) | 获取指定位置字符的Unicode编码 |
其他常用方法:
| 方法 | 作用 |
|---|---|
concat(str2, ...) | 连接多个字符串 |
toLowerCase() | 转小写 |
toUpperCase() | 转大写 |
split(分隔符) | 按分隔符分割成数组 |
replace(旧, 新) | 替换字符串 |
trim() | 删除前后空白字符 |
trimStart() | 删除开头空白 |
trimEnd() | 删除末尾空白 |
substring(start, end) | 截取字符串 |
substr(start, length) | 截取指定长度 |
3.6 值类型与引用类型
| 类型 | 包含 | 赋值方式 | 特点 |
|---|---|---|---|
| 值类型(基本类型) | Number、String、Boolean、Null、Undefined | 赋值传值 | 复制一份,互不影响 |
| 引用类型 | Object、Array、Function等 | 赋值传址 | 传递内存地址,修改会影响原变量 |
// 值类型
var a = 10;
var b = a;
a = 20;
console.log(b); // 10(不受影响)
// 引用类型
var arr1 = [1, 2, 3];
var arr2 = arr1;
arr1.push(4);
console.log(arr2); // [1,2,3,4](被影响了)垃圾回收机制: JS 有自动垃圾回收机制,会自动释放不再使用的内存。
3.7 正则表达式
正则表达式是描述字符串结构的语法规则,用于匹配字符串中的字符模式。
创建正则表达式
// 方式1:字面量(推荐)
var reg = /表达式/附加参数;
// 方式2:构造函数
var reg = new RegExp('表达式', '附加参数');附加参数:
g:全局匹配i:忽略大小写
正则操作方法
| 方法 | 作用 | 返回值 |
|---|---|---|
test() | 检测是否匹配 | true / false |
exec() | 检索匹配 | 结果数组 / null |
compile() | 编译正则 |
正则表达式语法
方括号(字符类):
| 表达式 | 描述 |
|---|---|
[abc] | 匹配a、b、c中的任意1个字符 |
[^abc] | 匹配不在a、b、c中的任意1个字符 |
[0-9] | 匹配0到9的任意1个数字 |
[a-z] | 匹配任意1个小写字母 |
[A-Z] | 匹配任意1个大写字母 |
[a-zA-Z] | 匹配任意1个字母 |
量词:
| 符号 | 描述 | 示例 |
|---|---|---|
* | 前面的字符出现0次或多次 | /a*b/ 可匹配 b、ab、aaab |
+ | 前面的字符出现1次或多次 | /a+b/ 可匹配 ab、aaab |
? | 前面的字符出现0次或1次 | /a?b/ 可匹配 b、ab |
{n} | 前面的字符连续出现n次 | /a{3}/ 相当于 aaa |
{n,} | 前面的字符连续出现至少n次 | /a{3,}/ |
{n,m} | 前面的字符连续出现n到m次 | /a{1,3}/ |
常用符号:
| 符号 | 描述 |
|---|---|
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
\d | 匹配一个数字字符,等价于 [0-9] |
\D | 匹配非数字字符,等价于 [^0-9] |
\w | 匹配数字、下划线或字母,等价于 [A-Za-z0-9_] |
\W | 匹配非单字字符 |
\s | 匹配任意空白字符 |
\S | 匹配任意非空白字符 |
. | 匹配除换行符外的任意字符 |
| | 或 |
常用正则示例:
// 用户名:英文字母和数字组成的4-16位字符,以字母开头
var userReg = /^[a-zA-Z][a-zA-Z0-9]{3,15}$/;
// 邮箱验证
var emailReg = /^\w+@\w+\.(com|cn)$/;
// 手机号验证
var phoneReg = /^1[3-9]\d{9}$/;第四章 BOM与DOM
4.1 API与Web API
API(Application Programming Interface):应用程序接口。 实现某种功能,开发人员无须访问源码、无须理解内部实现机制,只需要知道怎么用即可。
Web API: 操作浏览器和网页的接口集合。
- DOM:文档对象模型,操作网页元素
- BOM:浏览器对象模型,操作浏览器窗口
4.2 DOM概述
DOM(Document Object Model):文档对象模型。
操作网页元素的标准接口,可以获取元素、修改属性、操作样式、绑定事件等。
DOM树: 将HTML文档看成树结构。
document(文档)
└── html
├── head
│ └── title
└── body
├── div
└── p节点(node): 网页中的所有内容在DOM树中都是节点。
- 元素节点(标签)
- 属性节点
- 文本节点
- 注释节点
4.3 获取页面元素
(1)通过 ID 获取
var box = document.getElementById('box');返回单个元素对象。
(2)通过标签名获取
var lis = document.getElementsByTagName('li');返回伪数组(HTMLCollection),用索引访问单个元素。
(3)通过 name 获取
var fruits = document.getElementsByName('fruit');返回伪数组,常用于表单元素。
(4)通过类名获取(HTML5)
var items = document.getElementsByClassName('item');返回伪数组。
(5)querySelector(HTML5,推荐)
返回指定CSS选择器匹配的第一个元素。
document.querySelector('#box'); // ID选择器
document.querySelector('li'); // 标签选择器
document.querySelector('.item'); // 类选择器
document.querySelector('div > p'); // 后代选择器(6)querySelectorAll(HTML5,推荐)
返回指定CSS选择器匹配的所有元素(伪数组)。
document.querySelectorAll('.item');document 对象常用属性
document.title // 页面标题
document.body // body元素
document.documentElement // html元素
document.forms // 所有表单
document.images // 所有图片4.4 操作元素内容
| 属性 | 说明 | 特点 |
|---|---|---|
innerHTML | 获取/设置元素内容 | 保留标签、空格、换行 |
innerText | 获取/设置元素文本 | 去掉标签,去掉空格换行 |
textContent | 获取/设置元素文本 | 去掉标签,保留空格换行 |
var box = document.getElementById('box');
// 获取
console.log(box.innerHTML);
// 设置
box.innerHTML = '<h1>新标题</h1>';4.5 操作元素属性
// 获取属性
元素.属性名
// 修改属性
元素.属性名 = '属性值';常用属性: src、href、title、alt、id、className 等
var img = document.querySelector('img');
img.src = 'images/2.jpg';
img.title = '这是一张图片';4.6 操作元素样式
方式1:操作 style 属性
元素.style.样式名 = '值';var box = document.getElementById('box');
box.style.backgroundColor = 'red';
box.style.fontSize = '20px';
box.style.display = 'none'; // 隐藏元素⚠️ 注意:JS中样式名用驼峰命名,如
backgroundColor、fontSize
方式2:操作 className 属性
元素.className = '类名';通过修改类名,批量改变样式(推荐用于样式较多的情况)。
4.7 自定义属性与data-*
获取属性
// 通用方式(推荐,适用于所有属性)
element.getAttribute('属性名');
// 内置属性也可以用点语法
element.id;设置属性
// 通用方式(推荐)
element.setAttribute('属性名', '属性值');
// 内置属性也可以用点语法
element.id = 'newId';移除属性
element.removeAttribute('属性名');H5 自定义属性 data-*
H5 规定用 data-属性名 的方式设置自定义属性。
// 设置
element.setAttribute('data-index', '1');
element.dataset.index = '1'; // 另一种方式
// 获取
element.getAttribute('data-index');
element.dataset.index;4.8 DOM节点操作
节点层级关系
- 根节点:
document - 父节点:
parentNode - 子节点:
children - 兄弟节点:
nextElementSibling、previousElementSibling
获取父节点
元素.parentNode获取子节点
// 推荐:获取所有子元素节点(伪数组)
元素.children
// 第一个子元素
元素.children[0]
// 最后一个子元素
元素.children[元素.children.length - 1]获取兄弟节点
元素.nextElementSibling // 下一个兄弟元素
元素.previousElementSibling // 上一个兄弟元素创建节点
document.createElement('标签名');添加节点
// 在末尾添加
父元素.appendChild(子节点);
// 在指定节点前添加
父元素.insertBefore(新节点, 指定节点);删除节点
父元素.removeChild(子节点);
// 删除自己
node.parentNode.removeChild(node);复制节点
元素.cloneNode(true); // 深拷贝,复制内容
元素.cloneNode(false); // 浅拷贝,只复制标签4.9 事件基础
事件: 可以被JS检测到的行为,是一种"触发-响应"机制。
事件三要素
- 事件源:触发事件的元素(谁触发了事件)
- 事件类型:什么事件(如 click、mouseover)
- 事件处理程序:触发后执行的代码(做什么)
常用事件类型
| 事件名 | 触发时机 |
|---|---|
onclick | 鼠标单击 |
onfocus | 获得焦点 |
onblur | 失去焦点 |
onmouseover | 鼠标经过 |
onmouseout | 鼠标离开 |
onmousemove | 鼠标移动 |
onmousedown | 鼠标按下 |
onmouseup | 鼠标抬起 |
onkeydown | 键盘按下 |
onkeypress | 键盘按下(不识别功能键) |
onkeyup | 键盘松开 |
onload | 页面加载完成 |
onchange | 内容改变 |
onselect | 文本被选中 |
onsubmit | 表单提交 |
传统绑定事件方式
元素.onclick = function () {
// 事件处理代码
};⚠️ 传统方式:同一个元素同一个事件只能绑定一个处理函数,后绑定的会覆盖前面的。
排他思想
排除掉其他的(包括自己),然后给自己设置效果。
var btns = document.querySelectorAll('button');
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function () {
// 1. 先把所有按钮的样式去掉
for (var j = 0; j < btns.length; j++) {
btns[j].style.backgroundColor = '';
}
// 2. 给当前点击的按钮加样式
this.style.backgroundColor = 'red';
};
}4.10 事件进阶
事件监听(推荐)
同一个元素同一个事件可以绑定多个处理函数。
元素.addEventListener('事件类型', 处理函数);var btn = document.getElementById('btn');
btn.addEventListener('click', function () {
console.log('第一个处理函数');
});
btn.addEventListener('click', function () {
console.log('第二个处理函数');
});💡 事件类型不带
on前缀,如click、mouseover
删除事件
// 传统方式
元素.onclick = null;
// 事件监听方式
元素.removeEventListener('事件类型', 处理函数名);DOM 事件流
事件传播分为三个阶段:
- 捕获阶段:从父到子(从外向内)
- 目标阶段:到达事件源
- 冒泡阶段:从子到父(从内向外)
事件对象
与触发事件相关的所有信息,参数 event(或 e)就是事件对象。
元素.addEventListener('click', function (e) {
console.log(e); // 事件对象
});事件对象常用属性/方法:
| 属性/方法 | 说明 |
|---|---|
e.target | 触发事件的对象(标准浏览器) |
e.srcElement | 触发事件的对象(IE6-8) |
e.type | 事件类型(如 click,不带on) |
e.keyCode | 键盘按键码 |
e.stopPropagation() | 阻止事件冒泡 |
e.cancelBubble | 阻止事件冒泡(IE6-8) |
e.preventDefault() | 阻止默认行为(如链接跳转) |
e.pageX / e.pageY | 鼠标在文档中的坐标 |
e.clientX / e.clientY | 鼠标在可视区的坐标 |
e.target 与 this 的区别:
e.target:触发事件的对象(实际点击的元素)this:绑定事件的对象
阻止事件冒泡
e.stopPropagation(); // 标准浏览器
e.cancelBubble = true; // IE6-8阻止默认行为
e.preventDefault(); // 标准浏览器事件委托
不给子元素绑定事件,给父元素绑定事件,利用事件冒泡原理。
优点:减少事件绑定数量,提高性能。
// 给ul绑定事件,点击li也能触发
document.querySelector('ul').addEventListener('click', function (e) {
if (e.target.tagName === 'LI') {
console.log('点击了li');
}
});键盘事件
执行顺序:keydown → keypress → keyup
keydown:按键按下触发(识别所有键)keypress:按键按下触发(不识别功能键,区分大小写)keyup:按键松开触发
keyCode: 按键的ASCII码值
- keypress:区分大小写(大写65-90,小写97-122)
- keydown/keyup:字母键都以大写显示(65-90)
表单相关
// 获取/设置输入框内容
元素.value
// 获取/设置元素HTML内容
元素.innerHTML4.11 BOM概述
BOM(Browser Object Model):浏览器对象模型。
与浏览器窗口交互的对象集合,核心对象是 window。
window(顶级对象)
├── document(文档)
├── location(URL相关)
├── navigator(浏览器信息)
├── history(历史记录)
└── screen(屏幕信息)4.12 window对象
window 是浏览器的顶级对象,代表浏览器窗口。
常见属性
| 属性 | 描述 |
|---|---|
innerWidth | 窗口文档显示区宽度 |
innerHeight | 窗口文档显示区高度 |
name | 窗口名称 |
closed | 窗口是否已关闭 |
screenLeft / screenTop | 窗口左上角在屏幕的坐标 |
opener | 打开当前窗口的父窗口 |
parent | 父窗口(框架用) |
self | 当前窗口对象本身 |
常见事件
// 页面加载完成事件
window.onload = function () {
// 页面所有资源加载完后执行
};
// 窗口大小改变事件
window.onresize = function () {
// 窗口大小改变时触发
};常见方法
// 打开新窗口
window.open(URL, name, features, replace);
// 关闭窗口
window.close();open 参数说明:
URL:打开的页面地址name:窗口名称(_blank新窗口、_self当前页)features:窗口特征(宽、高、位置、菜单栏等)
模态对话框
alert('信息'); // 警告框
confirm('确认吗?'); // 确认框,返回true/false
prompt('请输入'); // 输入框,返回输入内容4.13 定时器
设置定时器
// 一次性定时器:指定毫秒后执行一次
setTimeout(函数, 毫秒数);
// 周期性定时器:每隔指定毫秒执行一次
setInterval(函数, 毫秒数);清除定时器
clearTimeout(定时器ID); // 清除一次性定时器
clearInterval(定时器ID); // 清除周期性定时器// 示例
var timer = setTimeout(function () {
console.log('3秒后执行');
}, 3000);
// 清除
clearTimeout(timer);4.14 JS执行机制
单线程
JS 是单线程的,同一时间只能做一件事。
同步与异步
- 同步:前一个任务结束后再执行后一个任务(排队执行)
- 异步:做一件事的同时,可以做其他事情
异步任务举例: click事件、setTimeout、setInterval、AJAX请求等
执行机制:
- 先执行所有同步任务
- 异步任务放入任务队列
- 同步任务执行完后,依次执行任务队列中的异步任务
4.15 location对象
URL 相关信息。
URL 组成示例:
https://www.baidu.com:443/path/index.html?id=1&name=2#hash
\_____/ \_________/ \__/ \____________/ \___________/ \___/
协议 主机名 端口 路径 参数 锚点常用属性:
| 属性 | 说明 |
|---|---|
href | 完整URL |
protocol | 协议 |
host | 主机+端口 |
hostname | 主机名 |
port | 端口 |
pathname | 路径 |
search | 查询参数(?后面的) |
hash | 锚点(#后面的) |
常用方法:
| 方法 | 说明 |
|---|---|
assign(url) | 载入新页面(有历史记录) |
replace(url) | 替换当前页面(无历史记录) |
reload() | 重新加载(刷新) |
4.16 history对象
浏览器历史记录。
| 属性/方法 | 说明 |
|---|---|
length | 历史记录数量 |
back() | 后退 |
forward() | 前进 |
go(n) | 跳转到第n条记录(正数前进,负数后退) |
4.17 navigator对象
浏览器信息。
常用属性: appCodeName、appName、appVersion、platform
常用方法: javaEnabled()
4.18 Web Storage
HTML5 新增的客户端存储方案,比 Cookie 更直观。
sessionStorage
临时保存同一窗口(标签页)的数据,关闭窗口即清除。
特点:
- 只在本地生效,关闭标签页清除
- key-value 存储,value 必须是字符串
- 存储上限约 5MB
// 保存
sessionStorage.setItem('key', 'value');
// 获取
sessionStorage.getItem('key');
// 删除
sessionStorage.removeItem('key');
// 清空所有
sessionStorage.clear();localStorage
永久保存在本地,关闭浏览器也不会消失,除非手动清除。
特点:
- 永久存储,同源窗口共享
- 只能存字符串
- 存储上限约 5MB
// 保存
localStorage.setItem('key', 'value');
// 获取
localStorage.getItem('key');
// 删除
localStorage.removeItem('key');
// 清空所有
localStorage.clear();三者对比
| 特性 | localStorage | sessionStorage | Cookie |
|---|---|---|---|
| 存储容量 | 约5-10MB | 约5-10MB | 约4KB |
| 持久性 | 永久 | 会话级(关标签页清除) | 可设置过期时间 |
| 共享范围 | 同源所有窗口共享 | 仅限当前窗口 | 同源所有窗口共享 |
| 与服务器通信 | 不会自动发送 | 不会自动发送 | 每次请求自动携带 |
| 用途 | 永久保存用户数据 | 临时保存会话数据 | 身份验证、Session ID |
第五章 JS网页特效
5.1 偏移量 offset
| 属性 | 作用 | 包含 |
|---|---|---|
offsetLeft | 相对有定位父元素左边框的偏移 | — |
offsetTop | 相对有定位父元素上边框的偏移 | — |
offsetWidth | 自身宽度 | padding + border + 内容 |
offsetHeight | 自身高度 | padding + border + 内容 |
offsetParent | 返回带定位的父元素 | — |
💡 如果父元素没有定位,则相对于 body。
offset 与 style 的区别:
- offset 可以获取任意样式表中的样式值
- offset 获取的是数值型(不带单位)
- offset 是只读属性,不能赋值
- style 只能获取行内样式,可读写
5.2 可视区 client
| 属性 | 作用 | 包含 | 不包含 |
|---|---|---|---|
clientLeft | 左边框宽度 | border-left | padding、margin、内容 |
clientTop | 上边框高度 | border-top | padding、margin、内容 |
clientWidth | 可视宽度 | 内容 + 左右padding | border、margin、滚动条 |
clientHeight | 可视高度 | 内容 + 上下padding | border、margin、滚动条 |
5.3 滚动 scroll
| 属性 | 作用 | 包含 | 不包含 |
|---|---|---|---|
scrollWidth | 总内容宽度 | 所有内容 + 左右padding | border、margin |
scrollHeight | 总内容高度 | 所有内容 + 上下padding | border、margin |
scrollLeft | 被卷去的左侧距离 | 滚动条偏移量 | — |
scrollTop | 被卷去的上方距离 | 滚动条偏移量 | — |
页面滚动事件:
window.onscroll = function () {
console.log(window.pageYOffset); // 页面被卷去的顶部距离
};第六章 ES6新特性
6.1 ES6概述
ES6(ECMAScript 6)是 JavaScript 语言的新标准,2015年6月正式发布,也叫 ES2015。
引入了大量新语法特性,使 JS 更现代化、易读、易维护,更适合企业级开发。
6.2 let 与 const
let 命令
声明变量,只在代码块内有效(块级作用域)。
{
let a = 10;
var b = 1;
}
console.log(a); // ReferenceError: a is not defined
console.log(b); // 1let vs var:
- let 有块级作用域,var 没有
- let 不存在变量提升,var 有
- let 有暂时性死区
- let 不允许重复声明
const 命令
声明只读的常量,一旦声明,值不能改变。
const PI = 3.1415;
PI = 3; // TypeError: Assignment to constant variable.⚠️ const 声明时必须赋值;如果是对象,对象的属性可以修改(因为地址不变)。
6.3 模板字符串
增强版的字符串,用反引号 ` 标识。
特点:
- 可以当普通字符串使用
- 可以定义多行字符串
- 可以在字符串中嵌入变量(
${变量})
let name = '张三';
let age = 18;
// 嵌入变量
let str = `${name}的年龄是${age}岁`;
// 多行字符串
let html = `
<div>
<h1>标题</h1>
<p>内容</p>
</div>
`;6.4 对象与方法简写
属性简写
const age = 12;
const name = 'Amy';
// 简写
const person = { age, name };
// 等同于
const person = { age: age, name: name };方法简写
const person = {
sayHi() {
console.log('Hi');
}
};
// 等同于
const person = {
sayHi: function () {
console.log('Hi');
}
};6.5 箭头函数
更加简洁的函数书写方式。
语法: 参数 => 函数体
// 普通函数
var fn1 = function (a, b) {
return a + b;
};
// 箭头函数
var fn2 = (a, b) => {
return a + b;
};简化规则:
- 只有一个参数时,括号可以省略
- 没有参数时,括号不能省略
- 函数体只有一行 return 语句时,大括号和 return 可以省略
| 传统定义 | 箭头函数 | 描述 |
|---|---|---|
function() {} | () => {} | 无参 |
function(a) {} | a => {} | 单个参数 |
function(a, b) {} | (a, b) => {} | 多个参数 |
function(a, ...args) {} | (a, ...args) => {} | 可变参数 |
⚠️ 箭头函数没有自己的 this,它的 this 继承自外层作用域。
6.6 解构赋值
数组解构
let [a, b, c] = [1, 2, 3];
// a=1, b=2, c=3对象解构
const { name, age } = { name: 'John', age: 20 };
// name='John', age=206.7 数组扩展方法
数组创建
Array.from(): 将伪数组/可遍历对象转为真正的数组
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let arr = Array.from(arrayLike); // ['a', 'b', 'c']Array.of(): 将一组值转为数组
Array.of(3, 11, 8); // [3, 11, 8]数据筛选
| 方法 | 作用 |
|---|---|
find(回调) | 找出第一个符合条件的成员 |
findIndex(回调) | 找出第一个符合条件的成员的索引,找不到返回-1 |
filter(回调) | 返回符合条件的全部成员(新数组) |
some(回调) | 是否有至少一个满足条件(布尔值) |
every(回调) | 是否全部满足条件(布尔值) |
var nums = [2, 6, 22, 55];
nums.find(v => v > 9); // 22
nums.filter(v => v > 9); // [22, 55]
nums.some(v => v > 50); // true
nums.every(v => v > 10); // false数据填充
fill(): 用给定值填充数组
// 创建长度为5、全为1的数组
const arr = new Array(5).fill(1); // [1, 1, 1, 1, 1]
// 填充指定位置
arr.fill(7, 1, 4); // 索引1~3填充为7(不包含4)数据遍历
| 方法 | 作用 |
|---|---|
keys() | 遍历键名(索引) |
values() | 遍历键值 |
entries() | 遍历键值对 |
let arr = ['小红', '小明', '小芳'];
for (let index of arr.keys()) {
console.log(index); // 0, 1, 2
}
for (let value of arr.values()) {
console.log(value); // 小红, 小明, 小芳
}
for (let [index, value] of arr.entries()) {
console.log(index + ':' + value); // 0:小红, 1:小明, 2:小芳
}includes
判断数组是否包含给定值,返回布尔值。
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[1, 2, 3].includes(3, 2); // true(从索引2开始找)flat
将嵌套数组"拉平",下降一个维度。
[1, 2, [3, [4, 5]]].flat(); // [1, 2, 3, [4, 5]]
[1, 2, [3, [4, 5]]].flat().flat(); // [1, 2, 3, 4, 5]6.8 Set 数据结构
类似于数组,但成员值唯一,没有重复。
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
// s = {2, 3, 5, 4}
const items = new Set([1, 2, 3, 4, 5, 5, 5]);
items.size; // 5(自动去重)常用方法:
| 方法 | 描述 |
|---|---|
size | 成员总数 |
add(value) | 添加值,返回Set本身 |
delete(value) | 删除值,返回布尔值 |
has(value) | 是否包含,返回布尔值 |
clear() | 清除所有成员 |
keys() / values() | 返回遍历器 |
entries() | 返回键值对遍历器 |
forEach() | 遍历每个成员 |
数组去重技巧:
let arr = [1, 2, 2, 3, 3, 3];
let unique = [...new Set(arr)]; // [1, 2, 3]6.9 Map 数据结构
键值对集合,键可以是任意类型(比 Object 更灵活)。
const map = new Map();
map.set('a', 1);
map.set('b', 2);
map.get('a'); // 1
map.set('a', 97); // 覆盖
map.get('a'); // 97
map.size; // 2
map.delete('b'); // true常用方法:
| 方法 | 描述 |
|---|---|
size | 成员总数 |
set(key, value) | 设置键值对,返回Map本身(可链式) |
get(key) | 读取值,找不到返回undefined |
has(key) | 是否存在键,返回布尔值 |
delete(key) | 删除键,返回布尔值 |
clear() | 清除所有成员 |
keys() | 返回键名遍历器 |
values() | 返回键值遍历器 |
entries() | 返回所有成员遍历器 |
forEach() | 遍历所有成员 |
6.10 Class 类与继承
ES6 引入了 Class(类)的概念,通过 class 关键字定义类。
类的基本语法
class Point {
// 构造方法
constructor(x, y) {
this.x = x;
this.y = y;
}
// 方法
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
// 创建实例
var point = new Point(2, 3);
console.log(point.toString()); // (2, 3)💡
constructor是构造方法,this代表实例对象。 类实质上就是一个函数,类自身指向构造函数。
类的继承
通过 extends 关键字实现继承。
super 关键字:在子类中调用父类的构造函数和方法。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类构造函数
this.breed = breed;
}
speak() {
super.speak(); // 调用父类方法
console.log(`${this.name} is a ${this.breed}.`);
}
}静态方法
通过 static 关键字定义,不需要创建实例就能直接调用。
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod(); // 'hello'(直接通过类名调用)教程结束
学习建议:
- 每学完一章,动手敲代码练习
- 多做小项目,如计算器、轮播图、TodoList
- 善用 MDN 文档查阅 API
- 学会调试:console.log + 断点调试