JavaScript 教程

JavaScript 是一种广泛用于 Web 开发的脚本语言,它可以使网页具有交互性和动态效果。通过本教程,你将学习 JavaScript 的基本概念和使用方法。

JavaScript 简介

JavaScript 是一种轻量级的编程语言,主要用于 Web 前端开发,它可以嵌入到 HTML 页面中,使页面具有动态交互功能。

JavaScript 的特点

  • 脚本语言:不需要编译,可以直接在浏览器中运行
  • 解释型语言:代码逐行执行
  • 面向对象:支持对象编程
  • 动态类型:变量可以存储任何类型的数据
  • 事件驱动:可以响应用户的交互事件

JavaScript 的用途

  • 修改 HTML 内容和属性
  • 修改 CSS 样式
  • 响应用户事件(如点击、鼠标移动等)
  • 验证表单数据
  • 创建动画效果
  • 与服务器进行通信(AJAX)
  • 开发游戏和应用程序
提示:JavaScript 与 Java 没有关系,它们是完全不同的编程语言。JavaScript 最初名为 LiveScript,后来为了营销目的改名为 JavaScript。
JavaScript 语法

JavaScript 的语法与 C 和 Java 类似,但也有自己的特点。

在 HTML 中使用 JavaScript

JavaScript 代码可以通过以下方式嵌入到 HTML 页面中:

1. 内联脚本

<script>
    // JavaScript 代码
    alert('Hello, World!');
</script>

2. 外部脚本

<!-- 在 HTML 文件中 -->
<script src="script.js"></script>

<!-- 在 script.js 文件中 -->
alert('Hello, World!');

