cv.cm

编码 · 编程语言

JavaScript 入门教程(零基础)

阅读约 8 分钟

简短回答

JavaScript 是 Web 的编程语言:所有浏览器都能运行它,Node.js 则让它运行在服务器和命令行上。用 const 和 let 声明变量,用函数声明或箭头函数编写函数,用数组和对象存放数据,并用 Promise 与 async/await 处理网络请求等耗时操作。运行 node hello.js 或打开浏览器控制台即可开始。

打开JSON 格式化

JavaScript 是什么,用来做什么

JavaScript 是一门动态类型语言,标准名称为 ECMAScript。它最初为网页而生,用来响应点击、更新页面并与服务器通信。如今它也通过 Node.js、Deno 和 Bun 运行在服务器和各类工具上,还用于桌面应用(Electron)和移动应用(React Native)。前端开发者、全栈开发者以及所有做 Web 开发的人都会用到它。本页的现代语法(let、const、箭头函数、类、模块)来自 ES2015 及之后的版本。

运行 Hello, world

方式一:打开任意网页,按 F12(Mac 上按 Cmd+Option+J)打开开发者控制台,输入下面这行代码。方式二:从 nodejs.org 安装 Node.js,把这行代码保存为 hello.js 并运行。

console.log("Hello, world");
node hello.js
# Hello, world

变量与基本类型

不会被重新赋值的值用 const,会变化的值用 let。避免使用旧的 var,它不遵守块级作用域。typeof 用于查看值的类型。

类型示例typeof
number42, 3.14, NaN"number"
bigint10n"bigint"
string"hi", 'hi', hi ${name} "string"
booleantrue, false"boolean"
undefinedundefined"undefined"
nullnull"object"(历史遗留的怪异行为)
object{}、[]、函数"object" 或 "function"
const name = "Ada";
let count = 1;
count += 1;
console.log(`${name} has ${count} items`); // Ada has 2 items
console.log(0.1 + 0.2);                    // 0.30000000000000004
console.log(Number("12") + 1, "12" + 1);   // 13 121

流程控制:if、循环与相等判断

请始终使用 === 和 !== 比较。宽松的 == 会先转换类型,因此 0 == "" 为 true。

const score = 72;
if (score >= 90) {
  console.log("A");
} else if (score >= 70) {
  console.log("B"); // B
} else {
  console.log("C");
}
for (let i = 0; i < 3; i++) console.log(i); // 0 1 2
for (const fruit of ["apple", "pear"]) console.log(fruit);
let n = 10;
while (n > 1) n = Math.floor(n / 2);
console.log(n); // 1

函数

函数也是值:可以存进变量、传给其他函数,也可以作为返回值。箭头函数是更简短的写法,常用于回调。

function greet(name, greeting = "Hello") {
  return `${greeting}, ${name}!`;
}
const square = (x) => x * x;
const sum = (...nums) => nums.reduce((a, b) => a + b, 0);
console.log(greet("Lin"));     // Hello, Lin!
console.log(square(5));        // 25
console.log(sum(1, 2, 3, 4));  // 10

数组与对象

数组是有序列表,对象把字符串键映射到值。两者都按引用传递。当键不是字符串或值必须唯一时,可以使用内置的 Map 和 Set。

const nums = [3, 1, 2];
nums.push(5);
const doubled = nums.map((n) => n * 2);
const evens = nums.filter((n) => n % 2 === 0);
console.log(doubled, evens);             // [ 6, 2, 4, 10 ] [ 2 ]
console.log([...nums].sort((a, b) => a - b)); // [ 1, 2, 3, 5 ]
const user = { name: "Ann", age: 31 };
user.city = "Oslo";
const { name, age } = user;              // destructuring
console.log(name, age, Object.keys(user)); // Ann 31 [ 'name', 'age', 'city' ]
console.log(JSON.stringify(user));       // {"name":"Ann","age":31,"city":"Oslo"}

标志性特性:用 Promise 编写异步代码

