一、JS 初相识
1.1 什么是 JavaScript
JavaScript 是一种高级的、解释型的编程语言,主要用于为网页添加交互性和动态功能,让原本静态的网页能够与用户进行实时互动,极大地提升了用户体验。比如,当你在网页上点击一个按钮,按钮会变色或者弹出一个提示框;又或者在表单中输入内容时,能实时得到格式是否正确的反馈,这些都是 JavaScript 在发挥作用。作为一门客户端脚本语言,JavaScript 可以直接嵌入到 HTML 页面中,与 HTML 和 CSS 紧密配合,HTML 负责搭建网页的结构,CSS 用于美化页面样式,而 JavaScript 则赋予网页生命,实现各种动态交互效果 ,它们共同构成了现代 Web 开发的三大核心技术。
1.2 JavaScript 的诞生与发展
1995 年,Netscape 公司的 Brendan Eich 为解决早期浏览器交互难题,在短短 10 天内设计完成了 JavaScript 的雏形,最初命名为 Mocha,后改为 LiveScript,最终定名为 JavaScript。当时,它的主要目的是让网页实现基本的交互功能,如简单的表单验证,减少网络流量和用户等待时间。次年,微软推出 JScript,与 JavaScript 竞争,导致不同浏览器对该语言的实现出现差异。为解决这一问题,1997 年,ECMAScript 1.0 标准发布,由欧洲计算机制造商协会(ECMA)对 JavaScript 进行标准化,规定了其核心语法、数据类型等基础内容。
随后在 1999 年,ECMAScript 3.0 发布,添加了正则表达式、try/catch、更多字符串方法等重要特性,为浏览器之间的兼容性打下了基础。2005 年,AJAX(异步 JavaScript 和 XML)技术流行,使网页应用可以在无需重新加载页面的情况下刷新数据,如 Gmail 和 Google Maps,标志着向更丰富、更互动的网络体验转型,JavaScript 的重要性也因此大增。
2009 年是 JavaScript 发展的一个重要转折点,ECMAScript 5(ES5)发布,添加了严格模式、JSON 支持、数组方法等,让 JavaScript 更现代化;同年,Node.js 诞生,使 JavaScript 可以用于服务器端开发,彻底改变了其仅能运行在浏览器端的局面,拓展了应用场景。
2015 年,ECMAScript 2015(ES6)发布,带来了重大更新,如引入 let/const 声明、箭头函数、类(class)语法、模板字符串、解构赋值、默认参数、Promise、模块系统、扩展运算符等,极大地增强了编码实践。从 ES2016 开始,ECMA 采用每年发布一个版本的模式,不断为 JavaScript 添加新特性,如 2016 年(ES7)的 Array.prototype.includes ()、指数运算符 (**);2017 年(ES8)的 async/await、Object.values ()/Object.entries ()、字符串填充方法 (padStart/padEnd) 等。
1.3 JavaScript 的应用领域
- 前端开发:JavaScript 是前端开发的核心语言,与 HTML 和 CSS 配合,实现网页的各种交互和动态效果。常见的前端框架如 React、Vue 和 Angular,都基于 JavaScript 构建,帮助开发者更高效地创建复杂的单页应用(SPA),像淘宝、京东等电商网站的前端页面,就大量运用了这些框架和 JavaScript 技术,实现商品展示、购物车操作、用户交互等功能。
- 后端开发:借助 Node.js,JavaScript 可以用于后端开发,构建服务器端应用程序。Node.js 基于 Chrome V8 引擎,具有高性能、事件驱动、非阻塞 I/O 等特点,适合开发网络服务、文件系统操作等应用。许多知名的后端项目,如 Express.js 框架构建的 Web 应用,以及 NPM(Node Package Manager)生态下的众多工具和库,都基于 Node.js 和 JavaScript 开发。
- 移动应用开发:通过 React Native、Ionic 等框架,JavaScript 可以用于开发跨平台的移动应用程序。React Native 使用 JavaScript 和 React 构建原生移动应用,能访问原生 API,开发出性能接近原生应用的移动程序,像 Facebook、Instagram 等应用的部分功能就使用了 React Native 开发。
- 桌面应用开发:使用 Electron 框架,JavaScript 可以构建跨平台的桌面应用程序。Electron 基于 Chromium 和 Node.js,允许开发者使用 Web 技术(HTML、CSS、JavaScript)创建桌面应用,如 Visual Studio Code、Atom 等编辑器就是基于 Electron 开发的。
二、搭建开发环境
“工欲善其事,必先利其器”,搭建一个合适的开发环境是学好 JavaScript 的重要前提。在这个章节中,我们将一起探讨如何选择合适的浏览器、文本编辑器,以及如何安装 Node.js 并配置项目,为后续的学习和实践打下坚实的基础。
2.1 选择浏览器
浏览器是运行 JavaScript 代码的主要环境,推荐使用 Chrome 或 Firefox 浏览器 ,它们不仅对 JavaScript 的支持度高,而且内置了强大的开发者工具,能极大地提高开发效率。以 Chrome 浏览器为例,其 DevTools 提供了丰富的功能,如断点调试,你可以在代码中设置断点,让代码在执行到断点处暂停,此时可以查看变量的值、调用栈信息等,帮助你快速定位和解决代码中的问题;性能分析工具能分析 JavaScript 代码的执行性能,找出性能瓶颈,优化代码,让网页加载和运行得更快;网络请求监控则可以查看网页发起的所有网络请求,包括请求的 URL、参数、响应状态等,方便调试与服务器交互的功能。
2.2 挑选文本编辑器
文本编辑器是编写 JavaScript 代码的工具,一款好的文本编辑器能让编码过程更加高效和舒适。VSCode 是一款由微软开发的免费开源代码编辑器,它功能强大,支持语法高亮,不同的代码元素会以不同的颜色显示,让代码结构一目了然;具备智能代码补全功能,能根据你输入的内容自动提示可能的代码,减少手动输入,提高编码速度;还拥有丰富的插件生态,通过安装插件,你可以进一步扩展其功能,如 ESLint 插件可以帮助你检测和修复代码中的语法错误和风格问题。
Sublime Text 也是一款颇受欢迎的编辑器,以其简洁高效的界面和强大的文本编辑功能著称,启动速度快,能让开发者迅速进入工作状态;它的快捷键操作方便,熟练掌握后可大大提高编辑效率,比如通过快捷键能快速定位到代码中的特定位置,或进行快速的文本替换操作。
Atom 则是 GitHub 开发的开源代码编辑器,具有高度的可定制性,你可以根据自己的喜好和需求对界面进行个性化设置,包括调整颜色主题、字体大小、布局等;它的插件生态系统也非常活跃,拥有大量的插件可供选择,这些插件可以扩展 Atom 的功能,使其能够适应各种不同的开发场景。
2.3 安装 Node.js
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境,它让 JavaScript 可以在服务器端运行,拓展了 JavaScript 的应用领域。Node.js 使用事件驱动、非阻塞 I/O 模型,非常适合构建高并发的网络应用。
安装 Node.js 很简单,以 Windows 系统为例,首先访问 Node.js 官网(https://nodejs.org/ ),在官网中可以看到不同版本的 Node.js,推荐下载 LTS(长期支持)版本,稳定性和兼容性更好。下载完成后,双击安装包,进入安装向导,点击 “Next”,阅读并勾选使用许可协议,再点击 “Next”,此时可以选择安装位置,若没有特殊需求,保持默认即可,继续点击 “Next”,安装过程中,注意勾选 “Add to PATH” 选项,这样安装完成后就可以在命令行中直接使用 node 和 npm 命令。安装完成后,按下 Win+R 键,输入 “cmd” 打开命令提示符,输入 “node -v” 查看 Node.js 版本,输入 “npm -v” 查看 npm(Node Package Manager,Node.js 的包管理器)版本,如果能输出版本号,说明安装成功。
2.4 配置项目
在开始一个新的 JavaScript 项目时,首先要创建项目目录。打开命令提示符,使用 “mkdir” 命令创建一个新的文件夹,例如 “mkdir my - js - project”,然后使用 “cd” 命令进入该目录,即 “cd my - js - project”。
进入项目目录后,需要初始化项目。在命令行中输入 “npm init”,这会引导你创建一个 package.json 文件,该文件是项目的配置文件,记录了项目的名称、版本、依赖项等信息。执行 “npm init” 后,会有一系列的交互式提问,如项目名称、版本号、描述等,你可以根据项目实际情况进行填写,若不想逐一设置,也可以直接输入 “npm init -y”,使用默认设置快速生成 package.json 文件。
项目初始化完成后,就可以安装项目依赖了。在 JavaScript 项目中,通常会使用一些第三方库和工具来帮助开发,这些库和工具就是项目的依赖项。使用 “npm install” 命令来安装依赖,例如,如果你想安装一个用于处理 HTTP 请求的库 “axios”,就在命令行中输入 “npm install axios”,npm 会自动从 npm 仓库下载 “axios” 及其依赖项,并将其安装到项目目录下的 “node_modules” 文件夹中。安装完成后,package.json 文件中会自动添加 “axios” 的依赖信息。
三、基础语法探秘
3.1 变量与数据类型
在 JavaScript 中,变量用于存储数据值。声明变量有三种方式:var、let和const。var是 ES5 中声明变量的关键字,它具有函数作用域,即如果在函数内部使用var声明变量,该变量在整个函数内都有效;如果在函数外部声明,变量会成为全局变量。比如:
function test() {
var num = 10;
if (true) {
var num = 20; // 这里重新声明的num会覆盖上面的num,因为var有变量提升,在函数作用域内有效
console.log(num); // 输出20
}
console.log(num); // 输出20
}
test();
let是 ES6 新增的声明变量的关键字,它具有块级作用域,只在最近的一对花括号{}内有效。例如:
function test() {
let num = 10;
if (true) {
let num = 20; // 这里声明的num是一个新的变量,只在这个if块内有效
console.log(num); // 输出20
}
console.log(num); // 输出10
}
test();
const也是 ES6 新增的,用于声明常量,一旦声明,其值就不能再改变。比如:
const PI = 3.14159;
// PI = 3.14; // 这行代码会报错,因为PI是常量,不能重新赋值
JavaScript 的基本数据类型有数字(Number)、字符串(String)、布尔值(Boolean)、null、undefined、Symbol(ES6 新增,表示唯一且不可变的值 )。数字类型既可以表示整数,也可以表示浮点数,如let num = 10; ,let floatNum = 3.14; ;字符串类型用于表示文本数据,用单引号或双引号包裹,如let str = ‘Hello, World!’; ;布尔值只有true和false两个取值,用于逻辑判断,如let isDone = true; ;null表示空值,let a = null; ;undefined表示变量未被赋值,let b; ,此时b的值就是undefined。
复杂数据类型主要有对象(Object)和数组(Array)等。对象是一种无序的键值对集合,用于存储多个相关数据,例如:
let person = {
name: 'John',
age: 30,
job: 'Engineer'
};
数组是一种有序的数据集合,可以存储多个值,例如:
let numbers = [1, 2, 3, 4, 5];
3.2 运算符
JavaScript 中的运算符丰富多样,涵盖了算术、比较、逻辑和赋值等多种类型。算术运算符用于基本数学运算,是数学计算的基础工具。例如+用于加法,let sum = 2 + 3; ,此时sum的值为 5;-用于减法,let diff = 5 - 2; ,diff的值为 3;*用于乘法,let product = 4 * 3; ,product的值为 12;/用于除法,let quotient = 10 / 2; ,quotient的值为 5;%用于取余,let remainder = 7 % 3; ,remainder的值为 1。自增++和自减–运算符也很常用,let num = 5; num++; ,执行后num的值变为 6;let num2 = 5; num2–; ,执行后num2的值变为 4。
比较运算符用于比较两个值,结果为布尔值true或false。>表示大于,let isGreater = 5 > 3; ,isGreater的值为true;<表示小于,let isLess = 2 < 4; ,isLess的值为true;==表示相等,比较时会进行类型转换,let isEqual1 = 5 == ‘5’; ,isEqual1的值为true;===表示全等,不仅比较值,还比较类型,let isEqual2 = 5 === ‘5’; ,isEqual2的值为false。!=表示不相等,let isNotEqual1 = 5 != 3; ,isNotEqual1的值为true;!==表示不全等,let isNotEqual2 = 5!== ‘5’; ,isNotEqual2的值为true。
逻辑运算符主要用于处理布尔逻辑,常用于条件判断。&&表示逻辑与,只有当两个操作数都为true时,结果才为true。例如let result1 = true && false; ,result1的值为false。||表示逻辑或,只要有一个操作数为true,结果就为true ,如let result2 = true || false; ,result2的值为true。!表示逻辑非,对操作数进行取反,let result3 =!true; ,result3的值为false。
赋值运算符用于将值赋给变量。=是最基本的赋值运算符,let num = 10; ,将 10 赋值给num。还有一些复合赋值运算符,如+=,let num4 = 5; num4 += 3; ,相当于num4 = num4 + 3; ,执行后num4的值为 8;-= ,let num5 = 10; num5 -= 2; ,相当于num5 = num5 - 2; ,执行后num5的值为 8;*= ,let num6 = 4; num6 *= 3; ,相当于num6 = num6 * 3; ,执行后num6的值为 12;/= ,let num7 = 10; num7 /= 2; ,相当于num7 = num7 / 2; ,执行后num7的值为 5。
3.3 条件语句
在 JavaScript 中,条件语句是控制程序流程的重要工具,它可以根据不同的条件执行不同的代码块。if-else语句是最常用的条件语句之一,语法如下:
if (condition) {
// 当condition为true时执行的代码
} else if (anotherCondition) {
// 当condition为false且anotherCondition为true时执行的代码
} else {
// 当以上所有条件都为false时执行的代码
}
例如,根据一个学生的成绩判断其等级:
let score = 85;
if (score >= 90) {
console.log('等级为A');
} else if (score >= 80) {
console.log('等级为B');
} else if (score >= 70) {
console.log('等级为C');
} else if (score >= 60) {
console.log('等级为D');
} else {
console.log('等级为F');
}
switch语句也是一种条件语句,它基于一个表达式的值来选择执行不同的代码块。语法如下:
switch (expression) {
case value1:
// 当expression的值等于value1时执行的代码
break;
case value2:
// 当expression的值等于value2时执行的代码
break;
default:
// 当expression的值不等于任何case值时执行的代码
}
例如,根据用户输入的数字输出对应的星期几:
let day = 3;
switch (day) {
case 1:
console.log('星期一');
break;
case 2:
console.log('星期二');
break;
case 3:
console.log('星期三');
break;
case 4:
console.log('星期四');
break;
case 5:
console.log('星期五');
break;
case 6:
console.log('星期六');
break;
case 7:
console.log('星期日');
break;
default:
console.log('无效的数字');
}
if-else语句更适合复杂的条件判断,当需要基于多个不同变量或复杂逻辑组合进行判断时,if-else语句能更好地发挥作用。而switch语句则更适用于单一变量或表达式的简单相等性测试,尤其是当有多个离散的可能值时,使用switch语句会使代码更加简洁和易读。
3.4 循环语句
循环语句在编程中至关重要,它能让一段代码重复执行,直到满足特定条件。for循环通常用于明确知道循环次数的场景,语法如下:
for (initialization; condition; update) {
// 循环体
}
例如,打印 1 到 5 的数字:
for (let i = 1; i <= 5; i++) {
console.log(i);
}
while循环用于循环次数不确定,但满足某个条件时继续执行的场景。语法为:
while (condition) {
// 循环体
}
例如,计算 1 到 100 的和:
let sum = 0;
let i = 1;
while (i <= 100) {
sum += i;
i++;
}
console.log('1到100的和为:', sum);
do-while循环与while循环类似,但它会先执行一次循环体,然后再检查条件。语法如下:
do {
// 循环体
} while (condition);
例如,用户登录系统,至少提示一次输入用户名和密码:
let username;
let password;
do {
username = prompt('请输入用户名:');
password = prompt('请输入密码:');
if (username === 'admin' && password === '123456') {
console.log('登录成功');
break;
} else {
console.log('用户名或密码错误,请重新输入');
}
} while (true);
for循环适用于固定次数的迭代和计数循环;while循环适用于条件驱动的迭代和等待某个条件的场景;do-while循环则确保循环体至少执行一次,适合至少执行一次的迭代和后条件循环的场景。
四、函数的魔法世界
4.1 函数的定义与调用
在 JavaScript 中,函数是一段可以重复使用的代码块,用于执行特定的任务。函数的定义语法如下:
function functionName(parameters) {
// 函数体
statements;
return value;
}
- function是定义函数的关键字。
- functionName是函数名,命名规则与变量名相同,应遵循驼峰命名法,且具有描述性,以便清晰表达函数的功能,如calculateSum表示计算总和的函数。
- parameters是参数列表,用于接收调用函数时传递的值,可以有多个参数,参数之间用逗号隔开,也可以没有参数。例如:
function addNumbers(a, b) {
let sum = a + b;
return sum;
}
这里的addNumbers函数有两个参数a和b,用于接收两个数字,函数体将这两个数字相加,并返回结果。
调用函数时,使用函数名后跟一对括号,如果函数有参数,在括号内传递相应的参数值。例如:
let result = addNumbers(3, 5);
console.log(result); // 输出8
在这个例子中,调用addNumbers函数,并传递 3 和 5 作为参数,函数执行后返回 8,将返回值赋值给result变量,然后输出result的值。
4.2 函数的返回值
函数可以使用return语句返回一个值,这个值可以是任何数据类型,如数字、字符串、对象、数组等。return语句会立即终止函数的执行,并将指定的值返回给调用者。例如:
function getFullName(firstName, lastName) {
let fullName = firstName + ' ' + lastName;
return fullName;
}
let name = getFullName('John', 'Doe');
console.log(name); // 输出John Doe
在这个例子中,getFullName函数接收firstName和lastName两个参数,将它们拼接成完整的姓名,并通过return语句返回,调用函数时,将返回的完整姓名赋值给name变量。
如果函数没有使用return语句显式返回值,或者return语句后面没有跟任何值,函数将返回undefined。例如:
function printMessage() {
console.log('Hello, World!');
}
let result = printMessage();
console.log(result); // 输出undefined
在这个例子中,printMessage函数没有return语句,所以调用该函数后,返回值为undefined,将其赋值给result变量并输出。
4.3 匿名函数与箭头函数
匿名函数是没有函数名的函数,通常用于在需要函数作为参数或返回值的场景中,如作为回调函数。例如,在setTimeout函数中,我们常常使用匿名函数作为回调,在指定的延迟时间后执行一些操作 :
setTimeout(function() {
console.log('延迟1秒后执行');
}, 1000);
在这个例子中,传递给setTimeout的是一个匿名函数,它没有函数名,当延迟 1 秒后,这个匿名函数会被执行。
ES6 中引入了箭头函数,它提供了一种更简洁的函数定义语法。箭头函数的基本语法如下:
(parameters) => expression
或者
(parameters) => {
statements;
return value;
}
如果只有一个参数,可以省略参数的括号;如果没有参数,使用空括号() ;如果函数体只有一条语句,并且这条语句是返回值,可以省略花括号和return关键字,直接返回该语句的结果。例如:
// 普通函数
function square1(x) {
return x * x;
}
// 箭头函数
const square2 = x => x * x;
let result1 = square1(5);
let result2 = square2(5);
console.log(result1); // 输出25
console.log(result2); // 输出25
在这个例子中,square1是普通函数,square2是箭头函数,它们实现了相同的功能,即计算一个数的平方。箭头函数的语法更加简洁,减少了代码量。
箭头函数还有一个重要特点,它没有自己的this值,它的this值继承自外层作用域。这在处理回调函数时非常有用,避免了传统函数中this指向问题带来的困扰。例如:
const person = {
name: 'John',
age: 30,
sayHello: function() {
setTimeout(() => {
console.log(`Hello, my name is ${this.name}, I'm ${this.age} years old.`);
}, 1000);
}
};
person.sayHello();
在这个例子中,sayHello方法中的setTimeout回调函数使用了箭头函数,箭头函数的this继承自sayHello方法,所以能够正确访问person对象的name和age属性。如果使用传统函数作为回调,this的指向会发生变化,导致无法正确访问person对象的属性。
五、深入对象与数组
5.1 对象的创建与使用
在 JavaScript 中,对象是一种复杂的数据类型,用于存储和组织相关的数据和功能。对象由属性和方法组成,属性是对象的特征,以键值对的形式存在,方法则是对象可以执行的操作,本质上是函数。创建对象有多种方式,其中最常见的是使用对象字面量和构造函数。
使用对象字面量创建对象非常简单直观,通过一对花括号{},在其中定义属性和方法。例如,创建一个表示人的对象:
let person = {
name: 'John',
age: 30,
sayHello: function() {
console.log('Hello, my name is'+ this.name);
}
};
在这个例子中,person对象有name和age两个属性,分别表示人的姓名和年龄,还有一个sayHello方法,用于打印问候语。访问对象的属性可以使用点符号(.)或方括号([])。例如:
console.log(person.name); // 输出John
console.log(person['age']); // 输出30
person.sayHello(); // 输出Hello, my name is John
使用点符号访问属性时,属性名是标识符,直接写在点后面;使用方括号访问属性时,属性名以字符串形式放在方括号内,这种方式更灵活,适用于属性名是变量或包含特殊字符的情况。
修改对象的属性也很简单,直接对属性赋值即可。例如:
person.age = 31;
console.log(person.age); // 输出31
如果要添加新的属性,同样直接赋值。例如:
person.gender ='male';
console.log(person.gender); // 输出male
另一种创建对象的方式是使用构造函数。构造函数是一种特殊的函数,用于创建和初始化对象实例。定义构造函数时,通常以大写字母开头,以便与普通函数区分。例如,定义一个Person构造函数:
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHello = function() {
console.log('Hello, my name is'+ this.name);
};
}
在构造函数内部,使用this关键字来引用新创建的对象,并为其添加属性和方法。使用new关键字调用构造函数,会创建一个新的对象实例。例如:
let person1 = new Person('Alice', 25);
let person2 = new Person('Bob', 35);
person1.sayHello(); // 输出Hello, my name is Alice
person2.sayHello(); // 输出Hello, my name is Bob
每个通过Person构造函数创建的对象实例都有自己独立的name和age属性,但共享sayHello方法,这样可以节省内存空间,提高代码的复用性。
5.2 数组的操作
数组是 JavaScript 中另一种常用的数据结构,用于存储一组有序的数据。创建数组有两种主要方法:使用数组字面量和构造函数。数组字面量是创建数组最简单的方式,使用方括号[],在其中依次列出数组的元素。例如:
let numbers = [1, 2, 3, 4, 5];
let fruits = ['apple', 'banana', 'orange'];
使用数组构造函数Array()也可以创建数组,可以传入具体的元素,也可以只传入数组的长度。例如:
let numbers1 = new Array(1, 2, 3, 4, 5);
let emptyArray = new Array(5); // 创建一个长度为5的空数组,元素默认是undefined
访问数组元素通过索引进行,索引从 0 开始。例如:
console.log(numbers[0]); // 输出1
console.log(fruits[2]); // 输出orange
修改数组元素同样通过索引赋值。例如:
numbers[1] = 10;
console.log(numbers); // 输出[1, 10, 3, 4, 5]
JavaScript 为数组提供了丰富的方法,方便对数组进行各种操作。push()方法用于在数组末尾添加一个或多个元素,并返回数组的新长度。例如:
let arr = [1, 2, 3];
let newLength = arr.push(4, 5);
console.log(arr); // 输出[1, 2, 3, 4, 5]
console.log(newLength); // 输出5
pop()方法用于删除数组末尾的一个元素,并返回被删除的元素。例如:
let lastElement = arr.pop();
console.log(arr); // 输出[1, 2, 3, 4]
console.log(lastElement); // 输出5
shift()方法用于删除数组开头的一个元素,并返回被删除的元素。例如:
let firstElement = arr.shift();
console.log(arr); // 输出[2, 3, 4]
console.log(firstElement); // 输出1
unshift()方法用于在数组开头添加一个或多个元素,并返回数组的新长度。例如:
let newLength2 = arr.unshift(0);
console.log(arr); // 输出[0, 2, 3, 4]
console.log(newLength2); // 输出4
slice()方法用于提取数组的一部分,返回一个新数组,不会修改原数组。它接受两个参数,分别是起始索引(包括)和结束索引(不包括)。例如:
let subArray = arr.slice(1, 3);
console.log(subArray); // 输出[2, 3]
console.log(arr); // 输出[0, 2, 3, 4],原数组不变
splice()方法用于在指定位置插入或删除元素,会修改原数组。它可以接受多个参数,第一个参数是起始位置,第二个参数是要删除的元素个数,后面的参数是要插入的元素。例如,删除元素:
let removedElements = arr.splice(1, 2);
console.log(arr); // 输出[0, 4]
console.log(removedElements); // 输出[2, 3]
插入元素:
arr.splice(1, 0, 2, 3);
console.log(arr); // 输出[0, 2, 3, 4]
六、DOM 操作与事件处理
6.1 认识 DOM
DOM,即文档对象模型(Document Object Model),是 W3C 组织推荐的处理可扩展标志语言的标准编程接口,它将 HTML 或 XML 文档表示为一个树状结构,其中每个节点都是文档的一个对象,这些对象可以是元素、属性、文本等。在这个树形结构中,最顶层的节点是document对象,它代表整个 HTML 文档。例如,对于下面这个简单的 HTML 文档:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>DOM示例</title>
</head>
<body>
<h1 id="title">欢迎来到我的网站</h1>
<p class="content">这是一段介绍性文字。</p>
<ul id="list">
<li>列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
</ul>
</body>
</html>
在 JavaScript 中,通过document对象可以访问和操作 HTML 文档的各个部分。比如,使用getElementById()方法可以通过元素的id获取对应的 DOM 元素,let title = document.getElementById(‘title’); ,这样就获取到了<h1>元素 ;getElementsByClassName()方法用于通过类名获取一组 DOM 元素,let contents = document.getElementsByClassName(‘content’); ,返回的是一个类数组对象,包含所有类名为content的元素 ;querySelector()方法则可以通过 CSS 选择器获取匹配的第一个 DOM 元素,let firstLi = document.querySelector(‘#list li’); ,获取到<ul>列表中的第一个<li>元素。
通过这些方法获取到 DOM 元素后,就可以对其进行各种操作,如修改元素的内容、属性、样式等。例如,修改<h1>元素的文本内容:
title.textContent = '新的标题';
修改<p>元素的样式:
contents[0].style.color ='red';
6.2 事件处理
在网页开发中,事件处理是实现用户与页面交互的关键。通过为 DOM 元素添加事件监听器,可以在特定事件发生时执行相应的代码。常见的事件类型有很多,click事件是当用户点击元素时触发。比如,为一个按钮添加点击事件监听器:
<button id="myButton">点击我</button>
<script>
let button = document.getElementById('myButton');
button.addEventListener('click', function () {
alert('按钮被点击了!');
});
</script>
mouseover事件在鼠标悬停在元素上方时触发,mouseout事件则在鼠标离开元素时触发。例如,当鼠标悬停在一个图片上时,改变图片的透明度:
<img src="example.jpg" id="myImage" alt="示例图片">
<script>
let image = document.getElementById('myImage');
image.addEventListener('mouseover', function () {
this.style.opacity = '0.5';
});
image.addEventListener('mouseout', function () {
this.style.opacity = '1';
});
</script>
keydown事件在用户按下键盘上的键时触发,常用于处理用户的键盘输入。比如,在一个输入框中监听用户的按键操作:
<input type="text" id="myInput">
<script>
let input = document.getElementById('myInput');
input.addEventListener('keydown', function (event) {
console.log('按下的键是:', event.key);
});
</script>
当事件发生时,会生成一个事件对象,这个对象包含了与事件相关的各种信息。事件对象的target属性返回触发事件的对象,currentTarget属性返回事件绑定的对象。例如:
<ul id="myList">
<li>列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
</ul>
<script>
let list = document.getElementById('myList');
list.addEventListener('click', function (event) {
console.log('触发事件的对象是:', event.target);
console.log('事件绑定的对象是:', event.currentTarget);
});
</script>
在这个例子中,如果点击某个<li>元素,event.target就是被点击的<li>元素,而event.currentTarget则是<ul>元素。事件对象还有很多其他属性和方法,preventDefault()方法可以阻止事件的默认行为,比如在点击链接时,阻止链接的跳转 :
<a href="https://www.example.com" id="myLink">点击跳转</a>
<script>
let link = document.getElementById('myLink');
link.addEventListener('click', function (event) {
event.preventDefault();
console.log('链接跳转被阻止');
});
</script>
stopPropagation()方法用于阻止事件冒泡,即阻止事件向父元素传播。例如:
<div id="parent">
<div id="child"></div>
</div>
<script>
let parent = document.getElementById('parent');
let child = document.getElementById('child');
child.addEventListener('click', function (event) {
console.log('子元素被点击');
event.stopPropagation();
});
parent.addEventListener('click', function () {
console.log('父元素被点击');
});
</script>
在这个例子中,当点击子元素时,由于调用了event.stopPropagation(),事件不会冒泡到父元素,所以不会触发父元素的点击事件。
七、总结与展望
7.1 知识回顾
在 JavaScript 基础入门的学习中,我们首先认识了 JavaScript 这门编程语言,了解到它在网页开发中负责实现交互和动态功能,与 HTML、CSS 共同构成现代 Web 开发的核心技术。它的发展历程丰富,从最初解决浏览器交互难题,到如今广泛应用于前端、后端、移动应用、桌面应用等多个领域。
搭建开发环境时,我们选择了对 JavaScript 支持度高且自带强大开发者工具的 Chrome 或 Firefox 浏览器 ,以及功能丰富的 VSCode、简洁高效的 Sublime Text、高度可定制的 Atom 等文本编辑器。通过官网下载安装包,我们顺利安装了 Node.js,并使用npm init初始化项目,用npm install安装项目依赖,完成了开发环境的搭建。
在基础语法部分,我们学习了变量声明的var、let和const关键字,以及数字、字符串、布尔值等基本数据类型和对象、数组等复杂数据类型。掌握了算术、比较、逻辑和赋值等运算符,学会使用if-else和switch条件语句,以及for、while、do - while循环语句来控制程序流程。
函数方面,学会了函数的定义与调用,理解函数返回值的概念,还认识了匿名函数和箭头函数,箭头函数以其简洁的语法和独特的this指向特性,在很多场景下为我们提供了更便捷的编程方式。
深入学习对象与数组时,我们掌握了使用对象字面量和构造函数创建对象的方法,学会访问、修改对象属性和调用对象方法。对于数组,了解了数组字面量和构造函数两种创建方式,以及通过索引访问和修改数组元素的方法,还熟练运用了push、pop、shift、unshift等丰富的数组方法。
最后,在 DOM 操作与事件处理中,我们认识到 DOM 将 HTML 文档表示为树状结构,通过document对象及getElementById、getElementsByClassName等方法可以获取 DOM 元素并进行操作。学会了为 DOM 元素添加click、mouseover、keydown等事件监听器,以及利用事件对象的target、currentTarget属性和preventDefault、stopPropagation等方法来处理事件。
7.2 下一步学习建议
- 深入学习高级特性:JavaScript 有许多强大的高级特性,如闭包、原型链、异步编程(Promise、async/await)等。闭包可以让函数访问其外部作用域的变量,在封装和数据保护等方面有重要应用。原型链是 JavaScript 实现继承的机制,深入理解它有助于更好地掌握对象的创建和继承关系。异步编程则是处理 JavaScript 中异步操作(如网络请求、定时器等)的关键,通过学习 Promise 和 async/await,可以更优雅地处理异步任务,避免回调地狱。
- 探索前端框架:在实际项目开发中,前端框架能极大提高开发效率和代码的可维护性。React 是目前最流行的前端框架之一,采用组件化开发和虚拟 DOM 技术,通过 JSX 语法将 HTML 和 JavaScript 代码融合,使代码结构更清晰,开发大型应用时优势明显。Vue 也是一款优秀的框架,以其简洁易用的 API 和强大的响应式系统受到开发者喜爱,它的模板语法简单直观,适合初学者快速上手。可以通过学习这些框架的官方文档、教程和实际项目来掌握它们。
- 参与实战项目:理论知识固然重要,但只有通过实践才能真正掌握 JavaScript。可以参与开源项目,在 GitHub 等平台上有许多优秀的 JavaScript 开源项目,参与其中能与其他开发者交流合作,学习到先进的开发理念和代码规范。也可以自己动手做一些小型项目,如个人博客、简单的 Web 应用等,从项目需求分析、设计到编码实现,全面锻炼自己的开发能力。在实战过程中,遇到问题并解决问题,不断积累经验,提升自己的编程水平。