基本语法规则

  1. 语句通常以分号结尾(在现代 JavaScript 中不是必须的,但建议使用)
  2. 区分大小写
  3. 使用双斜杠(//)添加单行注释
  4. 使用 /* ... */ 添加多行注释
  5. 代码块用花括号 {} 包裹

变量声明

JavaScript 有三种声明变量的方式:

// var: 函数作用域,可以重复声明
var x = 5;
var x = 10; // 允许

// let: 块级作用域,不能重复声明
let y = 15;
// let y = 20; // 错误

// const: 块级作用域,不能重新赋值
const z = 25;
// z = 30; // 错误
提示:在现代 JavaScript 中,推荐使用 let 和 const,而不是 var,因为它们提供了更好的作用域控制。
数据类型

JavaScript 有多种数据类型,包括原始类型和引用类型。

原始数据类型

  • String:字符串,用单引号或双引号包裹
  • Number:数字,可以是整数或浮点数
  • Boolean:布尔值,true 或 false
  • Undefined:变量声明但未赋值时的默认值
  • Null:表示空值或不存在的对象
  • Symbol:ES6 新增,表示唯一标识符
  • BigInt:ES2020 新增,可以表示任意精度的整数

引用数据类型

  • Object:对象,由键值对组成
  • Array:数组,用于存储多个值
  • Function:函数
  • Date:日期对象
  • RegExp:正则表达式对象

数据类型示例

// 字符串
let name = 'JavaScript';
let greeting = "Hello, world!";

// 数字
let age = 25;
let price = 19.99;

// 布尔值
let isActive = true;
let isAvailable = false;

// undefined
let x;
console.log(x); // undefined

// null
let emptyValue = null;

// 数组
let fruits = ['apple', 'banana', 'orange'];

// 对象
let person = {
    firstName: '张三',
    lastName: '李四',
    age: 30
};

// 函数
function greet() {
    console.log('Hello!');
}

类型转换

// 显式转换
let numStr = '123';
let num = Number(numStr); // 123 (数字)
let str = String(123); // "123" (字符串)
let bool = Boolean('hello'); // true

// 隐式转换
let result = '5' + 3; // "53" (字符串)
let sum = '5' - 3; // 2 (数字)

// 其他转换方法
let num1 = parseInt('101'); // 101 (整数)
let num2 = parseFloat('3.14'); // 3.14 (浮点数)
let boolStr = String(true); // "true"
运算符

JavaScript 提供了多种运算符用于执行不同类型的操作。

算术运算符

let a = 10;
let b = 3;

let addition = a + b; // 13
let subtraction = a - b; // 7
let multiplication = a * b; // 30
let division = a / b; // 3.333...
let modulus = a % b; // 1 (余数)
let exponentiation = a ** b; // 1000 (ES6 新增)

赋值运算符

let x = 5;
let y = 10;

x = y; // x 现在是 10
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

比较运算符

let a = 5;
let b = '5';

console.log(a == b); // true (只比较值,不比较类型)
console.log(a === b); // false (比较值和类型)
console.log(a != b); // false
console.log(a !== b); // true
console.log(a > b); // false
console.log(a < b); // false
console.log(a >= b); // true
console.log(a <= b); // true

逻辑运算符

let a = true;
let b = false;

console.log(a && b); // false (逻辑与)
console.log(a || b); // true (逻辑或)
console.log(!a); // false (逻辑非)

// 短路求值
let x = 0 || 10; // 10 (如果第一个操作数为假,则返回第二个操作数)
let y = 5 && 10; // 10 (如果第一个操作数为真,则返回第二个操作数)

递增和递减运算符

let x = 5;

console.log(x++); // 5 (先返回 x 的值,然后增加)
console.log(++x); // 7 (先增加 x,然后返回新值)
console.log(x--); // 7 (先返回 x 的值,然后减少)
console.log(--x); // 5 (先减少 x,然后返回新值)
控制流

控制流语句用于控制代码的执行顺序,包括条件语句和循环语句。

条件语句

if 语句

let age = 18;

if (age >= 18) {
    console.log('成年人');
} else if (age >= 13) {
    console.log('青少年');
} else {
    console.log('儿童');
}

switch 语句

let day = 3;
let dayName;

switch (day) {
    case 1:
        dayName = '星期一';
        break;
    case 2:
        dayName = '星期二';
        break;
    case 3:
        dayName = '星期三';
        break;
    case 4:
        dayName = '星期四';
        break;
    case 5:
        dayName = '星期五';
        break;
    case 6:
        dayName = '星期六';
        break;
    case 7:
        dayName = '星期日';
        break;
    default:
        dayName = '无效的星期';
}

循环语句

for 循环

// 基本 for 循环
for (let i = 0; i < 5; i++) {
    console.log(i); // 输出 0, 1, 2, 3, 4
}

// 遍历数组
let fruits = ['apple', 'banana', 'orange'];
for (let i = 0; i < fruits.length; i++) {
    console.log(fruits[i]);
}

// for...of 循环 (ES6 新增)
for (let fruit of fruits) {
    console.log(fruit);
}

// for...in 循环 (用于对象)
let person = {name: '张三', age: 30, job: '工程师'};
for (let key in person) {
    console.log(key + ': ' + person[key]);
}

while 循环

let i = 0;
while (i < 5) {
    console.log(i);
    i++;
}

do...while 循环

let i = 0;
do {
    console.log(i);
    i++;
} while (i < 5);

跳转语句

// break: 退出循环
for (let i = 0; i < 10; i++) {
    if (i === 5) {
        break;
    }
    console.log(i); // 输出 0 到 4
}

// continue: 跳过当前迭代,继续下一次迭代
for (let i = 0; i < 10; i++) {
    if (i % 2 === 0) {
        continue;
    }
    console.log(i); // 输出 1, 3, 5, 7, 9
}
函数

函数是一组执行特定任务的代码块,可以重复使用。

函数声明

// 基本函数声明
function greet(name) {
    return 'Hello, ' + name + '!';
}

// 调用函数
let message = greet('JavaScript');
console.log(message); // Hello, JavaScript!

函数表达式

// 函数表达式
let greet = function(name) {
    return 'Hello, ' + name + '!';
};

// 箭头函数 (ES6 新增)
let greet = (name) => {
    return 'Hello, ' + name + '!';
};

// 简化的箭头函数 (单行返回)
let greet = name => 'Hello, ' + name + '!';
let add = (a, b) => a + b;

参数和返回值

// 默认参数值 (ES6 新增)
function greet(name = 'World') {
    return 'Hello, ' + name + '!';
}

console.log(greet()); // Hello, World!
console.log(greet('JavaScript')); // Hello, JavaScript!

// 剩余参数 (ES6 新增)
function sum(...numbers) {
    return numbers.reduce((total, num) => total + num, 0);
}

console.log(sum(1, 2, 3, 4, 5)); // 15

// 返回多个值 (通过对象或数组)
function getUserInfo() {
    return {
        name: '张三',
        age: 30,
        job: '工程师'
    };
}

let user = getUserInfo();
console.log(user.name); // 张三

函数作用域

// 全局作用域
let globalVar = '全局变量';

function test() {
    // 函数作用域
    let localVar = '局部变量';
    console.log(globalVar); // 可以访问全局变量
    console.log(localVar); // 可以访问局部变量
}

test();
console.log(globalVar); // 可以访问全局变量
// console.log(localVar); // 错误:无法访问局部变量

闭包

// 闭包示例
function createCounter() {
    let count = 0;
    
    return {
        increment: function() {
            count++;
            return count;
        },
        decrement: function() {
            count--;
            return count;
        },
        getCount: function() {
            return count;
        }
    };
}

let counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.getCount()); // 1
数组

