第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文档的&lt;head&gt;&lt;body&gt;部分使用&lt;script&gt;标签定义JavaScript代码:

<script>
    function sayHello() {
        alert('Hello World!');
    }
</script>

2.3 外部脚本

将JavaScript代码保存为独立的.js文件,然后在HTML文档中使用&lt;script&gt;标签引入:

<script src="script.js"></script>

script.js文件内容:

function sayHello() {
    alert('Hello World!');
}

优点:代码与结构分离,便于维护和复用

2.4 脚本加载顺序

  • &lt;script&gt;标签默认是同步加载的,会阻塞页面渲染
  • 使用async属性:异步加载脚本,加载完成后立即执行
  • 使用defer属性:异步加载脚本,页面解析完成后执行
<script src="script.js" async></script>
<script src="script.js" defer></script>

3. JavaScript基础语法

3.1 注释

// 单行注释

/* 
   多行注释
   多行注释
*/

3.2 变量

使用varletconst关键字声明变量:

// 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; // 1

3.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); // 1

4. 控制流程

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()); // 3

6. 对象

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()); // 20

6.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应用程序。

« 上一篇 CSS基础 下一篇 » Flask框架基础