JavaScript 语言完整入门指南
JavaScript(简称 JS)是一种轻量级、解释型、动态类型、单线程的编程语言。它最初作为网页的脚本语言运行在浏览器中,但随着 Node.js 的诞生,JavaScript 已经演变为可以在服务器端、桌面端甚至物联网设备上运行的通用开发语言。
1. JavaScript 简介与环境搭建
1.1 核心特点
- 动态弱类型:变量可以赋任意类型的值,且支持隐式类型转换(如数字
1加字符串"2"会自动变成字符串"12")。 - 单线程与事件循环:使用非阻塞的异步 I/O 和事件循环机制,这使它在单线程下也能高效处理高并发网络请求。
- 双端支持:前端可以在浏览器控制台直接运行,后端可以使用 Node.js / Bun 运行环境执行。
1.2 运行环境搭建
- 浏览器端:任何现代浏览器(Chrome, Safari)按
F12或右键“检查”打开“控制台 (Console)”,即可直接输入和运行 JS 代码。 - 服务器端 (Node.js):
- 从 Node.js 官方网站 下载并安装,或使用命令行工具安装。
- 安装完成后在终端验证:
node -v npm -v # JS 的包管理器
1.3 第一个程序 (Hello World)
- 创建
index.js文件:console.log("Hello, World!"); - 在终端运行该程序:
node index.js
2. 变量与数据类型
2.1 变量声明
JS 提供了三种声明变量的关键字,现代开发中推荐仅使用 const 和 let:
const pi = 3.14159; // 声明常量,一旦赋值不可修改
let age = 27; // 声明可变变量
var name = "Alice"; // 传统声明方式(存在变量提升,现代开发已不推荐使用)2.2 数据类型
- 基本类型:
Number(整型与浮点型合并),String,Boolean,Null,Undefined,Symbol,BigInt。 - 引用类型:
Object(对象、数组、函数等)。
3. 对象与数组
引用类型是 JS 数据处理的核心。
3.1 对象 (Object) —— 键值对集合
const user = {
name: "Bob",
age: 27,
greet: function() {
console.log("Hello, " + this.name);
}
};
user.email = "bob@example.com"; // 动态增加属性
console.log(user.name); // 访问属性
user.greet(); // 调用方法3.2 数组 (Array) —— 动态列表
JS 数组长度可变,且内置了极其强大的高级链式操作方法(如 map, filter, reduce):
const numbers = [1, 2, 3, 4, 5];
// 1. push 追加
numbers.push(6);
// 2. filter 过滤
const evens = numbers.filter(x => x % 2 === 0); // [2, 4, 6]
// 3. map 转换
const doubled = numbers.map(x => x * 2); // [2, 4, 6, 8, 10, 12]4. 控制结构与函数
4.1 控制流 (if-else, switch, loops)
语法类似于其他 C 语言家族成员:
let score = 85;
if (score >= 90) {
console.log("A");
} else {
console.log("B");
}
// 遍历数组的常用方式
for (let num of numbers) {
console.log(num);
}4.2 函数的多种写法
在 JS 中,函数是一等公民(First-Class Citizens),可以作为变量传递。
// 1. 标准函数声明
function add(x, y) {
return x + y;
}
// 2. 函数表达式 (匿名函数)
const multiply = function(x, y) {
return x * y;
};
// 3. 箭头函数 (Lambda 表达式,写回调时最常用)
const subtract = (x, y) => x - y;5. 异步编程:Promise 与 Async/Await
由于 JS 是单线程的,处理网络请求、定时器等耗时操作必须采用异步编程,避免网页卡死。
5.1 Promise 基础
Promise 代表一个未来才会结束的事件的承诺:
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("数据下载成功");
}, 1000);
});
};
fetchData().then(result => {
console.log(result); // 1秒后输出: 数据下载成功
});5.2 终极解决方案:Async / Await
使用 async 和 await 可以用编写同步代码的直观逻辑去写异步程序:
async function main() {
try {
console.log("开始获取数据...");
const data = await fetchData(); // 发生阻塞式等待,直到 Promise resolve
console.log("获取成功:", data);
} catch (err) {
console.error("发生错误:", err);
}
}
main();6. 面向对象:Class
ES6 引入了 class 语法糖,让原本基于原型的继承在写法上与其他面向对象语言一致:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, my name is${this.name}`);
}
}
// 继承
class Employee extends Person {
constructor(name, age, role) {
super(name, age); // 调用父类构造器
this.role = role;
}
}
const emp = new Employee("Alice", 28, "QA");
emp.sayHello();7. 模块系统与包管理 (npm)
7.1 模块导入与导出 (ES Modules)
在现代开发中,推荐使用 import 和 export 管理模块:
// math.js (导出)
export const add = (x, y) => x + y;
// main.js (导入)
import { add } from './math.js';
console.log(add(2, 3));7.2 包管理 (package.json)
使用 npm init 可以初始化一个 JS 项目,生成 package.json(类似于 Python 的 requirements.txt + 配置):
# 初始化项目
npm init -y
# 安装第三方库,并将依赖写入 package.json
npm install lodash
# 安装开发环境依赖 (如测试框架 jest)
npm install --save-dev jest运行 npm install 会在本地生成一个非常庞大的 node_modules 文件夹,用于存储所有依赖。
💡 经典避坑与抓虫小测验
以下小测验选取了 JavaScript 开发中最常见、最容易混淆的语言特性陷阱。请尝试阅读并分析以下代码,预测其输出结果或找出 Bug,点击“答案与解析”查看具体原因。
测验 1:经典的 this 指向丢失
【题目】:预测以下代码的最终输出结果:
const obj = {
name: "Alice",
greet: function() {
console.log("Hello, " + this.name);
},
greetLater: function() {
setTimeout(function() {
console.log("Later, " + this.name);
}, 100);
}
};
obj.greet();
obj.greetLater();👉 答案与解析
【输出结果】:
Hello, Alice
Later, undefined【原因分析】
obj.greet()greetobjthisobj"Hello, Alice"obj.greetLater()setTimeoutsetTimeout全局作用域
thisobjwindowglobalnameundefined修改方法
箭头函数
thisthisjavascript greetLater: function() { // 箭头函数会捕获 greetLater 的 this(即 obj) setTimeout(() => { console.log("Later, " + this.name); }, 100); }测验 2:宽松相等(==)与严格相等(===)的混乱
【题目】:以下代码中,哪些表达式的结果是 true?
console.log(1 == "1");
console.log(1 === "1");
console.log([] == false);
console.log(null == undefined);👉 答案与解析
【输出结果】:
true
false
true
true【原因分析】
==隐式类型转换
1 == "1""1"1true1 === "1"===严格相等
false[] == false[]0false0truenull == undefinednullundefinedtrue避坑准则
100% 推荐只使用 === 进行相等比较
测验 3:传统 var 变量在循环中的闭包噩梦
【题目】:以下代码的意图是在 10 毫秒后依次输出 0, 1, 2。预测其实际输出:
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 10);
}👉 答案与解析
【输出结果】:
3
3
3【原因分析】
var函数作用域或全局作用域
isetTimeouti3i3修改方法
varlet
let块级作用域
i0, 1, 2测验 4:微任务与宏任务的竞态执行
【题目】:写出以下代码在控制台的输出顺序:
console.log("Start");
setTimeout(() => {
console.log("Timeout");
}, 0);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("End");👉 答案与解析
【输出结果】:
Start
End
Promise
Timeout【原因分析】
StartEnd微任务队列 (Microtask Queue)
Promise.thenPromise宏任务队列 (Macrotask Queue)
setTimeoutTimeout