数组是一种特殊的对象,用于存储多个值。数组中的每个值都有一个索引,从 0 开始计数。

创建数组

// 使用数组字面量
let fruits = ['apple', 'banana', 'orange'];

// 使用 Array 构造函数
let numbers = new Array(1, 2, 3, 4, 5);
let emptyArray = new Array(3); // 创建包含 3 个空位的数组

// 使用 Array.of() (ES6 新增)
let colors = Array.of('red', 'green', 'blue');

访问和修改数组元素

let fruits = ['apple', 'banana', 'orange'];

// 访问元素
console.log(fruits[0]); // 'apple'
console.log(fruits[1]); // 'banana'

// 修改元素
fruits[1] = 'grape';
console.log(fruits); // ['apple', 'grape', 'orange']

// 获取数组长度
console.log(fruits.length); // 3

// 修改数组长度
fruits.length = 2;
console.log(fruits); // ['apple', 'grape']

数组方法

let fruits = ['apple', 'banana', 'orange'];

// 添加元素
fruits.push('grape'); // 添加到末尾,返回新长度
fruits.unshift('mango'); // 添加到开头,返回新长度

// 删除元素
fruits.pop(); // 删除末尾元素,返回被删除的元素
fruits.shift(); // 删除开头元素,返回被删除的元素

// 数组操作
let sliced = fruits.slice(1, 3); // 浅拷贝数组的一部分
fruits.splice(1, 1, 'pear'); // 在指定位置删除/添加元素

// 连接数组
let moreFruits = ['peach', 'cherry'];
let allFruits = fruits.concat(moreFruits);

// 查找元素
let index = fruits.indexOf('banana'); // 返回元素索引,未找到返回 -1
let includes = fruits.includes('banana'); // 检查数组是否包含指定元素

// 遍历数组
fruits.forEach(function(fruit, index) {
    console.log(index + ': ' + fruit);
});

// 映射数组
let upperFruits = fruits.map(function(fruit) {
    return fruit.toUpperCase();
});

// 过滤数组
let longFruits = fruits.filter(function(fruit) {
    return fruit.length > 5;
});

// 归约数组
let sum = [1, 2, 3, 4, 5].reduce(function(total, num) {
    return total + num;
}, 0);

数组方法示例

// map 示例:将所有数字平方
let numbers = [1, 2, 3, 4, 5];
let squared = numbers.map(num => num * num);
console.log(squared); // [1, 4, 9, 16, 25]

// filter 示例:筛选偶数
let evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4]

// reduce 示例:计算平均值
let average = numbers.reduce((total, num, index, array) => {
    total += num;
    return index === array.length - 1 ? total / array.length : total;
}, 0);
console.log(average); // 3
对象

对象是 JavaScript 中的一种数据结构,用于存储键值对。对象可以包含属性和方法。

创建对象

// 使用对象字面量
let person = {
    firstName: '张三',
    lastName: '李四',
    age: 30,
    job: '工程师',
    fullName: function() {
        return this.firstName + ' ' + this.lastName;
    }
};

// 使用构造函数
function Person(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.fullName = function() {
        return this.firstName + ' ' + this.lastName;
    };
}

let john = new Person('John', 'Doe', 35);

// 使用 Object.create()
let car = Object.create(Object.prototype, {
    brand: { value: 'Toyota', writable: true },
    model: { value: 'Camry' }
});

// ES6 类 (语法糖,底层仍然是原型继承)
class Animal {
    constructor(name, sound) {
        this.name = name;
        this.sound = sound;
    }
    
    makeSound() {
        return this.name + ' says ' + this.sound;
    }
}

访问和修改对象属性