JavaScript 在单线程上通过事件循环运行你的代码。耗时操作(定时器、网络、文件)不会阻塞,而是返回一个稍后才会完成的 Promise。async 函数配合 await,可以让你自上而下地书写这类代码。

const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function main() {
  console.log("start");
  await wait(500);
  console.log("half a second later");
  const [a, b] = await Promise.all([wait(100).then(() => 1), wait(200).then(() => 2)]);
  console.log(a + b); // 3
}
main();
console.log("main() was called"); // prints before "half a second later"

类(class Dog extends Animal {})、模块(import 和 export)、可选链(user?.address?.city)以及空值合并运算符(value ?? "default")也是你会经常用到的现代特性。

错误处理

抛出 Error 对象,并用 try/catch 捕获。在 async 函数中,被拒绝的 Promise 会在 await 处变成异常。

function parseAge(text) {
  const age = Number(text);
  if (!Number.isInteger(age) || age < 0) {
    throw new Error(`invalid age: ${text}`);
  }
  return age;
}
try {
  console.log(parseAge("41"));  // 41
  console.log(parseAge("abc"));
} catch (err) {
  console.log(err.message);     // invalid age: abc
} finally {
  console.log("done");
}

一个完整的小程序:请求并汇总数据

这个 Node.js 脚本(Node 18 及以上内置 fetch)从公开 API 下载 JSON 并输出简短摘要。把它保存为 repos.mjs,然后运行 node repos.mjs nodejs。

const org = process.argv[2] ?? "nodejs";
async function topRepos(name, n = 3) {
  const res = await fetch(`https://api.github.com/orgs/${name}/repos?per_page=100`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const repos = await res.json();
  return repos
    .sort((a, b) => b.stargazers_count - a.stargazers_count)
    .slice(0, n)
    .map((r) => `${r.stargazers_count}\t${r.name}`);
}
try {
  const lines = await topRepos(org);
  console.log(lines.join("\n"));
} catch (err) {
  console.error("failed:", err.message);
  process.exitCode = 1;
}

.mjs 扩展名使文件成为 ES 模块,因此可以在顶层使用 await。

新手常见错误

  • 用 == 代替 ===,导致出人意料的类型转换。
  • 忘记写 await,结果得到的是待定状态的 Promise 对象,而不是真正的值。
  • 以为 const 能让对象不可变。它只是禁止重新赋值,obj.x = 1 依然有效。需要时请使用 Object.freeze。
  • 用 === 比较对象或数组,它比较的是引用是否相同,而不是内容。
  • 把方法当作回调传递时丢失了 this。请使用箭头函数或 .bind(obj)。

接下来学什么

阅读 MDN 的 JavaScript 指南(这是最完整的免费参考资料),并通过浏览器 DOM(document.querySelector、事件)进行练习。然后学习 npm 与模块,前端框架如 React、Vue 或 Svelte,或用 Node.js 开发服务器。在 JavaScript 之上加入 TypeScript,可以获得静态类型和更好的编辑器支持。

常见问题

JavaScript 和 Java 是同一种语言吗?

不是。它们是毫不相关的两种语言,只是名字相似。Java 是静态类型语言,编译为 JVM 字节码;JavaScript 是动态类型语言,运行在浏览器和 Node.js 中。

应该用 let、const 还是 var?

默认使用 const,需要重新赋值时使用 let。避免使用 var,因为它是函数作用域并且会变量提升,容易引发 bug。

null 和 undefined 有什么区别?

undefined 表示变量或属性从未被赋值。null 是你有意赋予的值,表示“空”。

为什么 0.1 + 0.2 不等于 0.3?

JavaScript 的数字是 64 位二进制浮点数,无法精确表示 0.1。显示时请做舍入,处理金额时请使用整数(例如以分为单位)。

学 JavaScript 一定要装 Node.js 吗?

不需要。每个浏览器的开发者控制台都能运行 JavaScript。当你想从文件运行脚本,或构建服务器和工具时,Node.js 才有用。

全部编码教程