第134集 JavaScript基础
1. JavaScript简介
JavaScript(简称JS)是一种轻量级的解释型编程语言,主要用于Web前端开发,为网页添加交互功能。
1.1 JavaScript的历史
- 1995年:由Netscape公司的Brendan Eich开发,最初名为LiveScript
- 1996年:更名为JavaScript,以利用Java的流行度
- 1997年:ECMA International发布ECMAScript 1.0标准
- 2009年:ECMAScript 5发布,成为广泛支持的版本
- 2015年:ECMAScript 6(ES6/ES2015)发布,引入大量新特性
- 2016年至今:每年发布一个新版本(ES2016-ES2025)
1.2 JavaScript的特点
- 解释型语言:不需要编译,直接由浏览器解释执行
- 弱类型语言:变量类型可以动态改变
- 面向对象:支持面向对象编程
- 事件驱动:通过事件触发函数执行
- 跨平台:在所有现代浏览器中都能运行
1.3 JavaScript的应用领域
- Web前端开发(网页交互)
- 服务器端开发(Node.js)
- 移动应用开发(React Native、Ionic等)
- 桌面应用开发(Electron等)
- 游戏开发(HTML5 Canvas + JavaScript)
- 人工智能和机器学习(TensorFlow.js等)
2. JavaScript的引入方式
2.1 内联脚本
直接在HTML元素的事件属性中编写JavaScript代码:
<button onclick="alert('Hello World!')">点击我</button>优点:简单直接
缺点:代码与结构混在一起,难以维护
2.2 内部脚本
在HTML文档的<head>或<body>部分使用<script>标签定义JavaScript代码:
<script>
function sayHello() {
alert('Hello World!');
}
</script>2.3 外部脚本
将JavaScript代码保存为独立的.js文件,然后在HTML文档中使用<script>标签引入:
<script src="script.js"></script>script.js文件内容:
function sayHello() {
alert('Hello World!');
}优点:代码与结构分离,便于维护和复用
2.4 脚本加载顺序
<script>标签默认是同步加载的,会阻塞页面渲染- 使用
async属性:异步加载脚本,加载完成后立即执行 - 使用
defer属性:异步加载脚本,页面解析完成后执行
<script src="script.js" async></script>
<script src="script.js" defer></script>3. JavaScript基础语法
3.1 注释
// 单行注释
/*
多行注释
多行注释
*/3.2 变量
使用var、let或const关键字声明变量:
// var关键字(ES5)
var name = "张三";
var age = 20;
// let关键字(ES6+)
let city = "北京";
city = "上海"; // 可以重新赋值
// const关键字(ES6+)
const PI = 3.14159;
// PI = 3.14; // 错误:const声明的变量不能重新赋值var、let、const的区别:
var:函数作用域,存在变量提升let:块级作用域,不存在变量提升,不能重复声明const:块级作用域,不存在变量提升,不能重复声明,不能重新赋值
3.3 数据类型
JavaScript有7种基本数据类型和1种引用数据类型:
基本数据类型
// 字符串
let str1 = "Hello"; // 双引号
let str2 = 'World'; // 单引号
let str3 = `Hello ${str2}`; // 模板字符串(ES6+)
// 数字
let num1 = 10; // 整数
let num2 = 3.14; // 浮点数
let num3 = NaN; // Not a Number
let num4 = Infinity; // 无穷大
// 布尔值
let isTrue = true;
let isFalse = false;
// null
let empty = null;
// undefined
let undefinedVar;
// Symbol(ES6+)
let symbol1 = Symbol("id");
let symbol2 = Symbol("id");
console.log(symbol1 === symbol2); // false
// BigInt(ES2020+)
let bigNum = 123456789012345678901234567890n;引用数据类型
// 对象
let person = {
name: "张三",
age: 20,
sayHello: function() {
console.log("你好,我是" + this.name);
}
};
// 数组
let fruits = ["苹果", "香蕉", "橘子"];
// 函数
function add(a, b) {
return a + b;
}
// 日期
let now = new Date();
// 正则表达式
let regex = /\d+/;3.4 类型转换
显式转换
// 转换为字符串
String(123); // "123"
123.toString(); // "123"
// 转换为数字
Number("123"); // 123
parseInt("123abc"); // 123
parseFloat("3.14abc"); // 3.14
// 转换为布尔值
Boolean("hello"); // true
Boolean(0); // false
Boolean(""); // false
Boolean(null); // false
Boolean(undefined); // false
Boolean(NaN); // false隐式转换
// 字符串连接
"123" + 456; // "123456"
// 数字运算
"123" - 456; // -333
"123" * 456; // 56088
"123" / 456; // 0.26973684210526316
// 布尔运算
1 + true; // 2
1 + false; // 13.5 运算符
算术运算符
let a = 10, b = 3;
console.log(a + b); // 13
console.log(a - b); // 7
console.log(a * b); // 30
console.log(a / b); // 3.3333333333333335
console.log(a % b); // 1
console.log(++a); // 11
console.log(b--); // 3比较运算符
console.log(5 == "5"); // true(值相等)
console.log(5 === "5"); // false(值和类型都相等)
console.log(5 != "5"); // false
console.log(5 !== "5"); // true
console.log(5 > 3); // true
console.log(5 < 3); // false
console.log(5 >= 5); // true
console.log(5 <= 3); // false逻辑运算符
let x = true, y = false;
console.log(x && y); // false(与)
console.log(x || y); // true(或)
console.log(!x); // false(非)赋值运算符
let a = 10;
a += 5; // a = a + 5
console.log(a); // 15
a -= 3; // a = a - 3
console.log(a); // 12
a *= 2; // a = a * 2
console.log(a); // 24
a /= 4; // a = a / 4
console.log(a); // 6
a %= 5; // a = a % 5
console.log(a); // 14. 控制流程
4.1 条件语句
if语句
let age = 18;
if (age >= 18) {
console.log("成年人");
} else if (age >= 13) {
console.log("青少年");
} else {
console.log("儿童");
}switch语句
let day = 1;
let dayName;
switch (day) {
case 1:
dayName = "星期一";
break;
case 2:
dayName = "星期二";
break;
case 3:
dayName = "星期三";
break;
default:
dayName = "未知";
}
console.log(dayName); // 星期一三元运算符
let age = 18;
let status = age >= 18 ? "成年人" : "未成年人";
console.log(status); // 成年人4.2 循环语句
for循环
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
// 遍历数组
let fruits = ["苹果", "香蕉", "橘子"];
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
// for...in循环(遍历对象属性)
let person = {name: "张三", age: 20};
for (let key in person) {
console.log(key + ": " + person[key]);
}
// for...of循环(遍历可迭代对象)
for (let fruit of fruits) {
console.log(fruit);
}while循环
let i = 0;
while (i < 5) {
console.log(i); // 0, 1, 2, 3, 4
i++;
}do...while循环
let i = 0;
do {
console.log(i); // 0, 1, 2, 3, 4
i++;
} while (i < 5);循环控制语句
// break:跳出循环
for (let i = 0; i < 10; i++) {
if (i === 5) {
break;
}
console.log(i); // 0, 1, 2, 3, 4
}
// continue:跳过当前循环,进入下一次循环
for (let i = 0; i < 10; i++) {
if (i % 2 === 0) {
continue;
}
console.log(i); // 1, 3, 5, 7, 9
}5. 函数
5.1 函数定义
函数声明
function add(a, b) {
return a + b;
}
let result = add(1, 2);
console.log(result); // 3函数表达式
let add = function(a, b) {
return a + b;
};
let result = add(1, 2);
console.log(result); // 3箭头函数(ES6+)
let add = (a, b) => {
return a + b;
};
// 简化写法
let add = (a, b) => a + b;
let sayHello = () => console.log("Hello");
let double = x => x * 2;5.2 函数参数
默认参数(ES6+)
function greet(name = "陌生人") {
console.log("你好," + name + "!");
}
greet(); // 你好,陌生人!
greet("张三"); // 你好,张三!剩余参数(ES6+)
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15展开运算符(ES6+)
let numbers = [1, 2, 3];
console.log(Math.max(...numbers)); // 3
let newNumbers = [...numbers, 4, 5];
console.log(newNumbers); // [1, 2, 3, 4, 5]5.3 函数作用域
function outer() {
let outerVar = "外部变量";
function inner() {
let innerVar = "内部变量";
console.log(outerVar); // 可以访问外部变量
}
inner();
console.log(innerVar); // 错误:不能访问内部变量
}
outer();5.4 闭包
闭包是指有权访问另一个函数作用域中变量的函数:
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
let counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 36. 对象
6.1 对象创建
字面量方式
let person = {
name: "张三",
age: 20,
gender: "男",
sayHello: function() {
console.log("你好,我是" + this.name);
}
};构造函数方式
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.sayHello = function() {
console.log("你好,我是" + this.name);
};
}
let person = new Person("张三", 20, "男");Object.create()方式
let person = Object.create(null);
person.name = "张三";
person.age = 20;6.2 对象属性访问
// 点表示法
console.log(person.name); // 张三
// 方括号表示法
console.log(person["age"]); // 20
// 动态属性名
let key = "gender";
console.log(person[key]); // 男6.3 对象方法
let person = {
name: "张三",
age: 20,
// ES5方式
sayHello: function() {
console.log("你好,我是" + this.name);
},
// ES6+方式
getAge() {
return this.age;
}
};
person.sayHello(); // 你好,我是张三
console.log(person.getAge()); // 206.4 对象遍历
let person = {name: "张三", age: 20, gender: "男"};
// for...in循环
for (let key in person) {
console.log(key + ": " + person[key]);
}
// Object.keys()
let keys = Object.keys(person);
console.log(keys); // ["name", "age", "gender"]
// Object.values()
let values = Object.values(person);
console.log(values); // ["张三", 20, "男"]
// Object.entries()
let entries = Object.entries(person);
console.log(entries); // [["name", "张三"], ["age", 20], ["gender", "男"]]7. 数组
7.1 数组创建
// 字面量方式
let fruits = ["苹果", "香蕉", "橘子"];
// 构造函数方式
let numbers = new Array(1, 2, 3, 4, 5);
let emptyArray = new Array(5); // 创建长度为5的空数组
// Array.of()(ES6+)
let colors = Array.of("红", "绿", "蓝");
// Array.from()(ES6+)
let str = "hello";
let chars = Array.from(str); // ["h", "e", "l", "l", "o"]7.2 数组访问和修改
let fruits = ["苹果", "香蕉", "橘子"];
// 访问元素
console.log(fruits[0]); // 苹果
console.log(fruits[1]); // 香蕉
console.log(fruits[2]); // 橘子
// 修改元素
fruits[1] = "葡萄";
console.log(fruits); // ["苹果", "葡萄", "橘子"]
// 获取数组长度
console.log(fruits.length); // 3
// 修改数组长度
fruits.length = 2;
console.log(fruits); // ["苹果", "葡萄"]7.3 数组方法
增删改查
let fruits = ["苹果", "香蕉", "橘子"];
// 添加元素到末尾
fruits.push("葡萄");
console.log(fruits); // ["苹果", "香蕉", "橘子", "葡萄"]
// 从末尾删除元素
let lastFruit = fruits.pop();
console.log(lastFruit); // 葡萄
console.log(fruits); // ["苹果", "香蕉", "橘子"]
// 添加元素到开头
fruits.unshift("草莓");
console.log(fruits); // ["草莓", "苹果", "香蕉", "橘子"]
// 从开头删除元素
let firstFruit = fruits.shift();
console.log(firstFruit); // 草莓
console.log(fruits); // ["苹果", "香蕉", "橘子"]
// 删除指定位置的元素
let removed = fruits.splice(1, 1); // 从索引1开始,删除1个元素
console.log(removed); // ["香蕉"]
console.log(fruits); // ["苹果", "橘子"]
// 在指定位置插入元素
fruits.splice(1, 0, "香蕉", "葡萄"); // 从索引1开始,删除0个元素,插入2个元素
console.log(fruits); // ["苹果", "香蕉", "葡萄", "橘子"]数组遍历
let fruits = ["苹果", "香蕉", "橘子"];
// for循环
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
// for...of循环
for (let fruit of fruits) {
console.log(fruit);
}
// forEach()方法
fruits.forEach(function(fruit, index, array) {
console.log(index + ": " + fruit);
});
// forEach()箭头函数
fruits.forEach((fruit, index) => {
console.log(index + ": " + fruit);
});数组映射、过滤、归约
let numbers = [1, 2, 3, 4, 5];
// map():映射数组
let doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
// filter():过滤数组
let evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4]
// reduce():归约数组
let sum = numbers.reduce((total, num) => total + num, 0);
console.log(sum); // 15
// find():查找第一个匹配的元素
let firstEven = numbers.find(num => num % 2 === 0);
console.log(firstEven); // 2
// findIndex():查找第一个匹配元素的索引
let firstEvenIndex = numbers.findIndex(num => num % 2 === 0);
console.log(firstEvenIndex); // 1数组排序和反转
let numbers = [3, 1, 4, 1, 5, 9, 2, 6];
// sort():排序
numbers.sort();
console.log(numbers); // [1, 1, 2, 3, 4, 5, 6, 9]
// 自定义排序
numbers.sort((a, b) => b - a);
console.log(numbers); // [9, 6, 5, 4, 3, 2, 1, 1]
// reverse():反转
numbers.reverse();
console.log(numbers); // [1, 1, 2, 3, 4, 5, 6, 9]8. DOM操作
DOM(Document Object Model)是HTML文档的编程接口,JavaScript通过DOM可以操作网页元素。
8.1 元素选择
// 根据ID选择元素
let elementById = document.getElementById("myId");
// 根据类名选择元素
let elementsByClass = document.getElementsByClassName("myClass");
// 根据标签名选择元素
let elementsByTag = document.getElementsByTagName("div");
// 根据CSS选择器选择元素
let element = document.querySelector(".myClass"); // 选择第一个匹配的元素
let elements = document.querySelectorAll(".myClass"); // 选择所有匹配的元素8.2 元素属性操作
let element = document.getElementById("myId");
// 获取属性
let value = element.getAttribute("attributeName");
// 设置属性
element.setAttribute("attributeName", "value");
// 移除属性
element.removeAttribute("attributeName");
// 检查属性是否存在
let hasAttr = element.hasAttribute("attributeName");
// 直接操作属性
element.src = "image.jpg";
element.href = "https://www.example.com";
element.innerHTML = "<p>Hello</p>";
element.textContent = "Hello";8.3 元素样式操作
let element = document.getElementById("myId");
// 直接操作style属性
element.style.color = "red";
element.style.fontSize = "16px";
element.style.backgroundColor = "#f0f0f0";
// 添加CSS类
element.classList.add("myClass");
// 移除CSS类
element.classList.remove("myClass");
// 切换CSS类
element.classList.toggle("myClass");
// 检查是否包含CSS类
let hasClass = element.classList.contains("myClass");8.4 元素创建和插入
// 创建元素
let newElement = document.createElement("div");
newElement.textContent = "新元素";
newElement.className = "newClass";
// 插入元素到末尾
document.body.appendChild(newElement);
// 插入元素到指定位置
let referenceElement = document.getElementById("reference");
document.body.insertBefore(newElement, referenceElement);
// 替换元素
let oldElement = document.getElementById("old");
document.body.replaceChild(newElement, oldElement);
// 删除元素
let elementToRemove = document.getElementById("remove");
elementToRemove.parentNode.removeChild(elementToRemove);8.5 事件处理
HTML事件属性
<button onclick="handleClick()">点击我</button>
<script>
function handleClick() {
alert("按钮被点击了!");
}
</script>DOM事件处理程序
let button = document.getElementById("myButton");
// DOM Level 0
button.onclick = function() {
alert("按钮被点击了!");
};
// DOM Level 2
button.addEventListener("click", function() {
alert("按钮被点击了!");
});
// 移除事件监听器
function handleClick() {
alert("按钮被点击了!");
}
button.addEventListener("click", handleClick);
button.removeEventListener("click", handleClick);常用事件
// 鼠标事件
button.addEventListener("click", function() {}); // 点击
button.addEventListener("dblclick", function() {}); // 双击
button.addEventListener("mouseover", function() {}); // 鼠标悬停
button.addEventListener("mouseout", function() {}); // 鼠标离开
button.addEventListener("mousedown", function() {}); // 鼠标按下
button.addEventListener("mouseup", function() {}); // 鼠标松开
// 键盘事件
input.addEventListener("keydown", function() {}); // 键盘按下
input.addEventListener("keyup", function() {}); // 键盘松开
input.addEventListener("keypress", function() {}); // 键盘按键
// 表单事件
form.addEventListener("submit", function() {}); // 表单提交
input.addEventListener("change", function() {}); // 内容改变
input.addEventListener("input", function() {}); // 输入时
input.addEventListener("focus", function() {}); // 获取焦点
input.addEventListener("blur", function() {}); // 失去焦点
// 窗口事件
window.addEventListener("load", function() {}); // 页面加载完成
window.addEventListener("resize", function() {}); // 窗口大小改变
window.addEventListener("scroll", function() {}); // 页面滚动9. JavaScript高级特性
9.1 定时器
// setTimeout:延迟执行一次
let timeoutId = setTimeout(function() {
console.log("延迟1秒执行");
}, 1000);
// 清除定时器
clearTimeout(timeoutId);
// setInterval:每隔一段时间执行一次
let intervalId = setInterval(function() {
console.log("每隔1秒执行一次");
}, 1000);
// 清除定时器
clearInterval(intervalId);9.2 异常处理
try {
// 可能抛出错误的代码
let result = 10 / 0;
console.log(result);
} catch (error) {
// 捕获错误
console.log("发生错误:" + error.message);
} finally {
// 无论是否发生错误都会执行
console.log("执行finally块");
}
// 抛出错误
function divide(a, b) {
if (b === 0) {
throw new Error("除数不能为0");
}
return a / b;
}
try {
let result = divide(10, 0);
} catch (error) {
console.log(error.message); // 除数不能为0
}9.3 Promise
Promise用于处理异步操作:
// 创建Promise
let promise = new Promise(function(resolve, reject) {
// 异步操作
setTimeout(function() {
let success = true;
if (success) {
resolve("操作成功");
} else {
reject("操作失败");
}
}, 1000);
});
// 使用Promise
promise.then(function(result) {
console.log(result); // 操作成功
}).catch(function(error) {
console.log(error); // 操作失败
});
// Promise链式调用
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log(error));9.4 async/await(ES8+)
async/await是基于Promise的异步编程语法糖:
async function fetchData() {
try {
let response = await fetch("https://api.example.com/data");
let data = await response.json();
console.log(data);
return data;
} catch (error) {
console.log(error);
throw error;
}
}
fetchData();10. JavaScript最佳实践
10.1 代码风格
- 使用一致的缩进(2个或4个空格)
- 使用驼峰命名法命名变量和函数
- 语句末尾添加分号
- 使用===和!==代替==和!=
10.2 性能优化
- 减少DOM操作
- 使用事件委托
- 避免使用eval()
- 优化循环
- 使用缓存
10.3 安全注意事项
- 防止XSS攻击:对用户输入进行过滤和转义
- 防止CSRF攻击:使用CSRF令牌
- 避免使用全局变量
- 保护敏感数据
11. 总结
JavaScript是Web开发中不可或缺的编程语言,它为网页提供了交互功能和动态效果。本集讲解了JavaScript的基础知识,包括:
- JavaScript的历史和特点
- JavaScript的引入方式
- 基础语法(变量、数据类型、运算符、控制流程)
- 函数和对象
- 数组操作
- DOM操作
- 事件处理
- 高级特性(定时器、异常处理、Promise、async/await)
通过学习本集内容,您已经掌握了JavaScript的基本概念和用法,可以开始编写简单的JavaScript代码来增强网页的交互性。在后续的课程中,我们将学习如何将JavaScript与HTML和CSS结合起来,开发完整的Web应用程序。