let person = {
    firstName: '张三',
    lastName: '李四',
    age: 30
};

// 点表示法
console.log(person.firstName); // '张三'
person.age = 31;

// 方括号表示法 (可以使用变量作为属性名)
let prop = 'firstName';
console.log(person[prop]); // '张三'
person['lastName'] = '王五';

// 添加新属性
person.job = '工程师';

// 删除属性
delete person.age;

// 检查属性是否存在
console.log('firstName' in person); // true
console.log(person.hasOwnProperty('firstName')); // true

对象遍历

let person = {
    firstName: '张三',
    lastName: '李四',
    age: 30,
    job: '工程师'
};

// for...in 循环
for (let key in person) {
    if (person.hasOwnProperty(key)) {
        console.log(key + ': ' + person[key]);
    }
}

// 获取所有键
let keys = Object.keys(person);
console.log(keys); // ['firstName', 'lastName', 'age', 'job']

// 获取所有值
let values = Object.values(person);
console.log(values); // ['张三', '李四', 30, '工程师']

// 获取所有键值对
let entries = Object.entries(person);
entries.forEach(([key, value]) => {
    console.log(key + ': ' + value);
});

原型继承

// 构造函数
function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

// 在原型上添加方法
Person.prototype.fullName = function() {
    return this.firstName + ' ' + this.lastName;
};

// 创建实例
let john = new Person('John', 'Doe');
console.log(john.fullName()); // 'John Doe'

// ES6 类和继承
class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    fullName() {
        return this.firstName + ' ' + this.lastName;
    }
}

class Employee extends Person {
    constructor(firstName, lastName, jobTitle) {
        super(firstName, lastName); // 调用父类构造函数
        this.jobTitle = jobTitle;
    }
    
    getJobInfo() {
        return this.fullName() + ' is a ' + this.jobTitle;
    }
}

let employee = new Employee('Jane', 'Smith', 'Developer');
console.log(employee.getJobInfo()); // 'Jane Smith is a Developer'
DOM 操作

DOM (Document Object Model) 是 HTML 和 XML 文档的编程接口。JavaScript 可以通过 DOM 来访问和操作网页元素。

查找元素

// 通过 ID 查找元素
let element = document.getElementById('myElement');

// 通过类名查找元素(返回元素集合)
let elements = document.getElementsByClassName('myClass');

// 通过标签名查找元素(返回元素集合)
let paragraphs = document.getElementsByTagName('p');

// 通过 CSS 选择器查找元素
let firstElement = document.querySelector('.myClass'); // 返回第一个匹配的元素
let allElements = document.querySelectorAll('p.myClass'); // 返回所有匹配的元素

修改元素

// 修改内容
let element = document.getElementById('myElement');
element.textContent = '新的文本内容'; // 修改文本内容
element.innerHTML = '新的 HTML 内容'; // 修改 HTML 内容

// 修改属性
let img = document.querySelector('img');
img.src = 'newImage.jpg';
img.alt = '新的图片描述';

// 获取属性值
let href = document.querySelector('a').getAttribute('href');

// 修改样式
element.style.color = 'red';
element.style.fontSize = '16px';
element.style.backgroundColor = '#f0f0f0';

// 添加和移除类
let element = document.getElementById('myElement');
element.classList.add('newClass');
element.classList.remove('oldClass');
element.classList.toggle('active'); // 如果存在则移除,不存在则添加
element.classList.contains('active'); // 检查是否包含指定类

创建和添加元素

// 创建新元素
let newDiv = document.createElement('div');
newDiv.textContent = '这是一个新的 div 元素';
newDiv.className = 'new-class';
newDiv.id = 'new-div';

// 添加到 DOM
let container = document.getElementById('container');
container.appendChild(newDiv); // 添加到容器末尾

// 在指定位置插入元素
let referenceElement = document.getElementById('reference');
container.insertBefore(newDiv, referenceElement); // 在参考元素之前插入

// 克隆元素
let clonedElement = newDiv.cloneNode(true); // true 表示深拷贝,包括所有子节点
container.appendChild(clonedElement);

// 删除元素
container.removeChild(newDiv);

DOM 遍历

let parent = document.getElementById('parent');

// 子节点
let children = parent.children; // 返回元素节点集合
let firstChild = parent.firstElementChild;
let lastChild = parent.lastElementChild;

