JavaScript 语言完整入门指南

2026/07/013 分钟阅读1,067

JavaScript(简称 JS)是一种轻量级、解释型、动态类型、单线程的编程语言。它最初作为网页的脚本语言运行在浏览器中,但随着 Node.js 的诞生,JavaScript 已经演变为可以在服务器端、桌面端甚至物联网设备上运行的通用开发语言。


1. JavaScript 简介与环境搭建

1.1 核心特点

  • 动态弱类型:变量可以赋任意类型的值,且支持隐式类型转换(如数字 1 加字符串 "2" 会自动变成字符串 "12")。
  • 单线程与事件循环:使用非阻塞的异步 I/O 和事件循环机制,这使它在单线程下也能高效处理高并发网络请求。
  • 双端支持:前端可以在浏览器控制台直接运行,后端可以使用 Node.js / Bun 运行环境执行。

1.2 运行环境搭建

  1. 浏览器端:任何现代浏览器(Chrome, Safari)按 F12 或右键“检查”打开“控制台 (Console)”,即可直接输入和运行 JS 代码。
  2. 服务器端 (Node.js)
    • Node.js 官方网站 下载并安装,或使用命令行工具安装。
    • 安装完成后在终端验证:
      node -v
      npm -v # JS 的包管理器

1.3 第一个程序 (Hello World)

  1. 创建 index.js 文件:
    console.log("Hello, World!");
  2. 在终端运行该程序:
    node index.js

2. 变量与数据类型

2.1 变量声明

JS 提供了三种声明变量的关键字,现代开发中推荐仅使用 constlet

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

使用 asyncawait 可以用编写同步代码的直观逻辑去写异步程序:

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)

在现代开发中,推荐使用 importexport 管理模块:

// 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()
greet
obj
this
obj
"Hello, Alice"
obj.greetLater()
setTimeout
setTimeout

全局作用域

this
obj
window
global
name
undefined

修改方法

箭头函数

this
this
javascript   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"
1
true
1 === "1"
===

严格相等

false
[] == false
[]
0
false
0
true
null == undefined
null
undefined
true

避坑准则

100% 推荐只使用 === 进行相等比较


测验 3:传统 var 变量在循环中的闭包噩梦

【题目】:以下代码的意图是在 10 毫秒后依次输出 0, 1, 2。预测其实际输出:

for (var i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, 10);
}
👉 答案与解析

【输出结果】

3
3
3

【原因分析】

var

函数作用域或全局作用域

i
setTimeout
i
3
i
3

修改方法

var

let

let

块级作用域

i
0, 1, 2

测验 4:微任务与宏任务的竞态执行

【题目】:写出以下代码在控制台的输出顺序:

console.log("Start");

setTimeout(() => {
    console.log("Timeout");
}, 0);

Promise.resolve().then(() => {
    console.log("Promise");
});

console.log("End");
👉 答案与解析

【输出结果】

Start
End
Promise
Timeout

【原因分析】

Start
End

微任务队列 (Microtask Queue)

Promise.then
Promise

宏任务队列 (Macrotask Queue)

setTimeout
Timeout