// 兄弟节点
let nextSibling = firstChild.nextElementSibling;
let previousSibling = lastChild.previousElementSibling;

// 父节点
let parentNode = firstChild.parentElement;
提示:操作 DOM 可能会导致页面重排和重绘,影响性能。为了提高性能,尽量减少不必要的 DOM 操作,并考虑使用文档片段(DocumentFragment)进行批量操作。
事件处理

JavaScript 事件是用户与网页交互时触发的动作,如点击、鼠标移动、键盘输入等。通过事件处理,我们可以对这些交互做出响应。

事件类型

  • 鼠标事件:click, dblclick, mouseover, mouseout, mousedown, mouseup, mousemove
  • 键盘事件:keydown, keyup, keypress
  • 表单事件:submit, change, input, focus, blur
  • 窗口事件:load, resize, scroll, unload
  • 触摸事件:touchstart, touchend, touchmove
  • 拖拽事件:dragstart, drag, dragend, dragover, drop

添加事件监听器

// 方法一:使用 addEventListener(推荐)
let button = document.getElementById('myButton');

button.addEventListener('click', function(event) {
    console.log('按钮被点击了!');
    console.log('事件对象:', event);
    console.log('目标元素:', event.target);
});

// 使用命名函数
function handleClick(event) {
    console.log('处理点击事件');
}

button.addEventListener('click', handleClick);

// 移除事件监听器
button.removeEventListener('click', handleClick);

// 方法二:使用 HTML 属性(不推荐)
// <button onclick="handleClick()">点击我</button>

// 方法三:使用 DOM 属性
button.onclick = function() {
    console.log('按钮被点击了!');
};

// 移除事件处理
button.onclick = null;

事件对象

document.getElementById('myButton').addEventListener('click', function(event) {
    // 阻止默认行为
    event.preventDefault();
    
    // 阻止事件冒泡
    event.stopPropagation();
    
    // 获取事件类型
    console.log('事件类型:', event.type);
    
    // 获取目标元素
    console.log('目标元素:', event.target);
    
    // 获取当前元素(绑定事件的元素)
    console.log('当前元素:', event.currentTarget);
    
    // 获取鼠标位置
    console.log('鼠标 X 坐标:', event.clientX);
    console.log('鼠标 Y 坐标:', event.clientY);
    
    // 获取键盘按键
    // 对于键盘事件
    // console.log('按键代码:', event.keyCode);
    // console.log('按键:', event.key);
});

事件冒泡和捕获

// HTML 结构
/*
点击我
*/ // 事件冒泡(默认) document.getElementById('outer').addEventListener('click', function() { console.log('外层 div 被点击了'); }); document.getElementById('middle').addEventListener('click', function() { console.log('中层 div 被点击了'); }); document.getElementById('inner').addEventListener('click', function(event) { console.log('内层 div 被点击了'); // event.stopPropagation(); // 阻止冒泡 }); // 事件捕获 // 使用 addEventListener 的第三个参数设置为 true document.getElementById('outer').addEventListener('click', function() { console.log('外层 div 捕获阶段'); }, true); document.getElementById('middle').addEventListener('click', function() { console.log('中层 div 捕获阶段'); }, true); document.getElementById('inner').addEventListener('click', function() { console.log('内层 div 捕获阶段'); }, true);
注意:尽量避免使用内联事件处理器(HTML 属性),因为它们将 HTML 和 JavaScript 混合在一起,不利于代码维护。推荐使用 addEventListener 方法。
异步编程

JavaScript 是单线程的,但它支持异步编程,允许在不阻塞主线程的情况下执行操作,如网络请求、文件操作等。

回调函数

回调函数是异步编程的基础,是指在异步操作完成后执行的函数。

// 回调函数示例
function fetchData(callback) {
    // 模拟异步操作
    setTimeout(function() {
        const data = { name: 'JavaScript', version: 'ES6' };
        callback(null, data); // 第一个参数是错误,第二个参数是数据
    }, 1000);
}

// 使用回调函数
fetchData(function(error, data) {
    if (error) {
        console.error('发生错误:', error);
        return;
    }
    console.log('获取的数据:', data);
});

Promise

Promise 是 ES6 引入的用于处理异步操作的对象,它代表一个异步操作的最终完成(或失败)及其结果值。

// 创建 Promise
function fetchData() {
    return new Promise((resolve, reject) => {
        // 模拟异步操作
        setTimeout(() => {
            const success = true;
            if (success) {
                const data = { name: 'JavaScript', version: 'ES6' };
                resolve(data); // 成功时调用
            } else {
                reject(new Error('获取数据失败')); // 失败时调用
            }
        }, 1000);
    });
}

// 使用 Promise
fetchData()
    .then(data => {
        console.log('获取的数据:', data);
        return data.name.toUpperCase();
    })
    .then(uppercaseName => {
        console.log('转换后的名称:', uppercaseName);
    })
    .catch(error => {
        console.error('发生错误:', error);
    })
    .finally(() => {
        console.log('操作完成');
    });

async/await

async/await 是 ES2017 引入的语法糖,基于 Promise,使异步代码更像同步代码。

// async 函数
async function processData() {
    try {
        const data = await fetchData(); // 等待 Promise 解决
        console.log('获取的数据:', data);
        const uppercaseName = data.name.toUpperCase();
        console.log('转换后的名称:', uppercaseName);
        return uppercaseName;
    } catch (error) {
        console.error('发生错误:', error);
    } finally {
        console.log('操作完成');
    }
}

// 调用 async 函数
processData()
    .then(result => {
        console.log('最终结果:', result);
    })
    .catch(error => {
        console.error('外部错误:', error);
    });

AJAX 和 Fetch API

// 使用 XMLHttpRequest (传统方法)
function fetchWithXHR(url, callback) {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onload = function() {
        if (xhr.status >= 200 && xhr.status < 300) {
            callback(null, JSON.parse(xhr.responseText));
        } else {
            callback(new Error('请求失败'));
        }
    };
    xhr.onerror = function() {
        callback(new Error('网络错误'));
    };
    xhr.send();
}

// 使用 Fetch API (现代方法)
async function fetchWithFetchAPI(url) {
    try {
        const response = await fetch(url);
        if (!response.ok) {
            throw new Error(`HTTP 错误!状态: ${response.status}`);
        }
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('获取数据时出错:', error);
        throw error;
    }
}
提示:在现代 JavaScript 中,推荐使用 async/await 语法进行异步编程,因为它使代码更简洁、更易于理解和调试。
JavaScript 最佳实践

编写高质量 JavaScript 的建议

  1. 使用严格模式:在脚本开头添加 "use strict" 来启用严格模式
  2. 使用 let 和 const,避免使用 var:提供更好的作用域控制
  3. 遵循命名约定:变量和函数使用驼峰命名法,构造函数使用帕斯卡命名法
  4. 避免全局变量:使用模块或闭包来封装代码
  5. 处理错误:使用 try...catch 语句来处理可能的错误
  6. 使用 === 而不是 ==:避免类型转换导致的意外行为
  7. 注释代码:添加清晰的注释,解释复杂的逻辑
  8. 优化性能:避免不必要的计算,使用合适的数据结构
  9. 模块化代码:将代码分割成可管理的模块
  10. 测试代码:使用测试框架来确保代码的质量

常见错误和解决方案

  • 忘记声明变量:始终使用 let 或 const 声明变量
  • 混淆 == 和 ===:优先使用 === 来比较值和类型
  • 忽略异步操作:正确处理 Promise 和异步函数
  • this 绑定问题:了解 this 的指向,必要时使用箭头函数或 bind
  • 内存泄漏:避免不必要的事件监听器和引用
  • 不处理错误:始终捕获和处理可能的错误

调试技巧

// 使用 console.log() 调试
console.log('变量值:', variable);

// 使用 console.table() 以表格形式显示数据
console.table(arrayOfObjects);

// 使用 console.error() 和 console.warn()
console.error('错误信息');
console.warn('警告信息');

// 使用断点:在浏览器开发者工具中设置断点

// 使用 debugger 语句
function problematicFunction() {
    // ... 代码 ...
    debugger; // 执行到这里会暂停
    // ... 代码 ...
}

JavaScript 框架和库

除了原生 JavaScript,还有许多流行的框架和库可以帮助你更高效地开发 Web 应用:

  • React:由 Facebook 开发的用于构建用户界面的库
  • Vue.js:渐进式 JavaScript 框架
  • Angular:由 Google 维护的完整框架
  • jQuery:简化 HTML 文档遍历和事件处理的库
  • Node.js:允许在服务器端运行 JavaScript
  • Express:基于 Node.js 的 Web 应用框架